Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 TryCatch try_catch; | 327 TryCatch try_catch; |
| 328 bool is_array_buffer_construct = element_size == 0; | 328 bool is_array_buffer_construct = element_size == 0; |
| 329 if (is_array_buffer_construct) { | 329 if (is_array_buffer_construct) { |
| 330 type = v8::kExternalByteArray; | 330 type = v8::kExternalByteArray; |
| 331 element_size = 1; | 331 element_size = 1; |
| 332 } | 332 } |
| 333 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || | 333 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || |
| 334 element_size == 8); | 334 element_size == 8); |
| 335 if (args.Length() == 0) { | 335 if (args.Length() == 0) { |
| 336 return ThrowException( | 336 return ThrowException( |
| 337 String::New("Array constructor must have at least one " | 337 String::New("Array constructor must have at least one parameter.")); |
| 338 "parameter.")); | |
| 339 } | 338 } |
| 340 bool first_arg_is_array_buffer = | 339 bool first_arg_is_array_buffer = |
| 341 args[0]->IsObject() && | 340 args[0]->IsObject() && |
| 342 args[0]->ToObject()->Get( | 341 args[0]->ToObject()->Get( |
| 343 String::New(kArrayBufferMarkerPropName))->IsTrue(); | 342 String::New(kArrayBufferMarkerPropName))->IsTrue(); |
| 344 // Currently, only the following constructors are supported: | 343 // Currently, only the following constructors are supported: |
| 344 // ArrayBuffer(unsigned long length) | |
| 345 // TypedArray(unsigned long length) | 345 // TypedArray(unsigned long length) |
| 346 // TypedArray(ArrayBuffer buffer, | 346 // TypedArray(ArrayBuffer buffer, |
| 347 // optional unsigned long byteOffset, | 347 // optional unsigned long byteOffset, |
| 348 // optional unsigned long length) | 348 // optional unsigned long length) |
| 349 if (args.Length() > 3) { | 349 size_t length; |
| 350 return ThrowException( | 350 size_t byteLength; |
| 351 String::New("Array constructor from ArrayBuffer must " | 351 size_t byteOffset; |
| 352 "have 1-3 parameters.")); | 352 void* data = NULL; |
| 353 } | 353 Handle<Object> array = Object::New(); |
| 354 if (is_array_buffer_construct) { | |
| 355 byteLength = convertToUint(args[0], &try_catch); | |
| 356 if (try_catch.HasCaught()) return try_catch.Exception(); | |
| 357 byteOffset = 0; | |
| 358 length = byteLength; | |
| 354 | 359 |
| 355 Local<Value> length_value = (args.Length() < 3) | 360 array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); |
|
Yang
2012/05/18 12:10:40
Is the property _is_array_buffer_ something that i
rossberg
2012/05/30 13:37:16
Done. _array_buffer_ref_ actually is redundant. Cl
| |
| 356 ? (first_arg_is_array_buffer | 361 } else if (first_arg_is_array_buffer) { |
| 357 ? args[0]->ToObject()->Get(String::New("byteLength")) | 362 Handle<Object> buffer = args[0]->ToObject(); |
| 358 : args[0]) | 363 data = buffer->GetIndexedPropertiesExternalArrayData(); |
| 359 : args[2]; | 364 byteLength = |
| 360 size_t byteLength = convertToUint(length_value, &try_catch); | 365 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); |
| 361 size_t length = byteLength; | |
| 362 if (try_catch.HasCaught()) return try_catch.Exception(); | |
| 363 | |
| 364 void* data = NULL; | |
| 365 size_t offset = 0; | |
| 366 | |
| 367 Handle<Object> array = Object::New(); | |
| 368 if (first_arg_is_array_buffer) { | |
| 369 Handle<Object> derived_from = args[0]->ToObject(); | |
| 370 data = derived_from->GetIndexedPropertiesExternalArrayData(); | |
| 371 | |
| 372 size_t array_buffer_length = convertToUint( | |
| 373 derived_from->Get(String::New("byteLength")), | |
| 374 &try_catch); | |
| 375 if (try_catch.HasCaught()) return try_catch.Exception(); | 366 if (try_catch.HasCaught()) return try_catch.Exception(); |
| 376 | 367 if (data == NULL && byteLength != 0) { |
| 377 if (data == NULL && array_buffer_length != 0) { | 368 return ThrowException(String::New("ArrayBuffer does not have data")); |
| 378 return ThrowException( | |
| 379 String::New("ArrayBuffer doesn't have data")); | |
| 380 } | 369 } |
| 381 | 370 |
| 382 if (args.Length() > 1) { | 371 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 383 offset = convertToUint(args[1], &try_catch); | 372 byteOffset = 0; |
| 373 } else { | |
| 374 byteOffset = convertToUint(args[1], &try_catch); | |
| 384 if (try_catch.HasCaught()) return try_catch.Exception(); | 375 if (try_catch.HasCaught()) return try_catch.Exception(); |
| 385 | 376 if (byteOffset % element_size != 0) { |
| 386 // The given byteOffset must be a multiple of the element size of the | |
| 387 // specific type, otherwise an exception is raised. | |
| 388 if (offset % element_size != 0) { | |
| 389 return ThrowException( | 377 return ThrowException( |
| 390 String::New("offset must be multiple of element_size")); | 378 String::New("byteOffset must be multiple of element_size")); |
| 391 } | 379 } |
| 392 } | 380 } |
| 393 | 381 |
| 394 if (offset > array_buffer_length) { | 382 if (args.Length() < 3 || args[2]->IsUndefined()) { |
| 395 return ThrowException( | 383 if (byteLength % element_size != 0) { |
| 396 String::New("byteOffset must be less than ArrayBuffer length.")); | 384 return ThrowException( |
| 385 String::New("buffer size must be multiple of element_size")); | |
| 386 } | |
| 387 length = (byteLength - byteOffset) / element_size; | |
| 388 } else { | |
| 389 length = convertToUint(args[2], &try_catch); | |
| 390 if (try_catch.HasCaught()) return try_catch.Exception(); | |
| 397 } | 391 } |
| 398 | 392 |
| 399 if (args.Length() == 2) { | 393 if (byteOffset + length * element_size > byteLength) { |
| 400 // If length is not explicitly specified, the length of the ArrayBuffer | 394 return ThrowException( |
| 401 // minus the byteOffset must be a multiple of the element size of the | 395 String::New("byteOffset or length out of bounds")); |
| 402 // specific type, or an exception is raised. | |
| 403 length = array_buffer_length - offset; | |
| 404 } | 396 } |
| 405 | 397 byteLength = byteOffset + length * element_size; |
| 406 if (args.Length() != 3) { | |
| 407 if (length % element_size != 0) { | |
| 408 return ThrowException( | |
| 409 String::New("ArrayBuffer length minus the byteOffset must be a " | |
| 410 "multiple of the element size")); | |
| 411 } | |
| 412 length /= element_size; | |
| 413 } | |
| 414 | |
| 415 // If a given byteOffset and length references an area beyond the end of | |
| 416 // the ArrayBuffer an exception is raised. | |
| 417 if (offset + (length * element_size) > array_buffer_length) { | |
| 418 return ThrowException( | |
| 419 String::New("length references an area beyond the end of the " | |
| 420 "ArrayBuffer")); | |
| 421 } | |
| 422 | 398 |
| 423 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. | 399 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. |
| 424 array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); | 400 array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); |
| 425 } | 401 } else { |
| 426 | 402 length = convertToUint(args[0], &try_catch); |
| 427 if (is_array_buffer_construct) { | 403 byteLength = length * element_size; |
| 428 array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); | 404 byteOffset = 0; |
| 429 } | 405 } |
| 430 | 406 |
| 431 Persistent<Object> persistent_array = Persistent<Object>::New(array); | 407 Persistent<Object> persistent_array = Persistent<Object>::New(array); |
| 432 if (data == NULL && length != 0) { | 408 if (data == NULL && byteLength != 0) { |
| 409 ASSERT(byteOffset == 0); | |
| 410 // Prepend the size of the allocated chunk to the data itself. | |
| 411 int total_size = | |
| 412 byteLength + kExternalArrayAllocationHeaderSize * sizeof(size_t); | |
| 413 static const int kMaxSize = 0x7fffffff; | |
| 433 // Make sure the total size fits into a (signed) int. | 414 // Make sure the total size fits into a (signed) int. |
| 434 static const int kMaxSize = 0x7fffffff; | 415 if (total_size > kMaxSize) { |
| 435 if (length > (kMaxSize - sizeof(size_t)) / element_size) { | |
| 436 return ThrowException(String::New("Array exceeds maximum size (2G)")); | 416 return ThrowException(String::New("Array exceeds maximum size (2G)")); |
| 437 } | 417 } |
| 438 // Prepend the size of the allocated chunk to the data itself. | |
| 439 int total_size = length * element_size + | |
| 440 kExternalArrayAllocationHeaderSize * sizeof(size_t); | |
| 441 data = malloc(total_size); | 418 data = malloc(total_size); |
| 442 if (data == NULL) { | 419 if (data == NULL) { |
| 443 return ThrowException(String::New("Memory allocation failed.")); | 420 return ThrowException(String::New("Memory allocation failed.")); |
| 444 } | 421 } |
| 445 *reinterpret_cast<size_t*>(data) = total_size; | 422 *reinterpret_cast<size_t*>(data) = total_size; |
| 446 data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize; | 423 data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize; |
| 447 memset(data, 0, length * element_size); | 424 memset(data, 0, byteLength); |
| 448 V8::AdjustAmountOfExternalAllocatedMemory(total_size); | 425 V8::AdjustAmountOfExternalAllocatedMemory(total_size); |
| 449 } | 426 } |
| 450 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | 427 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); |
| 451 persistent_array.MarkIndependent(); | 428 persistent_array.MarkIndependent(); |
| 452 | 429 |
| 453 array->SetIndexedPropertiesToExternalArrayData( | 430 array->SetIndexedPropertiesToExternalArrayData( |
| 454 reinterpret_cast<uint8_t*>(data) + offset, type, | 431 reinterpret_cast<uint8_t*>(data) + byteOffset, type, |
| 455 static_cast<int>(length)); | 432 static_cast<int>(length)); |
| 456 array->Set(String::New("byteLength"), | 433 array->Set(String::New("byteLength"), |
| 457 Int32::New(static_cast<int32_t>(byteLength)), ReadOnly); | 434 Int32::New(static_cast<int32_t>(byteLength)), ReadOnly); |
| 458 if (!is_array_buffer_construct) { | 435 if (!is_array_buffer_construct) { |
| 436 array->Set(String::New("byteOffset"), | |
| 437 Int32::New(static_cast<int32_t>(byteOffset)), ReadOnly); | |
| 459 array->Set(String::New("length"), | 438 array->Set(String::New("length"), |
| 460 Int32::New(static_cast<int32_t>(length)), ReadOnly); | 439 Int32::New(static_cast<int32_t>(length)), ReadOnly); |
| 461 array->Set(String::New("byteOffset"), | |
| 462 Int32::New(static_cast<int32_t>(offset)), ReadOnly); | |
| 463 array->Set(String::New("BYTES_PER_ELEMENT"), | 440 array->Set(String::New("BYTES_PER_ELEMENT"), |
| 464 Int32::New(static_cast<int32_t>(element_size))); | 441 Int32::New(static_cast<int32_t>(element_size))); |
| 465 // We currently support 'buffer' property only if constructed from a buffer. | 442 // We currently support 'buffer' property only if constructed from a buffer. |
| 466 if (first_arg_is_array_buffer) { | 443 if (first_arg_is_array_buffer) { |
| 467 array->Set(String::New("buffer"), args[0], ReadOnly); | 444 array->Set(String::New("buffer"), args[0], ReadOnly); |
| 468 } | 445 } |
| 469 } | 446 } |
| 470 return array; | 447 return array; |
| 471 } | 448 } |
| 472 | 449 |
| (...skipping 1122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1595 } | 1572 } |
| 1596 | 1573 |
| 1597 } // namespace v8 | 1574 } // namespace v8 |
| 1598 | 1575 |
| 1599 | 1576 |
| 1600 #ifndef GOOGLE3 | 1577 #ifndef GOOGLE3 |
| 1601 int main(int argc, char* argv[]) { | 1578 int main(int argc, char* argv[]) { |
| 1602 return v8::Shell::Main(argc, argv); | 1579 return v8::Shell::Main(argc, argv); |
| 1603 } | 1580 } |
| 1604 #endif | 1581 #endif |
| OLD | NEW |