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 |