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 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); | 317 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); |
318 #endif // V8_SHARED | 318 #endif // V8_SHARED |
319 if (raw_value > static_cast<int32_t>(kMaxLength)) { | 319 if (raw_value > static_cast<int32_t>(kMaxLength)) { |
320 ThrowException( | 320 ThrowException( |
321 String::New("Array length exceeds maximum length.")); | 321 String::New("Array length exceeds maximum length.")); |
322 } | 322 } |
323 return raw_value; | 323 return raw_value; |
324 } | 324 } |
325 | 325 |
326 | 326 |
| 327 // TODO(rossberg): should replace these by proper uses of HasInstance, |
| 328 // once we figure out a good way to make the templates global. |
327 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; | 329 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; |
328 const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; | 330 const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; |
329 | 331 |
330 | 332 |
331 Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, | 333 Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, |
332 int32_t length) { | 334 int32_t length) { |
333 static const int32_t kMaxSize = 0x7fffffff; | 335 static const int32_t kMaxSize = 0x7fffffff; |
334 // Make sure the total size fits into a (signed) int. | 336 // Make sure the total size fits into a (signed) int. |
335 if (length < 0 || length > kMaxSize) { | 337 if (length < 0 || length > kMaxSize) { |
336 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); | 338 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); |
337 } | 339 } |
338 uint8_t* data = new uint8_t[length]; | 340 uint8_t* data = new uint8_t[length]; |
339 if (data == NULL) { | 341 if (data == NULL) { |
340 return ThrowException(String::New("Memory allocation failed.")); | 342 return ThrowException(String::New("Memory allocation failed")); |
341 } | 343 } |
342 memset(data, 0, length); | 344 memset(data, 0, length); |
343 | 345 |
344 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); | 346 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); |
345 Persistent<Object> persistent_array = Persistent<Object>::New(buffer); | 347 Persistent<Object> persistent_array = Persistent<Object>::New(buffer); |
346 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | 348 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); |
347 persistent_array.MarkIndependent(); | 349 persistent_array.MarkIndependent(); |
348 V8::AdjustAmountOfExternalAllocatedMemory(length); | 350 V8::AdjustAmountOfExternalAllocatedMemory(length); |
349 | 351 |
350 buffer->SetIndexedPropertiesToExternalArrayData( | 352 buffer->SetIndexedPropertiesToExternalArrayData( |
351 data, v8::kExternalByteArray, length); | 353 data, v8::kExternalByteArray, length); |
352 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); | 354 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); |
353 | 355 |
354 return buffer; | 356 return buffer; |
355 } | 357 } |
356 | 358 |
357 | 359 |
358 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { | 360 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { |
359 if (!args.IsConstructCall()) { | 361 if (!args.IsConstructCall()) { |
360 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; | 362 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; |
361 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; | 363 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; |
362 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); | 364 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); |
363 delete[] rec_args; | 365 delete[] rec_args; |
364 return result; | 366 return result; |
365 } | 367 } |
366 | 368 |
367 if (args.Length() == 0) { | 369 if (args.Length() == 0) { |
368 return ThrowException( | 370 return ThrowException( |
369 String::New("ArrayBuffer constructor must have one parameter.")); | 371 String::New("ArrayBuffer constructor must have one argument")); |
370 } | 372 } |
371 TryCatch try_catch; | 373 TryCatch try_catch; |
372 int32_t length = convertToUint(args[0], &try_catch); | 374 int32_t length = convertToUint(args[0], &try_catch); |
373 if (try_catch.HasCaught()) return try_catch.Exception(); | 375 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
374 | 376 |
375 return CreateExternalArrayBuffer(args.This(), length); | 377 return CreateExternalArrayBuffer(args.This(), length); |
376 } | 378 } |
377 | 379 |
378 | 380 |
379 Handle<Object> Shell::CreateExternalArray(Handle<Object> array, | 381 Handle<Object> Shell::CreateExternalArray(Handle<Object> array, |
380 Handle<Object> buffer, | 382 Handle<Object> buffer, |
381 ExternalArrayType type, | 383 ExternalArrayType type, |
382 int32_t length, | 384 int32_t length, |
383 int32_t byteLength, | 385 int32_t byteLength, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 // TypedArray(ArrayBuffer buffer, | 427 // TypedArray(ArrayBuffer buffer, |
426 // optional unsigned long byteOffset, | 428 // optional unsigned long byteOffset, |
427 // optional unsigned long length) | 429 // optional unsigned long length) |
428 Handle<Object> buffer; | 430 Handle<Object> buffer; |
429 int32_t length; | 431 int32_t length; |
430 int32_t byteLength; | 432 int32_t byteLength; |
431 int32_t byteOffset; | 433 int32_t byteOffset; |
432 bool init_from_array = false; | 434 bool init_from_array = false; |
433 if (args.Length() == 0) { | 435 if (args.Length() == 0) { |
434 return ThrowException( | 436 return ThrowException( |
435 String::New("Array constructor must have at least one parameter.")); | 437 String::New("Array constructor must have at least one argument")); |
436 } | 438 } |
437 if (args[0]->IsObject() && | 439 if (args[0]->IsObject() && |
438 !args[0]->ToObject()->GetHiddenValue( | 440 !args[0]->ToObject()->GetHiddenValue( |
439 String::New(kArrayBufferMarkerPropName)).IsEmpty()) { | 441 String::New(kArrayBufferMarkerPropName)).IsEmpty()) { |
440 // Construct from ArrayBuffer. | 442 // Construct from ArrayBuffer. |
441 buffer = args[0]->ToObject(); | 443 buffer = args[0]->ToObject(); |
442 int32_t bufferLength = | 444 int32_t bufferLength = |
443 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); | 445 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); |
444 if (try_catch.HasCaught()) return try_catch.Exception(); | 446 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
445 | 447 |
446 if (args.Length() < 2 || args[1]->IsUndefined()) { | 448 if (args.Length() < 2 || args[1]->IsUndefined()) { |
447 byteOffset = 0; | 449 byteOffset = 0; |
448 } else { | 450 } else { |
449 byteOffset = convertToUint(args[1], &try_catch); | 451 byteOffset = convertToUint(args[1], &try_catch); |
450 if (try_catch.HasCaught()) return try_catch.Exception(); | 452 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
451 if (byteOffset > bufferLength) { | 453 if (byteOffset > bufferLength) { |
452 return ThrowException(String::New("byteOffset out of bounds")); | 454 return ThrowException(String::New("byteOffset out of bounds")); |
453 } | 455 } |
454 if (byteOffset % element_size != 0) { | 456 if (byteOffset % element_size != 0) { |
455 return ThrowException( | 457 return ThrowException( |
456 String::New("byteOffset must be multiple of element_size")); | 458 String::New("byteOffset must be multiple of element size")); |
457 } | 459 } |
458 } | 460 } |
459 | 461 |
460 if (args.Length() < 3 || args[2]->IsUndefined()) { | 462 if (args.Length() < 3 || args[2]->IsUndefined()) { |
461 byteLength = bufferLength - byteOffset; | 463 byteLength = bufferLength - byteOffset; |
462 length = byteLength / element_size; | 464 length = byteLength / element_size; |
463 if (byteLength % element_size != 0) { | 465 if (byteLength % element_size != 0) { |
464 return ThrowException( | 466 return ThrowException( |
465 String::New("buffer size must be multiple of element_size")); | 467 String::New("buffer size must be multiple of element size")); |
466 } | 468 } |
467 } else { | 469 } else { |
468 length = convertToUint(args[2], &try_catch); | 470 length = convertToUint(args[2], &try_catch); |
469 if (try_catch.HasCaught()) return try_catch.Exception(); | 471 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
470 byteLength = length * element_size; | 472 byteLength = length * element_size; |
471 if (byteOffset + byteLength > bufferLength) { | 473 if (byteOffset + byteLength > bufferLength) { |
472 return ThrowException(String::New("length out of bounds")); | 474 return ThrowException(String::New("length out of bounds")); |
473 } | 475 } |
474 } | 476 } |
475 } else { | 477 } else { |
476 if (args[0]->IsObject() && | 478 if (args[0]->IsObject() && |
477 args[0]->ToObject()->Has(String::New("length"))) { | 479 args[0]->ToObject()->Has(String::New("length"))) { |
478 // Construct from array. | 480 // Construct from array. |
479 length = convertToUint( | 481 length = convertToUint( |
480 args[0]->ToObject()->Get(String::New("length")), &try_catch); | 482 args[0]->ToObject()->Get(String::New("length")), &try_catch); |
481 if (try_catch.HasCaught()) return try_catch.Exception(); | 483 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
482 init_from_array = true; | 484 init_from_array = true; |
483 } else { | 485 } else { |
484 // Construct from size. | 486 // Construct from size. |
485 length = convertToUint(args[0], &try_catch); | 487 length = convertToUint(args[0], &try_catch); |
486 if (try_catch.HasCaught()) return try_catch.Exception(); | 488 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
487 } | 489 } |
488 byteLength = length * element_size; | 490 byteLength = length * element_size; |
489 byteOffset = 0; | 491 byteOffset = 0; |
490 | 492 |
491 Handle<Object> global = Context::GetCurrent()->Global(); | 493 Handle<Object> global = Context::GetCurrent()->Global(); |
492 Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); | 494 Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); |
493 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); | 495 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); |
494 Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; | 496 Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; |
495 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( | 497 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( |
496 1, buffer_args); | 498 1, buffer_args); |
497 if (try_catch.HasCaught()) return result; | 499 if (try_catch.HasCaught()) return result; |
498 buffer = result->ToObject(); | 500 buffer = result->ToObject(); |
499 } | 501 } |
500 | 502 |
501 Handle<Object> array = CreateExternalArray( | 503 Handle<Object> array = CreateExternalArray( |
502 args.This(), buffer, type, length, byteLength, byteOffset, element_size); | 504 args.This(), buffer, type, length, byteLength, byteOffset, element_size); |
503 | 505 |
504 if (init_from_array) { | 506 if (init_from_array) { |
505 Handle<Object> init = args[0]->ToObject(); | 507 Handle<Object> init = args[0]->ToObject(); |
506 for (int i = 0; i < length; ++i) array->Set(i, init->Get(i)); | 508 for (int i = 0; i < length; ++i) array->Set(i, init->Get(i)); |
507 } | 509 } |
508 | 510 |
509 return array; | 511 return array; |
510 } | 512 } |
511 | 513 |
512 | 514 |
513 Handle<Value> Shell::SubArray(const Arguments& args) { | 515 Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) { |
514 TryCatch try_catch; | 516 TryCatch try_catch; |
515 | 517 |
516 if (!args.This()->IsObject()) { | 518 if (!args.This()->IsObject()) { |
517 return ThrowException( | 519 return ThrowException( |
518 String::New("subarray invoked on non-object receiver.")); | 520 String::New("'slice' invoked on non-object receiver")); |
| 521 } |
| 522 |
| 523 Local<Object> self = args.This(); |
| 524 Local<Value> marker = |
| 525 self->GetHiddenValue(String::New(kArrayBufferMarkerPropName)); |
| 526 if (marker.IsEmpty()) { |
| 527 return ThrowException( |
| 528 String::New("'slice' invoked on wrong receiver type")); |
| 529 } |
| 530 |
| 531 int32_t length = |
| 532 convertToUint(self->Get(String::New("byteLength")), &try_catch); |
| 533 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 534 |
| 535 if (args.Length() == 0) { |
| 536 return ThrowException( |
| 537 String::New("'slice' must have at least one argument")); |
| 538 } |
| 539 int32_t begin = convertToInt(args[0], &try_catch); |
| 540 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 541 if (begin < 0) begin += length; |
| 542 if (begin < 0) begin = 0; |
| 543 if (begin > length) begin = length; |
| 544 |
| 545 int32_t end; |
| 546 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 547 end = length; |
| 548 } else { |
| 549 end = convertToInt(args[1], &try_catch); |
| 550 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 551 if (end < 0) end += length; |
| 552 if (end < 0) end = 0; |
| 553 if (end > length) end = length; |
| 554 if (end < begin) end = begin; |
| 555 } |
| 556 |
| 557 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); |
| 558 Handle<Value> new_args[] = { Uint32::New(end - begin) }; |
| 559 Handle<Value> result = constructor->NewInstance(1, new_args); |
| 560 if (try_catch.HasCaught()) return result; |
| 561 Handle<Object> buffer = result->ToObject(); |
| 562 uint8_t* dest = |
| 563 static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData()); |
| 564 uint8_t* src = begin + static_cast<uint8_t*>( |
| 565 self->GetIndexedPropertiesExternalArrayData()); |
| 566 memcpy(dest, src, end - begin); |
| 567 |
| 568 return buffer; |
| 569 } |
| 570 |
| 571 |
| 572 Handle<Value> Shell::ArraySubArray(const Arguments& args) { |
| 573 TryCatch try_catch; |
| 574 |
| 575 if (!args.This()->IsObject()) { |
| 576 return ThrowException( |
| 577 String::New("'subarray' invoked on non-object receiver")); |
519 } | 578 } |
520 | 579 |
521 Local<Object> self = args.This(); | 580 Local<Object> self = args.This(); |
522 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); | 581 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); |
523 if (marker.IsEmpty()) { | 582 if (marker.IsEmpty()) { |
524 return ThrowException( | 583 return ThrowException( |
525 String::New("subarray invoked on wrong receiver type.")); | 584 String::New("'subarray' invoked on wrong receiver type")); |
526 } | 585 } |
527 | 586 |
528 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); | 587 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
529 if (try_catch.HasCaught()) return try_catch.Exception(); | 588 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
530 int32_t length = | 589 int32_t length = |
531 convertToUint(self->Get(String::New("length")), &try_catch); | 590 convertToUint(self->Get(String::New("length")), &try_catch); |
532 if (try_catch.HasCaught()) return try_catch.Exception(); | 591 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
533 int32_t byteOffset = | 592 int32_t byteOffset = |
534 convertToUint(self->Get(String::New("byteOffset")), &try_catch); | 593 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
535 if (try_catch.HasCaught()) return try_catch.Exception(); | 594 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
536 int32_t element_size = | 595 int32_t element_size = |
537 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); | 596 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
538 if (try_catch.HasCaught()) return try_catch.Exception(); | 597 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
539 | 598 |
540 if (args.Length() == 0) { | 599 if (args.Length() == 0) { |
541 return ThrowException( | 600 return ThrowException( |
542 String::New("subarray must have at least one parameter.")); | 601 String::New("'subarray' must have at least one argument")); |
543 } | 602 } |
544 int32_t begin = convertToInt(args[0], &try_catch); | 603 int32_t begin = convertToInt(args[0], &try_catch); |
545 if (try_catch.HasCaught()) return try_catch.Exception(); | 604 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
546 if (begin < 0) begin += length; | 605 if (begin < 0) begin += length; |
547 if (begin < 0) begin = 0; | 606 if (begin < 0) begin = 0; |
548 if (begin > length) begin = length; | 607 if (begin > length) begin = length; |
549 | 608 |
550 int32_t end; | 609 int32_t end; |
551 if (args.Length() < 2 || args[1]->IsUndefined()) { | 610 if (args.Length() < 2 || args[1]->IsUndefined()) { |
552 end = length; | 611 end = length; |
553 } else { | 612 } else { |
554 end = convertToInt(args[1], &try_catch); | 613 end = convertToInt(args[1], &try_catch); |
555 if (try_catch.HasCaught()) return try_catch.Exception(); | 614 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
556 if (end < 0) end += length; | 615 if (end < 0) end += length; |
557 if (end < 0) end = 0; | 616 if (end < 0) end = 0; |
558 if (end > length) end = length; | 617 if (end > length) end = length; |
559 if (end < begin) end = begin; | 618 if (end < begin) end = begin; |
560 } | 619 } |
561 | 620 |
562 length = end - begin; | 621 length = end - begin; |
563 byteOffset += begin * element_size; | 622 byteOffset += begin * element_size; |
564 | 623 |
565 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); | 624 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); |
566 Handle<Value> construct_args[] = { | 625 Handle<Value> construct_args[] = { |
567 buffer, Uint32::New(byteOffset), Uint32::New(length) | 626 buffer, Uint32::New(byteOffset), Uint32::New(length) |
568 }; | 627 }; |
569 return constructor->NewInstance(3, construct_args); | 628 return constructor->NewInstance(3, construct_args); |
570 } | 629 } |
571 | 630 |
572 | 631 |
| 632 Handle<Value> Shell::ArraySet(const Arguments& args) { |
| 633 TryCatch try_catch; |
| 634 |
| 635 if (!args.This()->IsObject()) { |
| 636 return ThrowException( |
| 637 String::New("'set' invoked on non-object receiver")); |
| 638 } |
| 639 |
| 640 Local<Object> self = args.This(); |
| 641 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); |
| 642 if (marker.IsEmpty()) { |
| 643 return ThrowException( |
| 644 String::New("'set' invoked on wrong receiver type")); |
| 645 } |
| 646 int32_t length = |
| 647 convertToUint(self->Get(String::New("length")), &try_catch); |
| 648 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 649 int32_t element_size = |
| 650 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
| 651 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 652 |
| 653 if (args.Length() == 0) { |
| 654 return ThrowException( |
| 655 String::New("'set' must have at least one argument")); |
| 656 } |
| 657 if (!args[0]->IsObject() || |
| 658 !args[0]->ToObject()->Has(String::New("length"))) { |
| 659 return ThrowException( |
| 660 String::New("'set' invoked with non-array argument")); |
| 661 } |
| 662 Handle<Object> source = args[0]->ToObject(); |
| 663 int32_t source_length = |
| 664 convertToUint(source->Get(String::New("length")), &try_catch); |
| 665 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 666 |
| 667 int32_t offset; |
| 668 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 669 offset = 0; |
| 670 } else { |
| 671 offset = convertToUint(args[1], &try_catch); |
| 672 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 673 } |
| 674 if (offset + source_length > length) { |
| 675 return ThrowException(String::New("offset or source length out of bounds")); |
| 676 } |
| 677 |
| 678 int32_t source_element_size; |
| 679 if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty()) { |
| 680 source_element_size = 0; |
| 681 } else { |
| 682 source_element_size = |
| 683 convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
| 684 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 685 } |
| 686 |
| 687 if (element_size == source_element_size && |
| 688 self->GetConstructor()->StrictEquals(source->GetConstructor())) { |
| 689 // Use memmove on the array buffers. |
| 690 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
| 691 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 692 Handle<Object> source_buffer = |
| 693 source->Get(String::New("buffer"))->ToObject(); |
| 694 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 695 int32_t byteOffset = |
| 696 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
| 697 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 698 int32_t source_byteOffset = |
| 699 convertToUint(source->Get(String::New("byteOffset")), &try_catch); |
| 700 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 701 |
| 702 uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>( |
| 703 buffer->GetIndexedPropertiesExternalArrayData()); |
| 704 uint8_t* src = source_byteOffset + static_cast<uint8_t*>( |
| 705 source_buffer->GetIndexedPropertiesExternalArrayData()); |
| 706 memmove(dest, src, source_length * element_size); |
| 707 } else if (source_element_size == 0) { |
| 708 // Source is not a typed array, copy element-wise sequentially. |
| 709 for (int i = 0; i < source_length; ++i) { |
| 710 self->Set(offset + i, source->Get(i)); |
| 711 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 712 } |
| 713 } else { |
| 714 // Need to copy element-wise to make the right conversions. |
| 715 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
| 716 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 717 Handle<Object> source_buffer = |
| 718 source->Get(String::New("buffer"))->ToObject(); |
| 719 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 720 |
| 721 if (buffer->StrictEquals(source_buffer)) { |
| 722 // Same backing store, need to handle overlap correctly. |
| 723 // This gets a bit tricky in the case of different element sizes |
| 724 // (which, of course, is extremely unlikely to ever occur in practice). |
| 725 int32_t byteOffset = |
| 726 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
| 727 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 728 int32_t source_byteOffset = |
| 729 convertToUint(source->Get(String::New("byteOffset")), &try_catch); |
| 730 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 731 |
| 732 // Copy as much as we can from left to right. |
| 733 int i = 0; |
| 734 int32_t next_dest_offset = byteOffset + (offset + 1) * element_size; |
| 735 int32_t next_src_offset = source_byteOffset + source_element_size; |
| 736 while (i < length && next_dest_offset <= next_src_offset) { |
| 737 self->Set(offset + i, source->Get(i)); |
| 738 ++i; |
| 739 next_dest_offset += element_size; |
| 740 next_src_offset += source_element_size; |
| 741 } |
| 742 // Of what's left, copy as much as we can from right to left. |
| 743 int j = length - 1; |
| 744 int32_t dest_offset = byteOffset + (offset + j) * element_size; |
| 745 int32_t src_offset = source_byteOffset + j * source_element_size; |
| 746 while (j >= i && dest_offset >= src_offset) { |
| 747 self->Set(offset + j, source->Get(j)); |
| 748 --j; |
| 749 dest_offset -= element_size; |
| 750 src_offset -= source_element_size; |
| 751 } |
| 752 // There can be at most 8 entries left in the middle that need buffering |
| 753 // (because the largest element_size is 8 times the smallest). |
| 754 ASSERT(j+1 - i <= 8); |
| 755 Handle<Value> temp[8]; |
| 756 for (int k = i; k <= j; ++k) { |
| 757 temp[k - i] = source->Get(k); |
| 758 } |
| 759 for (int k = i; k <= j; ++k) { |
| 760 self->Set(offset + k, temp[k - i]); |
| 761 } |
| 762 } else { |
| 763 // Different backing stores, safe to copy element-wise sequentially. |
| 764 for (int i = 0; i < source_length; ++i) |
| 765 self->Set(offset + i, source->Get(i)); |
| 766 } |
| 767 } |
| 768 |
| 769 return Undefined(); |
| 770 } |
| 771 |
| 772 |
573 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { | 773 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { |
574 HandleScope scope; | 774 HandleScope scope; |
575 int32_t length = | 775 int32_t length = |
576 object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); | 776 object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); |
577 V8::AdjustAmountOfExternalAllocatedMemory(-length); | 777 V8::AdjustAmountOfExternalAllocatedMemory(-length); |
578 delete[] static_cast<uint8_t*>(data); | 778 delete[] static_cast<uint8_t*>(data); |
579 object.Dispose(); | 779 object.Dispose(); |
580 } | 780 } |
581 | 781 |
582 | 782 |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
912 0, 1); | 1112 0, 1); |
913 if (result == BZ_OK) { | 1113 if (result == BZ_OK) { |
914 *raw_data_size = decompressed_size; | 1114 *raw_data_size = decompressed_size; |
915 } | 1115 } |
916 return result; | 1116 return result; |
917 } | 1117 } |
918 }; | 1118 }; |
919 #endif | 1119 #endif |
920 | 1120 |
921 | 1121 |
| 1122 Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate( |
| 1123 InvocationCallback fun) { |
| 1124 Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun); |
| 1125 Local<Template> proto_template = buffer_template->PrototypeTemplate(); |
| 1126 proto_template->Set(String::New("slice"), |
| 1127 FunctionTemplate::New(ArrayBufferSlice)); |
| 1128 return buffer_template; |
| 1129 } |
| 1130 |
| 1131 |
922 Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { | 1132 Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { |
923 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); | 1133 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); |
924 Local<Template> proto_template = array_template->PrototypeTemplate(); | 1134 Local<Template> proto_template = array_template->PrototypeTemplate(); |
925 proto_template->Set(String::New("subarray"), FunctionTemplate::New(SubArray)); | 1135 proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet)); |
| 1136 proto_template->Set(String::New("subarray"), |
| 1137 FunctionTemplate::New(ArraySubArray)); |
926 return array_template; | 1138 return array_template; |
927 } | 1139 } |
928 | 1140 |
929 | 1141 |
930 Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { | 1142 Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { |
931 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); | 1143 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); |
932 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); | 1144 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); |
933 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); | 1145 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); |
934 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); | 1146 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); |
935 global_template->Set(String::New("readbuffer"), | 1147 global_template->Set(String::New("readbuffer"), |
936 FunctionTemplate::New(ReadBuffer)); | 1148 FunctionTemplate::New(ReadBuffer)); |
937 global_template->Set(String::New("readline"), | 1149 global_template->Set(String::New("readline"), |
938 FunctionTemplate::New(ReadLine)); | 1150 FunctionTemplate::New(ReadLine)); |
939 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); | 1151 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); |
940 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); | 1152 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); |
941 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); | 1153 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); |
942 global_template->Set(String::New("enableProfiler"), | 1154 global_template->Set(String::New("enableProfiler"), |
943 FunctionTemplate::New(EnableProfiler)); | 1155 FunctionTemplate::New(EnableProfiler)); |
944 global_template->Set(String::New("disableProfiler"), | 1156 global_template->Set(String::New("disableProfiler"), |
945 FunctionTemplate::New(DisableProfiler)); | 1157 FunctionTemplate::New(DisableProfiler)); |
946 | 1158 |
947 // Bind the handlers for external arrays. | 1159 // Bind the handlers for external arrays. |
948 PropertyAttribute attr = | 1160 PropertyAttribute attr = |
949 static_cast<PropertyAttribute>(ReadOnly | DontDelete); | 1161 static_cast<PropertyAttribute>(ReadOnly | DontDelete); |
950 global_template->Set(String::New("ArrayBuffer"), | 1162 global_template->Set(String::New("ArrayBuffer"), |
951 CreateArrayTemplate(ArrayBuffer), attr); | 1163 CreateArrayBufferTemplate(ArrayBuffer), attr); |
952 global_template->Set(String::New("Int8Array"), | 1164 global_template->Set(String::New("Int8Array"), |
953 CreateArrayTemplate(Int8Array), attr); | 1165 CreateArrayTemplate(Int8Array), attr); |
954 global_template->Set(String::New("Uint8Array"), | 1166 global_template->Set(String::New("Uint8Array"), |
955 CreateArrayTemplate(Uint8Array), attr); | 1167 CreateArrayTemplate(Uint8Array), attr); |
956 global_template->Set(String::New("Int16Array"), | 1168 global_template->Set(String::New("Int16Array"), |
957 CreateArrayTemplate(Int16Array), attr); | 1169 CreateArrayTemplate(Int16Array), attr); |
958 global_template->Set(String::New("Uint16Array"), | 1170 global_template->Set(String::New("Uint16Array"), |
959 CreateArrayTemplate(Uint16Array), attr); | 1171 CreateArrayTemplate(Uint16Array), attr); |
960 global_template->Set(String::New("Int32Array"), | 1172 global_template->Set(String::New("Int32Array"), |
961 CreateArrayTemplate(Int32Array), attr); | 1173 CreateArrayTemplate(Int32Array), attr); |
(...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1677 } | 1889 } |
1678 | 1890 |
1679 } // namespace v8 | 1891 } // namespace v8 |
1680 | 1892 |
1681 | 1893 |
1682 #ifndef GOOGLE3 | 1894 #ifndef GOOGLE3 |
1683 int main(int argc, char* argv[]) { | 1895 int main(int argc, char* argv[]) { |
1684 return v8::Shell::Main(argc, argv); | 1896 return v8::Shell::Main(argc, argv); |
1685 } | 1897 } |
1686 #endif | 1898 #endif |
OLD | NEW |