| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/atomic-utils.h" | 5 #include "src/base/atomic-utils.h" |
| 6 #include "src/macro-assembler.h" | 6 #include "src/macro-assembler.h" |
| 7 #include "src/objects.h" | 7 #include "src/objects.h" |
| 8 #include "src/property-descriptor.h" | 8 #include "src/property-descriptor.h" |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| 11 #include "src/simulator.h" | 11 #include "src/simulator.h" |
| 12 | 12 |
| 13 #include "src/wasm/ast-decoder.h" | 13 #include "src/wasm/ast-decoder.h" |
| 14 #include "src/wasm/module-decoder.h" | 14 #include "src/wasm/module-decoder.h" |
| 15 #include "src/wasm/wasm-function-name-table.h" | 15 #include "src/wasm/wasm-function-name-table.h" |
| 16 #include "src/wasm/wasm-module.h" | 16 #include "src/wasm/wasm-module.h" |
| 17 #include "src/wasm/wasm-result.h" | 17 #include "src/wasm/wasm-result.h" |
| 18 | 18 |
| 19 #include "src/compiler/wasm-compiler.h" | 19 #include "src/compiler/wasm-compiler.h" |
| 20 | 20 |
| 21 namespace v8 { | 21 namespace v8 { |
| 22 namespace internal { | 22 namespace internal { |
| 23 namespace wasm { | 23 namespace wasm { |
| 24 | 24 |
| 25 static const int kPlaceholderMarker = 1000000000; | |
| 26 | |
| 27 static const char* wasmSections[] = { | 25 static const char* wasmSections[] = { |
| 28 #define F(enumerator, order, string) string, | 26 #define F(enumerator, order, string) string, |
| 29 FOR_EACH_WASM_SECTION_TYPE(F) | 27 FOR_EACH_WASM_SECTION_TYPE(F) |
| 30 #undef F | 28 #undef F |
| 31 "<unknown>" // entry for "Max" | 29 "<unknown>" // entry for "Max" |
| 32 }; | 30 }; |
| 33 | 31 |
| 34 static uint8_t wasmSectionsLengths[]{ | 32 static uint8_t wasmSectionsLengths[]{ |
| 35 #define F(enumerator, order, string) sizeof(string) - 1, | 33 #define F(enumerator, order, string) sizeof(string) - 1, |
| 36 FOR_EACH_WASM_SECTION_TYPE(F) | 34 FOR_EACH_WASM_SECTION_TYPE(F) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 os.write(name.start(), name.length()); | 102 os.write(name.start(), name.length()); |
| 105 } else { | 103 } else { |
| 106 os << "+" << pair.function_->func_index; | 104 os << "+" << pair.function_->func_index; |
| 107 } | 105 } |
| 108 } else { | 106 } else { |
| 109 os << "?"; | 107 os << "?"; |
| 110 } | 108 } |
| 111 return os; | 109 return os; |
| 112 } | 110 } |
| 113 | 111 |
| 114 // A helper class for compiling multiple wasm functions that offers | |
| 115 // placeholder code objects for calling functions that are not yet compiled. | |
| 116 class WasmLinker { | |
| 117 public: | |
| 118 WasmLinker(Isolate* isolate, std::vector<Handle<Code>>* functions) | |
| 119 : isolate_(isolate), | |
| 120 placeholder_code_(functions->size()), | |
| 121 function_code_(functions) { | |
| 122 for (uint32_t i = 0; i < placeholder_code_.size(); ++i) { | |
| 123 CreatePlaceholder(i); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 Handle<Code> GetPlaceholderCode(uint32_t index) const { | |
| 128 return placeholder_code_[index]; | |
| 129 } | |
| 130 | |
| 131 void Finish(uint32_t index, Handle<Code> code) { | |
| 132 DCHECK(index < function_code().size()); | |
| 133 function_code()[index] = code; | |
| 134 } | |
| 135 | |
| 136 void Link(Handle<FixedArray> function_table, | |
| 137 const std::vector<uint16_t>& functions) { | |
| 138 for (size_t i = 0; i < function_code().size(); i++) { | |
| 139 LinkFunction(function_code()[i]); | |
| 140 } | |
| 141 if (!function_table.is_null()) { | |
| 142 int table_size = static_cast<int>(functions.size()); | |
| 143 DCHECK_EQ(function_table->length(), table_size * 2); | |
| 144 for (int i = 0; i < table_size; i++) { | |
| 145 function_table->set(i + table_size, *function_code()[functions[i]]); | |
| 146 } | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 private: | |
| 151 std::vector<Handle<Code>>& function_code() { return *function_code_; } | |
| 152 | |
| 153 void CreatePlaceholder(uint32_t index) { | |
| 154 DCHECK(index < function_code().size()); | |
| 155 DCHECK(function_code()[index].is_null()); | |
| 156 // Create a placeholder code object and encode the corresponding index in | |
| 157 // the {constant_pool_offset} field of the code object. | |
| 158 // TODO(titzer): placeholder code objects are somewhat dangerous. | |
| 159 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. | |
| 160 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; | |
| 161 Handle<Code> code = isolate_->factory()->NewCode( | |
| 162 desc, Code::KindField::encode(Code::WASM_FUNCTION), | |
| 163 Handle<Object>::null()); | |
| 164 code->set_constant_pool_offset(static_cast<int>(index) + | |
| 165 kPlaceholderMarker); | |
| 166 placeholder_code_[index] = code; | |
| 167 function_code()[index] = code; | |
| 168 } | |
| 169 | |
| 170 Isolate* isolate_; | |
| 171 std::vector<Handle<Code>> placeholder_code_; | |
| 172 std::vector<Handle<Code>>* function_code_; | |
| 173 | |
| 174 void LinkFunction(Handle<Code> code) { | |
| 175 bool modified = false; | |
| 176 int mode_mask = RelocInfo::kCodeTargetMask; | |
| 177 AllowDeferredHandleDereference embedding_raw_address; | |
| 178 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { | |
| 179 RelocInfo::Mode mode = it.rinfo()->rmode(); | |
| 180 if (RelocInfo::IsCodeTarget(mode)) { | |
| 181 Code* target = | |
| 182 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | |
| 183 if (target->kind() == Code::WASM_FUNCTION && | |
| 184 target->constant_pool_offset() >= kPlaceholderMarker) { | |
| 185 // Patch direct calls to placeholder code objects. | |
| 186 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; | |
| 187 CHECK(index < function_code().size()); | |
| 188 Handle<Code> new_target = function_code()[index]; | |
| 189 if (target != *new_target) { | |
| 190 CHECK_EQ(*placeholder_code_[index], target); | |
| 191 it.rinfo()->set_target_address(new_target->instruction_start(), | |
| 192 SKIP_WRITE_BARRIER, | |
| 193 SKIP_ICACHE_FLUSH); | |
| 194 modified = true; | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 } | |
| 199 if (modified) { | |
| 200 Assembler::FlushICache(isolate_, code->instruction_start(), | |
| 201 code->instruction_size()); | |
| 202 } | |
| 203 } | |
| 204 }; | |
| 205 | |
| 206 namespace { | 112 namespace { |
| 207 // Internal constants for the layout of the module object. | 113 // Internal constants for the layout of the module object. |
| 208 const int kWasmModuleInternalFieldCount = 5; | 114 const int kWasmModuleInternalFieldCount = 5; |
| 209 const int kWasmModuleFunctionTable = 0; | 115 const int kWasmModuleFunctionTable = 0; |
| 210 const int kWasmModuleCodeTable = 1; | 116 const int kWasmModuleCodeTable = 1; |
| 211 const int kWasmMemArrayBuffer = 2; | 117 const int kWasmMemArrayBuffer = 2; |
| 212 const int kWasmGlobalsArrayBuffer = 3; | 118 const int kWasmGlobalsArrayBuffer = 3; |
| 213 const int kWasmFunctionNamesArray = 4; | 119 const int kWasmFunctionNamesArray = 4; |
| 214 | 120 |
| 215 void LoadDataSegments(const WasmModule* module, byte* mem_addr, | 121 void LoadDataSegments(const WasmModule* module, byte* mem_addr, |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 } | 634 } |
| 729 if (!instance.globals_buffer.is_null()) { | 635 if (!instance.globals_buffer.is_null()) { |
| 730 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, | 636 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, |
| 731 *instance.globals_buffer); | 637 *instance.globals_buffer); |
| 732 } | 638 } |
| 733 | 639 |
| 734 HistogramTimerScope wasm_compile_module_time_scope( | 640 HistogramTimerScope wasm_compile_module_time_scope( |
| 735 isolate->counters()->wasm_compile_module_time()); | 641 isolate->counters()->wasm_compile_module_time()); |
| 736 | 642 |
| 737 instance.function_table = BuildFunctionTable(isolate, this); | 643 instance.function_table = BuildFunctionTable(isolate, this); |
| 738 WasmLinker linker(isolate, &instance.function_code); | |
| 739 ModuleEnv module_env; | 644 ModuleEnv module_env; |
| 740 module_env.module = this; | 645 module_env.module = this; |
| 741 module_env.instance = &instance; | 646 module_env.instance = &instance; |
| 742 module_env.linker = &linker; | |
| 743 module_env.origin = origin; | 647 module_env.origin = origin; |
| 744 | 648 |
| 745 //------------------------------------------------------------------------- | 649 //------------------------------------------------------------------------- |
| 746 // Compile wrappers to imported functions. | |
| 747 //------------------------------------------------------------------------- | |
| 748 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, | |
| 749 &thrower, factory, &module_env, | |
| 750 code_stats)) { | |
| 751 return MaybeHandle<JSObject>(); | |
| 752 } | |
| 753 //------------------------------------------------------------------------- | |
| 754 // Compile all functions in the module. | 650 // Compile all functions in the module. |
| 755 //------------------------------------------------------------------------- | 651 //------------------------------------------------------------------------- |
| 756 { | 652 { |
| 757 isolate->counters()->wasm_functions_per_module()->AddSample( | 653 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 758 static_cast<int>(functions.size())); | 654 static_cast<int>(functions.size())); |
| 759 if (FLAG_wasm_num_compilation_tasks != 0) { | 655 if (FLAG_wasm_num_compilation_tasks != 0) { |
| 760 CompileInParallel(isolate, this, instance.function_code, &thrower, | 656 CompileInParallel(isolate, this, instance.function_code, &thrower, |
| 761 &module_env); | 657 &module_env); |
| 762 } else { | 658 } else { |
| 763 // 5) The main thread finishes the compilation. | 659 // 5) The main thread finishes the compilation. |
| 764 CompileSequentially(isolate, this, instance.function_code, &thrower, | 660 CompileSequentially(isolate, this, instance.function_code, &thrower, |
| 765 &module_env); | 661 &module_env); |
| 766 } | 662 } |
| 767 if (thrower.error()) { | 663 if (thrower.error()) { |
| 768 return Handle<JSObject>::null(); | 664 return Handle<JSObject>::null(); |
| 769 } | 665 } |
| 770 | 666 |
| 771 // At this point, compilation has completed. Update the code table | 667 // At this point, compilation has completed. Update the code table |
| 772 // and record sizes. | 668 // and record sizes. |
| 773 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 669 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
| 774 i < instance.function_code.size(); ++i) { | 670 i < instance.function_code.size(); ++i) { |
| 775 Code* code = *instance.function_code[i]; | 671 Code* code = *instance.function_code[i]; |
| 776 code_table->set(static_cast<int>(i), code); | 672 code_table->set(static_cast<int>(i), code); |
| 777 code_stats.Record(code); | 673 code_stats.Record(code); |
| 778 } | 674 } |
| 779 | 675 |
| 780 // Patch all direct call sites. | 676 // Patch all direct call sites. |
| 781 linker.Link(instance.function_table, this->function_table); | 677 compiler::Link(isolate, instance.function_code, instance.function_code, |
| 678 RelocInfo::kWasmDirectCallMask); |
| 679 //------------------------------------------------------------------------- |
| 680 // Compile wrappers to imported functions. |
| 681 //------------------------------------------------------------------------- |
| 682 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, |
| 683 &thrower, factory, &module_env, |
| 684 code_stats)) { |
| 685 return MaybeHandle<JSObject>(); |
| 686 } |
| 687 |
| 688 compiler::Link(isolate, instance.function_code, instance.import_code, |
| 689 RelocInfo::kWasmImportCallMask); |
| 690 |
| 691 instance.PopulateExportTable(instance.function_code, function_table); |
| 692 |
| 782 instance.js_object->SetInternalField(kWasmModuleFunctionTable, | 693 instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
| 783 Smi::FromInt(0)); | 694 Smi::FromInt(0)); |
| 784 | 695 |
| 785 SetDeoptimizationData(factory, instance.js_object, instance.function_code); | 696 SetDeoptimizationData(factory, instance.js_object, instance.function_code); |
| 786 | 697 |
| 787 //------------------------------------------------------------------------- | 698 //------------------------------------------------------------------------- |
| 788 // Create and populate the exports object. | 699 // Create and populate the exports object. |
| 789 //------------------------------------------------------------------------- | 700 //------------------------------------------------------------------------- |
| 790 if (export_table.size() > 0 || mem_export) { | 701 if (export_table.size() > 0 || mem_export) { |
| 791 Handle<JSObject> exports_object; | 702 Handle<JSObject> exports_object; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 MaybeHandle<Object> retval = | 769 MaybeHandle<Object> retval = |
| 859 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); | 770 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
| 860 | 771 |
| 861 if (retval.is_null()) { | 772 if (retval.is_null()) { |
| 862 thrower.Error("WASM.instantiateModule(): start function failed"); | 773 thrower.Error("WASM.instantiateModule(): start function failed"); |
| 863 } | 774 } |
| 864 } | 775 } |
| 865 return instance.js_object; | 776 return instance.js_object; |
| 866 } | 777 } |
| 867 | 778 |
| 868 Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const { | 779 void WasmModuleInstance::PopulateExportTable( |
| 869 DCHECK(IsValidFunction(index)); | 780 const std::vector<Handle<Code>>& compiled_functions, |
| 870 if (linker != nullptr) return linker->GetPlaceholderCode(index); | 781 const std::vector<uint16_t>& functions) { |
| 871 DCHECK_NOT_NULL(instance); | 782 if (!function_table.is_null()) { |
| 872 return instance->function_code[index]; | 783 int table_size = static_cast<int>(functions.size()); |
| 873 } | 784 DCHECK_EQ(function_table->length(), table_size * 2); |
| 874 | 785 for (int i = 0; i < table_size; i++) { |
| 875 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { | 786 function_table->set(i + table_size, *(compiled_functions[functions[i]])); |
| 876 DCHECK(IsValidImport(index)); | 787 } |
| 877 return instance ? instance->import_code[index] : Handle<Code>::null(); | 788 } |
| 878 } | |
| 879 | |
| 880 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, | |
| 881 uint32_t index) { | |
| 882 DCHECK(IsValidFunction(index)); | |
| 883 // Always make a direct call to whatever is in the table at that location. | |
| 884 // A wrapper will be generated for FFI calls. | |
| 885 const WasmFunction* function = &module->functions[index]; | |
| 886 return GetWasmCallDescriptor(zone, function->sig); | |
| 887 } | 789 } |
| 888 | 790 |
| 889 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, | 791 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, |
| 890 const byte* module_end, bool asm_js) { | 792 const byte* module_end, bool asm_js) { |
| 891 HandleScope scope(isolate); | 793 HandleScope scope(isolate); |
| 892 Zone zone(isolate->allocator()); | 794 Zone zone(isolate->allocator()); |
| 893 // Decode the module, but don't verify function bodies, since we'll | 795 // Decode the module, but don't verify function bodies, since we'll |
| 894 // be compiling them anyway. | 796 // be compiling them anyway. |
| 895 ModuleResult result = | 797 ModuleResult result = |
| 896 DecodeWasmModule(isolate, &zone, module_start, module_end, false, | 798 DecodeWasmModule(isolate, &zone, module_start, module_end, false, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 924 | 826 |
| 925 // Allocate the globals area if necessary. | 827 // Allocate the globals area if necessary. |
| 926 if (!AllocateGlobals(&thrower, isolate, &instance)) { | 828 if (!AllocateGlobals(&thrower, isolate, &instance)) { |
| 927 return -1; | 829 return -1; |
| 928 } | 830 } |
| 929 | 831 |
| 930 // Build the function table. | 832 // Build the function table. |
| 931 instance.function_table = BuildFunctionTable(isolate, module); | 833 instance.function_table = BuildFunctionTable(isolate, module); |
| 932 | 834 |
| 933 // Create module environment. | 835 // Create module environment. |
| 934 WasmLinker linker(isolate, &instance.function_code); | |
| 935 ModuleEnv module_env; | 836 ModuleEnv module_env; |
| 936 module_env.module = module; | 837 module_env.module = module; |
| 937 module_env.instance = &instance; | 838 module_env.instance = &instance; |
| 938 module_env.linker = &linker; | |
| 939 module_env.origin = module->origin; | 839 module_env.origin = module->origin; |
| 940 | 840 |
| 941 if (module->export_table.size() == 0) { | 841 if (module->export_table.size() == 0) { |
| 942 thrower.Error("WASM.compileRun() failed: no exported functions"); | 842 thrower.Error("WASM.compileRun() failed: no exported functions"); |
| 943 return -2; | 843 return -2; |
| 944 } | 844 } |
| 945 | 845 |
| 946 // Compile all functions. | 846 // Compile all functions. |
| 947 for (const WasmFunction& func : module->functions) { | 847 for (const WasmFunction& func : module->functions) { |
| 948 // Compile the function and install it in the linker. | 848 // Compile the function and install it in the linker. |
| 949 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( | 849 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( |
| 950 &thrower, isolate, &module_env, &func); | 850 &thrower, isolate, &module_env, &func); |
| 951 if (!code.is_null()) linker.Finish(func.func_index, code); | 851 if (!code.is_null()) instance.function_code[func.func_index] = code; |
| 952 if (thrower.error()) return -1; | 852 if (thrower.error()) return -1; |
| 953 } | 853 } |
| 954 | 854 |
| 955 linker.Link(instance.function_table, instance.module->function_table); | 855 compiler::Link(isolate, instance.function_code, instance.function_code, |
| 856 RelocInfo::kWasmDirectCallMask); |
| 857 instance.PopulateExportTable(instance.function_code, |
| 858 instance.module->function_table); |
| 956 | 859 |
| 957 // Wrap the main code so it can be called as a JS function. | 860 // Wrap the main code so it can be called as a JS function. |
| 958 uint32_t main_index = module->export_table.back().func_index; | 861 uint32_t main_index = module->export_table.back().func_index; |
| 959 Handle<Code> main_code = instance.function_code[main_index]; | 862 Handle<Code> main_code = instance.function_code[main_index]; |
| 960 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); | 863 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); |
| 961 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); | 864 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); |
| 962 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( | 865 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
| 963 isolate, &module_env, name, main_code, module_object, main_index); | 866 isolate, &module_env, name, main_code, module_object, main_index); |
| 964 | 867 |
| 965 // Call the JS function. | 868 // Call the JS function. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && | 900 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && |
| 998 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && | 901 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && |
| 999 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && | 902 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && |
| 1000 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || | 903 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || |
| 1001 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); | 904 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); |
| 1002 } | 905 } |
| 1003 | 906 |
| 1004 } // namespace wasm | 907 } // namespace wasm |
| 1005 } // namespace internal | 908 } // namespace internal |
| 1006 } // namespace v8 | 909 } // namespace v8 |
| OLD | NEW |