| 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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 #endif | 82 #endif |
| 83 | 83 |
| 84 namespace v8 { | 84 namespace v8 { |
| 85 | 85 |
| 86 | 86 |
| 87 static Handle<Value> Throw(const char* message) { | 87 static Handle<Value> Throw(const char* message) { |
| 88 return ThrowException(String::New(message)); | 88 return ThrowException(String::New(message)); |
| 89 } | 89 } |
| 90 | 90 |
| 91 | 91 |
| 92 // TODO(rossberg): should replace these by proper uses of HasInstance, | |
| 93 // once we figure out a good way to make the templates global. | |
| 94 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; | |
| 95 const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; | |
| 96 | |
| 97 | |
| 98 #define FOR_EACH_STRING(V) \ | |
| 99 V(ArrayBuffer, "ArrayBuffer") \ | |
| 100 V(ArrayBufferMarkerPropName, kArrayBufferMarkerPropName) \ | |
| 101 V(ArrayMarkerPropName, kArrayMarkerPropName) \ | |
| 102 V(buffer, "buffer") \ | |
| 103 V(byteLength, "byteLength") \ | |
| 104 V(byteOffset, "byteOffset") \ | |
| 105 V(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \ | |
| 106 V(length, "length") | |
| 107 | |
| 108 | 92 |
| 109 class PerIsolateData { | 93 class PerIsolateData { |
| 110 public: | 94 public: |
| 111 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) { | 95 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) { |
| 112 HandleScope scope(isolate); | 96 HandleScope scope(isolate); |
| 113 #define INIT_STRING(name, value) \ | |
| 114 name##_string_ = Persistent<String>::New(isolate, String::NewSymbol(value)); | |
| 115 FOR_EACH_STRING(INIT_STRING) | |
| 116 #undef INIT_STRING | |
| 117 isolate->SetData(this); | 97 isolate->SetData(this); |
| 118 } | 98 } |
| 119 | 99 |
| 120 ~PerIsolateData() { | 100 ~PerIsolateData() { |
| 121 #define DISPOSE_STRING(name, value) name##_string_.Dispose(isolate_); | |
| 122 FOR_EACH_STRING(DISPOSE_STRING) | |
| 123 #undef DISPOSE_STRING | |
| 124 isolate_->SetData(NULL); // Not really needed, just to be sure... | 101 isolate_->SetData(NULL); // Not really needed, just to be sure... |
| 125 } | 102 } |
| 126 | 103 |
| 127 inline static PerIsolateData* Get(Isolate* isolate) { | 104 inline static PerIsolateData* Get(Isolate* isolate) { |
| 128 return reinterpret_cast<PerIsolateData*>(isolate->GetData()); | 105 return reinterpret_cast<PerIsolateData*>(isolate->GetData()); |
| 129 } | 106 } |
| 130 | 107 |
| 131 #define DEFINE_STRING_GETTER(name, value) \ | |
| 132 static Handle<String> name##_string(Isolate* isolate) { \ | |
| 133 return Handle<String>(*Get(isolate)->name##_string_); \ | |
| 134 } | |
| 135 FOR_EACH_STRING(DEFINE_STRING_GETTER) | |
| 136 #undef DEFINE_STRING_GETTER | |
| 137 | |
| 138 class RealmScope { | 108 class RealmScope { |
| 139 public: | 109 public: |
| 140 explicit RealmScope(PerIsolateData* data); | 110 explicit RealmScope(PerIsolateData* data); |
| 141 ~RealmScope(); | 111 ~RealmScope(); |
| 142 private: | 112 private: |
| 143 PerIsolateData* data_; | 113 PerIsolateData* data_; |
| 144 }; | 114 }; |
| 145 | 115 |
| 146 private: | 116 private: |
| 147 friend class Shell; | 117 friend class Shell; |
| 148 friend class RealmScope; | 118 friend class RealmScope; |
| 149 Isolate* isolate_; | 119 Isolate* isolate_; |
| 150 int realm_count_; | 120 int realm_count_; |
| 151 int realm_current_; | 121 int realm_current_; |
| 152 int realm_switch_; | 122 int realm_switch_; |
| 153 Persistent<Context>* realms_; | 123 Persistent<Context>* realms_; |
| 154 Persistent<Value> realm_shared_; | 124 Persistent<Value> realm_shared_; |
| 155 | 125 |
| 156 #define DEFINE_MEMBER(name, value) Persistent<String> name##_string_; | |
| 157 FOR_EACH_STRING(DEFINE_MEMBER) | |
| 158 #undef DEFINE_MEMBER | |
| 159 | |
| 160 int RealmFind(Handle<Context> context); | 126 int RealmFind(Handle<Context> context); |
| 161 }; | 127 }; |
| 162 | 128 |
| 163 | 129 |
| 164 LineEditor *LineEditor::current_ = NULL; | 130 LineEditor *LineEditor::current_ = NULL; |
| 165 | 131 |
| 166 | 132 |
| 167 LineEditor::LineEditor(Type type, const char* name) | 133 LineEditor::LineEditor(Type type, const char* name) |
| 168 : type_(type), name_(name) { | 134 : type_(type), name_(name) { |
| 169 if (current_ == NULL || current_->type_ < type) current_ = this; | 135 if (current_ == NULL || current_->type_ < type) current_ = this; |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 source, | 520 source, |
| 555 String::New(*file), | 521 String::New(*file), |
| 556 false, | 522 false, |
| 557 true)) { | 523 true)) { |
| 558 return Throw("Error executing file"); | 524 return Throw("Error executing file"); |
| 559 } | 525 } |
| 560 } | 526 } |
| 561 return Undefined(args.GetIsolate()); | 527 return Undefined(args.GetIsolate()); |
| 562 } | 528 } |
| 563 | 529 |
| 564 static int32_t convertToInt(Local<Value> value_in, TryCatch* try_catch) { | |
| 565 if (value_in->IsInt32()) { | |
| 566 return value_in->Int32Value(); | |
| 567 } | |
| 568 | |
| 569 Local<Value> number = value_in->ToNumber(); | |
| 570 if (try_catch->HasCaught()) return 0; | |
| 571 | |
| 572 ASSERT(number->IsNumber()); | |
| 573 Local<Int32> int32 = number->ToInt32(); | |
| 574 if (try_catch->HasCaught() || int32.IsEmpty()) return 0; | |
| 575 | |
| 576 int32_t value = int32->Int32Value(); | |
| 577 if (try_catch->HasCaught()) return 0; | |
| 578 | |
| 579 return value; | |
| 580 } | |
| 581 | |
| 582 | |
| 583 static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { | |
| 584 int32_t raw_value = convertToInt(value_in, try_catch); | |
| 585 if (try_catch->HasCaught()) return 0; | |
| 586 | |
| 587 if (raw_value < 0) { | |
| 588 Throw("Array length must not be negative."); | |
| 589 return 0; | |
| 590 } | |
| 591 | |
| 592 static const int kMaxLength = 0x3fffffff; | |
| 593 #ifndef V8_SHARED | |
| 594 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); | |
| 595 #endif // V8_SHARED | |
| 596 if (raw_value > static_cast<int32_t>(kMaxLength)) { | |
| 597 Throw("Array length exceeds maximum length."); | |
| 598 } | |
| 599 return raw_value; | |
| 600 } | |
| 601 | |
| 602 | |
| 603 Handle<Value> Shell::CreateExternalArrayBuffer(Isolate* isolate, | |
| 604 Handle<Object> buffer, | |
| 605 int32_t length) { | |
| 606 static const int32_t kMaxSize = 0x7fffffff; | |
| 607 // Make sure the total size fits into a (signed) int. | |
| 608 if (length < 0 || length > kMaxSize) { | |
| 609 return Throw("ArrayBuffer exceeds maximum size (2G)"); | |
| 610 } | |
| 611 uint8_t* data = new uint8_t[length]; | |
| 612 if (data == NULL) { | |
| 613 return Throw("Memory allocation failed"); | |
| 614 } | |
| 615 memset(data, 0, length); | |
| 616 | |
| 617 buffer->SetHiddenValue( | |
| 618 PerIsolateData::ArrayBufferMarkerPropName_string(isolate), True()); | |
| 619 Persistent<Object> persistent_array = | |
| 620 Persistent<Object>::New(isolate, buffer); | |
| 621 persistent_array.MakeWeak(isolate, data, ExternalArrayWeakCallback); | |
| 622 persistent_array.MarkIndependent(isolate); | |
| 623 isolate->AdjustAmountOfExternalAllocatedMemory(length); | |
| 624 | |
| 625 buffer->SetIndexedPropertiesToExternalArrayData( | |
| 626 data, v8::kExternalByteArray, length); | |
| 627 buffer->Set(PerIsolateData::byteLength_string(isolate), | |
| 628 Int32::New(length, isolate), | |
| 629 ReadOnly); | |
| 630 | |
| 631 return buffer; | |
| 632 } | |
| 633 | |
| 634 | |
| 635 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { | |
| 636 if (!args.IsConstructCall()) { | |
| 637 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; | |
| 638 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; | |
| 639 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); | |
| 640 delete[] rec_args; | |
| 641 return result; | |
| 642 } | |
| 643 | |
| 644 if (args.Length() == 0) { | |
| 645 return Throw("ArrayBuffer constructor must have one argument"); | |
| 646 } | |
| 647 TryCatch try_catch; | |
| 648 int32_t length = convertToUint(args[0], &try_catch); | |
| 649 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 650 | |
| 651 return CreateExternalArrayBuffer(args.GetIsolate(), args.This(), length); | |
| 652 } | |
| 653 | |
| 654 | |
| 655 Handle<Object> Shell::CreateExternalArray(Isolate* isolate, | |
| 656 Handle<Object> array, | |
| 657 Handle<Object> buffer, | |
| 658 ExternalArrayType type, | |
| 659 int32_t length, | |
| 660 int32_t byteLength, | |
| 661 int32_t byteOffset, | |
| 662 int32_t element_size) { | |
| 663 ASSERT(element_size == 1 || element_size == 2 || | |
| 664 element_size == 4 || element_size == 8); | |
| 665 ASSERT(byteLength == length * element_size); | |
| 666 | |
| 667 void* data = buffer->GetIndexedPropertiesExternalArrayData(); | |
| 668 ASSERT(data != NULL); | |
| 669 | |
| 670 array->SetIndexedPropertiesToExternalArrayData( | |
| 671 static_cast<uint8_t*>(data) + byteOffset, type, length); | |
| 672 array->SetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate), | |
| 673 Int32::New(type, isolate)); | |
| 674 array->Set(PerIsolateData::byteLength_string(isolate), | |
| 675 Int32::New(byteLength, isolate), | |
| 676 ReadOnly); | |
| 677 array->Set(PerIsolateData::byteOffset_string(isolate), | |
| 678 Int32::New(byteOffset, isolate), | |
| 679 ReadOnly); | |
| 680 array->Set(PerIsolateData::length_string(isolate), | |
| 681 Int32::New(length, isolate), | |
| 682 ReadOnly); | |
| 683 array->Set(PerIsolateData::BYTES_PER_ELEMENT_string(isolate), | |
| 684 Int32::New(element_size, isolate)); | |
| 685 array->Set(PerIsolateData::buffer_string(isolate), | |
| 686 buffer, | |
| 687 ReadOnly); | |
| 688 | |
| 689 return array; | |
| 690 } | |
| 691 | |
| 692 | |
| 693 Handle<Value> Shell::CreateExternalArray(const Arguments& args, | |
| 694 ExternalArrayType type, | |
| 695 int32_t element_size) { | |
| 696 Isolate* isolate = args.GetIsolate(); | |
| 697 if (!args.IsConstructCall()) { | |
| 698 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; | |
| 699 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; | |
| 700 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); | |
| 701 delete[] rec_args; | |
| 702 return result; | |
| 703 } | |
| 704 | |
| 705 TryCatch try_catch; | |
| 706 ASSERT(element_size == 1 || element_size == 2 || | |
| 707 element_size == 4 || element_size == 8); | |
| 708 | |
| 709 // All of the following constructors are supported: | |
| 710 // TypedArray(unsigned long length) | |
| 711 // TypedArray(type[] array) | |
| 712 // TypedArray(TypedArray array) | |
| 713 // TypedArray(ArrayBuffer buffer, | |
| 714 // optional unsigned long byteOffset, | |
| 715 // optional unsigned long length) | |
| 716 Handle<Object> buffer; | |
| 717 int32_t length; | |
| 718 int32_t byteLength; | |
| 719 int32_t byteOffset; | |
| 720 bool init_from_array = false; | |
| 721 if (args.Length() == 0) { | |
| 722 return Throw("Array constructor must have at least one argument"); | |
| 723 } | |
| 724 if (args[0]->IsObject() && | |
| 725 !args[0]->ToObject()->GetHiddenValue( | |
| 726 PerIsolateData::ArrayBufferMarkerPropName_string(isolate)).IsEmpty()) { | |
| 727 // Construct from ArrayBuffer. | |
| 728 buffer = args[0]->ToObject(); | |
| 729 int32_t bufferLength = convertToUint( | |
| 730 buffer->Get(PerIsolateData::byteLength_string(isolate)), &try_catch); | |
| 731 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 732 | |
| 733 if (args.Length() < 2 || args[1]->IsUndefined()) { | |
| 734 byteOffset = 0; | |
| 735 } else { | |
| 736 byteOffset = convertToUint(args[1], &try_catch); | |
| 737 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 738 if (byteOffset > bufferLength) { | |
| 739 return Throw("byteOffset out of bounds"); | |
| 740 } | |
| 741 if (byteOffset % element_size != 0) { | |
| 742 return Throw("byteOffset must be multiple of element size"); | |
| 743 } | |
| 744 } | |
| 745 | |
| 746 if (args.Length() < 3 || args[2]->IsUndefined()) { | |
| 747 byteLength = bufferLength - byteOffset; | |
| 748 length = byteLength / element_size; | |
| 749 if (byteLength % element_size != 0) { | |
| 750 return Throw("buffer size must be multiple of element size"); | |
| 751 } | |
| 752 } else { | |
| 753 length = convertToUint(args[2], &try_catch); | |
| 754 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 755 byteLength = length * element_size; | |
| 756 if (byteOffset + byteLength > bufferLength) { | |
| 757 return Throw("length out of bounds"); | |
| 758 } | |
| 759 } | |
| 760 } else { | |
| 761 if (args[0]->IsObject() && | |
| 762 args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) { | |
| 763 // Construct from array. | |
| 764 Local<Value> value = | |
| 765 args[0]->ToObject()->Get(PerIsolateData::length_string(isolate)); | |
| 766 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 767 length = convertToUint(value, &try_catch); | |
| 768 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 769 init_from_array = true; | |
| 770 } else { | |
| 771 // Construct from size. | |
| 772 length = convertToUint(args[0], &try_catch); | |
| 773 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 774 } | |
| 775 byteLength = length * element_size; | |
| 776 byteOffset = 0; | |
| 777 | |
| 778 Handle<Object> global = Context::GetCurrent()->Global(); | |
| 779 Handle<Value> array_buffer = | |
| 780 global->Get(PerIsolateData::ArrayBuffer_string(isolate)); | |
| 781 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); | |
| 782 Handle<Value> buffer_args[] = { Uint32::New(byteLength, isolate) }; | |
| 783 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( | |
| 784 1, buffer_args); | |
| 785 if (try_catch.HasCaught()) return result; | |
| 786 buffer = result->ToObject(); | |
| 787 } | |
| 788 | |
| 789 Handle<Object> array = | |
| 790 CreateExternalArray(isolate, args.This(), buffer, type, length, | |
| 791 byteLength, byteOffset, element_size); | |
| 792 | |
| 793 if (init_from_array) { | |
| 794 Handle<Object> init = args[0]->ToObject(); | |
| 795 for (int i = 0; i < length; ++i) { | |
| 796 Local<Value> value = init->Get(i); | |
| 797 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 798 array->Set(i, value); | |
| 799 } | |
| 800 } | |
| 801 | |
| 802 return array; | |
| 803 } | |
| 804 | |
| 805 | |
| 806 Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) { | |
| 807 TryCatch try_catch; | |
| 808 | |
| 809 if (!args.This()->IsObject()) { | |
| 810 return Throw("'slice' invoked on non-object receiver"); | |
| 811 } | |
| 812 | |
| 813 Isolate* isolate = args.GetIsolate(); | |
| 814 Local<Object> self = args.This(); | |
| 815 Local<Value> marker = self->GetHiddenValue( | |
| 816 PerIsolateData::ArrayBufferMarkerPropName_string(isolate)); | |
| 817 if (marker.IsEmpty()) { | |
| 818 return Throw("'slice' invoked on wrong receiver type"); | |
| 819 } | |
| 820 | |
| 821 int32_t length = convertToUint( | |
| 822 self->Get(PerIsolateData::byteLength_string(isolate)), &try_catch); | |
| 823 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 824 | |
| 825 if (args.Length() == 0) { | |
| 826 return Throw("'slice' must have at least one argument"); | |
| 827 } | |
| 828 int32_t begin = convertToInt(args[0], &try_catch); | |
| 829 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 830 if (begin < 0) begin += length; | |
| 831 if (begin < 0) begin = 0; | |
| 832 if (begin > length) begin = length; | |
| 833 | |
| 834 int32_t end; | |
| 835 if (args.Length() < 2 || args[1]->IsUndefined()) { | |
| 836 end = length; | |
| 837 } else { | |
| 838 end = convertToInt(args[1], &try_catch); | |
| 839 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 840 if (end < 0) end += length; | |
| 841 if (end < 0) end = 0; | |
| 842 if (end > length) end = length; | |
| 843 if (end < begin) end = begin; | |
| 844 } | |
| 845 | |
| 846 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); | |
| 847 Handle<Value> new_args[] = { Uint32::New(end - begin, isolate) }; | |
| 848 Handle<Value> result = constructor->NewInstance(1, new_args); | |
| 849 if (try_catch.HasCaught()) return result; | |
| 850 Handle<Object> buffer = result->ToObject(); | |
| 851 uint8_t* dest = | |
| 852 static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData()); | |
| 853 uint8_t* src = begin + static_cast<uint8_t*>( | |
| 854 self->GetIndexedPropertiesExternalArrayData()); | |
| 855 memcpy(dest, src, end - begin); | |
| 856 | |
| 857 return buffer; | |
| 858 } | |
| 859 | |
| 860 | |
| 861 Handle<Value> Shell::ArraySubArray(const Arguments& args) { | |
| 862 TryCatch try_catch; | |
| 863 | |
| 864 if (!args.This()->IsObject()) { | |
| 865 return Throw("'subarray' invoked on non-object receiver"); | |
| 866 } | |
| 867 | |
| 868 Isolate* isolate = args.GetIsolate(); | |
| 869 Local<Object> self = args.This(); | |
| 870 Local<Value> marker = | |
| 871 self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate)); | |
| 872 if (marker.IsEmpty()) { | |
| 873 return Throw("'subarray' invoked on wrong receiver type"); | |
| 874 } | |
| 875 | |
| 876 Handle<Object> buffer = | |
| 877 self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); | |
| 878 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 879 int32_t length = convertToUint( | |
| 880 self->Get(PerIsolateData::length_string(isolate)), &try_catch); | |
| 881 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 882 int32_t byteOffset = convertToUint( | |
| 883 self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); | |
| 884 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 885 int32_t element_size = convertToUint( | |
| 886 self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch); | |
| 887 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 888 | |
| 889 if (args.Length() == 0) { | |
| 890 return Throw("'subarray' must have at least one argument"); | |
| 891 } | |
| 892 int32_t begin = convertToInt(args[0], &try_catch); | |
| 893 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 894 if (begin < 0) begin += length; | |
| 895 if (begin < 0) begin = 0; | |
| 896 if (begin > length) begin = length; | |
| 897 | |
| 898 int32_t end; | |
| 899 if (args.Length() < 2 || args[1]->IsUndefined()) { | |
| 900 end = length; | |
| 901 } else { | |
| 902 end = convertToInt(args[1], &try_catch); | |
| 903 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 904 if (end < 0) end += length; | |
| 905 if (end < 0) end = 0; | |
| 906 if (end > length) end = length; | |
| 907 if (end < begin) end = begin; | |
| 908 } | |
| 909 | |
| 910 length = end - begin; | |
| 911 byteOffset += begin * element_size; | |
| 912 | |
| 913 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); | |
| 914 Handle<Value> construct_args[] = { | |
| 915 buffer, Uint32::New(byteOffset, isolate), Uint32::New(length, isolate) | |
| 916 }; | |
| 917 return constructor->NewInstance(3, construct_args); | |
| 918 } | |
| 919 | |
| 920 | |
| 921 Handle<Value> Shell::ArraySet(const Arguments& args) { | |
| 922 TryCatch try_catch; | |
| 923 | |
| 924 if (!args.This()->IsObject()) { | |
| 925 return Throw("'set' invoked on non-object receiver"); | |
| 926 } | |
| 927 | |
| 928 Isolate* isolate = args.GetIsolate(); | |
| 929 Local<Object> self = args.This(); | |
| 930 Local<Value> marker = | |
| 931 self->GetHiddenValue(PerIsolateData::ArrayMarkerPropName_string(isolate)); | |
| 932 if (marker.IsEmpty()) { | |
| 933 return Throw("'set' invoked on wrong receiver type"); | |
| 934 } | |
| 935 int32_t length = convertToUint( | |
| 936 self->Get(PerIsolateData::length_string(isolate)), &try_catch); | |
| 937 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 938 int32_t element_size = convertToUint( | |
| 939 self->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), &try_catch); | |
| 940 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 941 | |
| 942 if (args.Length() == 0) { | |
| 943 return Throw("'set' must have at least one argument"); | |
| 944 } | |
| 945 if (!args[0]->IsObject() || | |
| 946 !args[0]->ToObject()->Has(PerIsolateData::length_string(isolate))) { | |
| 947 return Throw("'set' invoked with non-array argument"); | |
| 948 } | |
| 949 Handle<Object> source = args[0]->ToObject(); | |
| 950 int32_t source_length = convertToUint( | |
| 951 source->Get(PerIsolateData::length_string(isolate)), &try_catch); | |
| 952 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 953 | |
| 954 int32_t offset; | |
| 955 if (args.Length() < 2 || args[1]->IsUndefined()) { | |
| 956 offset = 0; | |
| 957 } else { | |
| 958 offset = convertToUint(args[1], &try_catch); | |
| 959 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 960 } | |
| 961 if (offset + source_length > length) { | |
| 962 return Throw("offset or source length out of bounds"); | |
| 963 } | |
| 964 | |
| 965 int32_t source_element_size; | |
| 966 if (source->GetHiddenValue( | |
| 967 PerIsolateData::ArrayMarkerPropName_string(isolate)).IsEmpty()) { | |
| 968 source_element_size = 0; | |
| 969 } else { | |
| 970 source_element_size = convertToUint( | |
| 971 source->Get(PerIsolateData::BYTES_PER_ELEMENT_string(isolate)), | |
| 972 &try_catch); | |
| 973 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 974 } | |
| 975 | |
| 976 if (element_size == source_element_size && | |
| 977 self->GetConstructor()->StrictEquals(source->GetConstructor())) { | |
| 978 // Use memmove on the array buffers. | |
| 979 Handle<Object> buffer = | |
| 980 self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); | |
| 981 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 982 Handle<Object> source_buffer = | |
| 983 source->Get(PerIsolateData::buffer_string(isolate))->ToObject(); | |
| 984 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 985 int32_t byteOffset = convertToUint( | |
| 986 self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); | |
| 987 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 988 int32_t source_byteOffset = convertToUint( | |
| 989 source->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); | |
| 990 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 991 | |
| 992 uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>( | |
| 993 buffer->GetIndexedPropertiesExternalArrayData()); | |
| 994 uint8_t* src = source_byteOffset + static_cast<uint8_t*>( | |
| 995 source_buffer->GetIndexedPropertiesExternalArrayData()); | |
| 996 memmove(dest, src, source_length * element_size); | |
| 997 } else if (source_element_size == 0) { | |
| 998 // Source is not a typed array, copy element-wise sequentially. | |
| 999 for (int i = 0; i < source_length; ++i) { | |
| 1000 self->Set(offset + i, source->Get(i)); | |
| 1001 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 1002 } | |
| 1003 } else { | |
| 1004 // Need to copy element-wise to make the right conversions. | |
| 1005 Handle<Object> buffer = | |
| 1006 self->Get(PerIsolateData::buffer_string(isolate))->ToObject(); | |
| 1007 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 1008 Handle<Object> source_buffer = | |
| 1009 source->Get(PerIsolateData::buffer_string(isolate))->ToObject(); | |
| 1010 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 1011 | |
| 1012 if (buffer->StrictEquals(source_buffer)) { | |
| 1013 // Same backing store, need to handle overlap correctly. | |
| 1014 // This gets a bit tricky in the case of different element sizes | |
| 1015 // (which, of course, is extremely unlikely to ever occur in practice). | |
| 1016 int32_t byteOffset = convertToUint( | |
| 1017 self->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); | |
| 1018 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 1019 int32_t source_byteOffset = convertToUint( | |
| 1020 source->Get(PerIsolateData::byteOffset_string(isolate)), &try_catch); | |
| 1021 if (try_catch.HasCaught()) return try_catch.ReThrow(); | |
| 1022 | |
| 1023 // Copy as much as we can from left to right. | |
| 1024 int i = 0; | |
| 1025 int32_t next_dest_offset = byteOffset + (offset + 1) * element_size; | |
| 1026 int32_t next_src_offset = source_byteOffset + source_element_size; | |
| 1027 while (i < length && next_dest_offset <= next_src_offset) { | |
| 1028 self->Set(offset + i, source->Get(i)); | |
| 1029 ++i; | |
| 1030 next_dest_offset += element_size; | |
| 1031 next_src_offset += source_element_size; | |
| 1032 } | |
| 1033 // Of what's left, copy as much as we can from right to left. | |
| 1034 int j = length - 1; | |
| 1035 int32_t dest_offset = byteOffset + (offset + j) * element_size; | |
| 1036 int32_t src_offset = source_byteOffset + j * source_element_size; | |
| 1037 while (j >= i && dest_offset >= src_offset) { | |
| 1038 self->Set(offset + j, source->Get(j)); | |
| 1039 --j; | |
| 1040 dest_offset -= element_size; | |
| 1041 src_offset -= source_element_size; | |
| 1042 } | |
| 1043 // There can be at most 8 entries left in the middle that need buffering | |
| 1044 // (because the largest element_size is 8 times the smallest). | |
| 1045 ASSERT(j+1 - i <= 8); | |
| 1046 Handle<Value> temp[8]; | |
| 1047 for (int k = i; k <= j; ++k) { | |
| 1048 temp[k - i] = source->Get(k); | |
| 1049 } | |
| 1050 for (int k = i; k <= j; ++k) { | |
| 1051 self->Set(offset + k, temp[k - i]); | |
| 1052 } | |
| 1053 } else { | |
| 1054 // Different backing stores, safe to copy element-wise sequentially. | |
| 1055 for (int i = 0; i < source_length; ++i) | |
| 1056 self->Set(offset + i, source->Get(i)); | |
| 1057 } | |
| 1058 } | |
| 1059 | |
| 1060 return Undefined(args.GetIsolate()); | |
| 1061 } | |
| 1062 | |
| 1063 | |
| 1064 void Shell::ExternalArrayWeakCallback(v8::Isolate* isolate, | |
| 1065 Persistent<Object>* object, | |
| 1066 uint8_t* data) { | |
| 1067 HandleScope scope(isolate); | |
| 1068 int32_t length = (*object)->Get( | |
| 1069 PerIsolateData::byteLength_string(isolate))->Uint32Value(); | |
| 1070 isolate->AdjustAmountOfExternalAllocatedMemory(-length); | |
| 1071 delete[] data; | |
| 1072 object->Dispose(isolate); | |
| 1073 } | |
| 1074 | |
| 1075 | |
| 1076 Handle<Value> Shell::Int8Array(const Arguments& args) { | |
| 1077 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); | |
| 1078 } | |
| 1079 | |
| 1080 | |
| 1081 Handle<Value> Shell::Uint8Array(const Arguments& args) { | |
| 1082 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); | |
| 1083 } | |
| 1084 | |
| 1085 | |
| 1086 Handle<Value> Shell::Int16Array(const Arguments& args) { | |
| 1087 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t)); | |
| 1088 } | |
| 1089 | |
| 1090 | |
| 1091 Handle<Value> Shell::Uint16Array(const Arguments& args) { | |
| 1092 return CreateExternalArray( | |
| 1093 args, kExternalUnsignedShortArray, sizeof(uint16_t)); | |
| 1094 } | |
| 1095 | |
| 1096 | |
| 1097 Handle<Value> Shell::Int32Array(const Arguments& args) { | |
| 1098 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t)); | |
| 1099 } | |
| 1100 | |
| 1101 | |
| 1102 Handle<Value> Shell::Uint32Array(const Arguments& args) { | |
| 1103 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t)); | |
| 1104 } | |
| 1105 | |
| 1106 | |
| 1107 Handle<Value> Shell::Float32Array(const Arguments& args) { | |
| 1108 return CreateExternalArray( | |
| 1109 args, kExternalFloatArray, sizeof(float)); // NOLINT | |
| 1110 } | |
| 1111 | |
| 1112 | |
| 1113 Handle<Value> Shell::Float64Array(const Arguments& args) { | |
| 1114 return CreateExternalArray( | |
| 1115 args, kExternalDoubleArray, sizeof(double)); // NOLINT | |
| 1116 } | |
| 1117 | |
| 1118 | |
| 1119 Handle<Value> Shell::Uint8ClampedArray(const Arguments& args) { | |
| 1120 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t)); | |
| 1121 } | |
| 1122 | |
| 1123 | 530 |
| 1124 Handle<Value> Shell::Quit(const Arguments& args) { | 531 Handle<Value> Shell::Quit(const Arguments& args) { |
| 1125 int exit_code = args[0]->Int32Value(); | 532 int exit_code = args[0]->Int32Value(); |
| 1126 OnExit(); | 533 OnExit(); |
| 1127 exit(exit_code); | 534 exit(exit_code); |
| 1128 return Undefined(args.GetIsolate()); | 535 return Undefined(args.GetIsolate()); |
| 1129 } | 536 } |
| 1130 | 537 |
| 1131 | 538 |
| 1132 Handle<Value> Shell::Version(const Arguments& args) { | 539 Handle<Value> Shell::Version(const Arguments& args) { |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1405 0, 1); | 812 0, 1); |
| 1406 if (result == BZ_OK) { | 813 if (result == BZ_OK) { |
| 1407 *raw_data_size = decompressed_size; | 814 *raw_data_size = decompressed_size; |
| 1408 } | 815 } |
| 1409 return result; | 816 return result; |
| 1410 } | 817 } |
| 1411 }; | 818 }; |
| 1412 #endif | 819 #endif |
| 1413 | 820 |
| 1414 | 821 |
| 1415 Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate( | |
| 1416 InvocationCallback fun) { | |
| 1417 Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun); | |
| 1418 Local<Template> proto_template = buffer_template->PrototypeTemplate(); | |
| 1419 proto_template->Set(String::New("slice"), | |
| 1420 FunctionTemplate::New(ArrayBufferSlice)); | |
| 1421 return buffer_template; | |
| 1422 } | |
| 1423 | |
| 1424 | |
| 1425 Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { | |
| 1426 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); | |
| 1427 Local<Template> proto_template = array_template->PrototypeTemplate(); | |
| 1428 proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet)); | |
| 1429 proto_template->Set(String::New("subarray"), | |
| 1430 FunctionTemplate::New(ArraySubArray)); | |
| 1431 return array_template; | |
| 1432 } | |
| 1433 | |
| 1434 | |
| 1435 Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { | 822 Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { |
| 1436 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); | 823 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); |
| 1437 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); | 824 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); |
| 1438 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); | 825 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); |
| 1439 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); | 826 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); |
| 1440 global_template->Set(String::New("readbuffer"), | 827 global_template->Set(String::New("readbuffer"), |
| 1441 FunctionTemplate::New(ReadBuffer)); | 828 FunctionTemplate::New(ReadBuffer)); |
| 1442 global_template->Set(String::New("readline"), | 829 global_template->Set(String::New("readline"), |
| 1443 FunctionTemplate::New(ReadLine)); | 830 FunctionTemplate::New(ReadLine)); |
| 1444 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); | 831 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1462 realm_template->Set(String::New("dispose"), | 849 realm_template->Set(String::New("dispose"), |
| 1463 FunctionTemplate::New(RealmDispose)); | 850 FunctionTemplate::New(RealmDispose)); |
| 1464 realm_template->Set(String::New("switch"), | 851 realm_template->Set(String::New("switch"), |
| 1465 FunctionTemplate::New(RealmSwitch)); | 852 FunctionTemplate::New(RealmSwitch)); |
| 1466 realm_template->Set(String::New("eval"), | 853 realm_template->Set(String::New("eval"), |
| 1467 FunctionTemplate::New(RealmEval)); | 854 FunctionTemplate::New(RealmEval)); |
| 1468 realm_template->SetAccessor(String::New("shared"), | 855 realm_template->SetAccessor(String::New("shared"), |
| 1469 RealmSharedGet, RealmSharedSet); | 856 RealmSharedGet, RealmSharedSet); |
| 1470 global_template->Set(String::New("Realm"), realm_template); | 857 global_template->Set(String::New("Realm"), realm_template); |
| 1471 | 858 |
| 1472 // Bind the handlers for external arrays. | |
| 1473 #ifndef V8_SHARED | |
| 1474 if (!i::FLAG_harmony_typed_arrays) { | |
| 1475 #endif // V8_SHARED | |
| 1476 PropertyAttribute attr = | |
| 1477 static_cast<PropertyAttribute>(ReadOnly | DontDelete); | |
| 1478 global_template->Set(PerIsolateData::ArrayBuffer_string(isolate), | |
| 1479 CreateArrayBufferTemplate(ArrayBuffer), attr); | |
| 1480 global_template->Set(String::New("Int8Array"), | |
| 1481 CreateArrayTemplate(Int8Array), attr); | |
| 1482 global_template->Set(String::New("Uint8Array"), | |
| 1483 CreateArrayTemplate(Uint8Array), attr); | |
| 1484 global_template->Set(String::New("Int16Array"), | |
| 1485 CreateArrayTemplate(Int16Array), attr); | |
| 1486 global_template->Set(String::New("Uint16Array"), | |
| 1487 CreateArrayTemplate(Uint16Array), attr); | |
| 1488 global_template->Set(String::New("Int32Array"), | |
| 1489 CreateArrayTemplate(Int32Array), attr); | |
| 1490 global_template->Set(String::New("Uint32Array"), | |
| 1491 CreateArrayTemplate(Uint32Array), attr); | |
| 1492 global_template->Set(String::New("Float32Array"), | |
| 1493 CreateArrayTemplate(Float32Array), attr); | |
| 1494 global_template->Set(String::New("Float64Array"), | |
| 1495 CreateArrayTemplate(Float64Array), attr); | |
| 1496 global_template->Set(String::New("Uint8ClampedArray"), | |
| 1497 CreateArrayTemplate(Uint8ClampedArray), attr); | |
| 1498 #ifndef V8_SHARED | |
| 1499 } | |
| 1500 #endif // V8_SHARED | |
| 1501 | |
| 1502 #if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64) | 859 #if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64) |
| 1503 Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); | 860 Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); |
| 1504 AddOSMethods(os_templ); | 861 AddOSMethods(os_templ); |
| 1505 global_template->Set(String::New("os"), os_templ); | 862 global_template->Set(String::New("os"), os_templ); |
| 1506 #endif // V8_SHARED | 863 #endif // V8_SHARED |
| 1507 | 864 |
| 1508 return global_template; | 865 return global_template; |
| 1509 } | 866 } |
| 1510 | 867 |
| 1511 | 868 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1698 int length; | 1055 int length; |
| 1699 if (*filename == NULL) { | 1056 if (*filename == NULL) { |
| 1700 return Throw("Error loading file"); | 1057 return Throw("Error loading file"); |
| 1701 } | 1058 } |
| 1702 | 1059 |
| 1703 uint8_t* data = reinterpret_cast<uint8_t*>( | 1060 uint8_t* data = reinterpret_cast<uint8_t*>( |
| 1704 ReadChars(args.GetIsolate(), *filename, &length)); | 1061 ReadChars(args.GetIsolate(), *filename, &length)); |
| 1705 if (data == NULL) { | 1062 if (data == NULL) { |
| 1706 return Throw("Error reading file"); | 1063 return Throw("Error reading file"); |
| 1707 } | 1064 } |
| 1708 Isolate* isolate = args.GetIsolate(); | 1065 Handle<v8::ArrayBuffer> buffer = ArrayBuffer::New(length); |
| 1709 Handle<Object> buffer = Object::New(); | 1066 memcpy(buffer->Data(), data, length); |
| 1710 buffer->SetHiddenValue( | 1067 delete[] data; |
| 1711 PerIsolateData::ArrayBufferMarkerPropName_string(isolate), True()); | |
| 1712 Persistent<Object> persistent_buffer = | |
| 1713 Persistent<Object>::New(isolate, buffer); | |
| 1714 persistent_buffer.MakeWeak(isolate, data, ExternalArrayWeakCallback); | |
| 1715 persistent_buffer.MarkIndependent(isolate); | |
| 1716 isolate->AdjustAmountOfExternalAllocatedMemory(length); | |
| 1717 | |
| 1718 buffer->SetIndexedPropertiesToExternalArrayData( | |
| 1719 data, kExternalUnsignedByteArray, length); | |
| 1720 buffer->Set(PerIsolateData::byteLength_string(isolate), | |
| 1721 Int32::New(static_cast<int32_t>(length), isolate), ReadOnly); | |
| 1722 return buffer; | 1068 return buffer; |
| 1723 } | 1069 } |
| 1724 | 1070 |
| 1725 | 1071 |
| 1726 #ifndef V8_SHARED | 1072 #ifndef V8_SHARED |
| 1727 static char* ReadToken(char* data, char token) { | 1073 static char* ReadToken(char* data, char token) { |
| 1728 char* next = i::OS::StrChr(data, token); | 1074 char* next = i::OS::StrChr(data, token); |
| 1729 if (next != NULL) { | 1075 if (next != NULL) { |
| 1730 *next = '\0'; | 1076 *next = '\0'; |
| 1731 return (next + 1); | 1077 return (next + 1); |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2256 } | 1602 } |
| 2257 | 1603 |
| 2258 } // namespace v8 | 1604 } // namespace v8 |
| 2259 | 1605 |
| 2260 | 1606 |
| 2261 #ifndef GOOGLE3 | 1607 #ifndef GOOGLE3 |
| 2262 int main(int argc, char* argv[]) { | 1608 int main(int argc, char* argv[]) { |
| 2263 return v8::Shell::Main(argc, argv); | 1609 return v8::Shell::Main(argc, argv); |
| 2264 } | 1610 } |
| 2265 #endif | 1611 #endif |
| OLD | NEW |