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. | 650 // Compile wrappers to imported functions. |
747 //------------------------------------------------------------------------- | 651 //------------------------------------------------------------------------- |
748 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, | 652 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, |
749 &thrower, factory, &module_env, | 653 &thrower, factory, &module_env, |
750 code_stats)) { | 654 code_stats)) { |
751 return MaybeHandle<JSObject>(); | 655 return MaybeHandle<JSObject>(); |
752 } | 656 } |
(...skipping 18 matching lines...) Expand all Loading... |
771 // At this point, compilation has completed. Update the code table | 675 // At this point, compilation has completed. Update the code table |
772 // and record sizes. | 676 // and record sizes. |
773 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 677 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
774 i < instance.function_code.size(); ++i) { | 678 i < instance.function_code.size(); ++i) { |
775 Code* code = *instance.function_code[i]; | 679 Code* code = *instance.function_code[i]; |
776 code_table->set(static_cast<int>(i), code); | 680 code_table->set(static_cast<int>(i), code); |
777 code_stats.Record(code); | 681 code_stats.Record(code); |
778 } | 682 } |
779 | 683 |
780 // Patch all direct call sites. | 684 // Patch all direct call sites. |
781 linker.Link(instance.function_table, this->function_table); | 685 compiler::Link(isolate, instance.function_code); |
| 686 |
| 687 instance.PopulateExportTable(instance.function_code, function_table); |
| 688 |
782 instance.js_object->SetInternalField(kWasmModuleFunctionTable, | 689 instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
783 Smi::FromInt(0)); | 690 Smi::FromInt(0)); |
784 | 691 |
785 SetDeoptimizationData(factory, instance.js_object, instance.function_code); | 692 SetDeoptimizationData(factory, instance.js_object, instance.function_code); |
786 | 693 |
787 //------------------------------------------------------------------------- | 694 //------------------------------------------------------------------------- |
788 // Create and populate the exports object. | 695 // Create and populate the exports object. |
789 //------------------------------------------------------------------------- | 696 //------------------------------------------------------------------------- |
790 if (export_table.size() > 0 || mem_export) { | 697 if (export_table.size() > 0 || mem_export) { |
791 Handle<JSObject> exports_object; | 698 Handle<JSObject> exports_object; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 MaybeHandle<Object> retval = | 765 MaybeHandle<Object> retval = |
859 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); | 766 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
860 | 767 |
861 if (retval.is_null()) { | 768 if (retval.is_null()) { |
862 thrower.Error("WASM.instantiateModule(): start function failed"); | 769 thrower.Error("WASM.instantiateModule(): start function failed"); |
863 } | 770 } |
864 } | 771 } |
865 return instance.js_object; | 772 return instance.js_object; |
866 } | 773 } |
867 | 774 |
868 Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const { | 775 void WasmModuleInstance::PopulateExportTable( |
869 DCHECK(IsValidFunction(index)); | 776 const std::vector<Handle<Code>>& compiled_functions, |
870 if (linker != nullptr) return linker->GetPlaceholderCode(index); | 777 const std::vector<uint16_t>& functions) { |
871 DCHECK_NOT_NULL(instance); | 778 if (!function_table.is_null()) { |
872 return instance->function_code[index]; | 779 int table_size = static_cast<int>(functions.size()); |
| 780 DCHECK_EQ(function_table->length(), table_size * 2); |
| 781 for (int i = 0; i < table_size; i++) { |
| 782 function_table->set(i + table_size, *(compiled_functions[functions[i]])); |
| 783 } |
| 784 } |
873 } | 785 } |
874 | 786 |
875 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { | 787 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { |
876 DCHECK(IsValidImport(index)); | 788 DCHECK(IsValidImport(index)); |
877 return instance ? instance->import_code[index] : Handle<Code>::null(); | 789 return instance ? instance->import_code[index] : Handle<Code>::null(); |
878 } | 790 } |
879 | 791 |
880 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, | 792 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, |
881 uint32_t index) { | 793 uint32_t index) { |
882 DCHECK(IsValidFunction(index)); | 794 DCHECK(IsValidFunction(index)); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
924 | 836 |
925 // Allocate the globals area if necessary. | 837 // Allocate the globals area if necessary. |
926 if (!AllocateGlobals(&thrower, isolate, &instance)) { | 838 if (!AllocateGlobals(&thrower, isolate, &instance)) { |
927 return -1; | 839 return -1; |
928 } | 840 } |
929 | 841 |
930 // Build the function table. | 842 // Build the function table. |
931 instance.function_table = BuildFunctionTable(isolate, module); | 843 instance.function_table = BuildFunctionTable(isolate, module); |
932 | 844 |
933 // Create module environment. | 845 // Create module environment. |
934 WasmLinker linker(isolate, &instance.function_code); | |
935 ModuleEnv module_env; | 846 ModuleEnv module_env; |
936 module_env.module = module; | 847 module_env.module = module; |
937 module_env.instance = &instance; | 848 module_env.instance = &instance; |
938 module_env.linker = &linker; | |
939 module_env.origin = module->origin; | 849 module_env.origin = module->origin; |
940 | 850 |
941 if (module->export_table.size() == 0) { | 851 if (module->export_table.size() == 0) { |
942 thrower.Error("WASM.compileRun() failed: no exported functions"); | 852 thrower.Error("WASM.compileRun() failed: no exported functions"); |
943 return -2; | 853 return -2; |
944 } | 854 } |
945 | 855 |
946 // Compile all functions. | 856 // Compile all functions. |
947 for (const WasmFunction& func : module->functions) { | 857 for (const WasmFunction& func : module->functions) { |
948 // Compile the function and install it in the linker. | 858 // Compile the function and install it in the linker. |
949 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( | 859 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( |
950 &thrower, isolate, &module_env, &func); | 860 &thrower, isolate, &module_env, &func); |
951 if (!code.is_null()) linker.Finish(func.func_index, code); | 861 if (!code.is_null()) instance.function_code[func.func_index] = code; |
952 if (thrower.error()) return -1; | 862 if (thrower.error()) return -1; |
953 } | 863 } |
954 | 864 |
955 linker.Link(instance.function_table, instance.module->function_table); | 865 compiler::Link(isolate, instance.function_code); |
| 866 instance.PopulateExportTable(instance.function_code, |
| 867 instance.module->function_table); |
956 | 868 |
957 // Wrap the main code so it can be called as a JS function. | 869 // Wrap the main code so it can be called as a JS function. |
958 uint32_t main_index = module->export_table.back().func_index; | 870 uint32_t main_index = module->export_table.back().func_index; |
959 Handle<Code> main_code = instance.function_code[main_index]; | 871 Handle<Code> main_code = instance.function_code[main_index]; |
960 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); | 872 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); |
961 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); | 873 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); |
962 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( | 874 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
963 isolate, &module_env, name, main_code, module_object, main_index); | 875 isolate, &module_env, name, main_code, module_object, main_index); |
964 | 876 |
965 // Call the JS function. | 877 // Call the JS function. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && | 909 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && |
998 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && | 910 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && |
999 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && | 911 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && |
1000 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || | 912 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || |
1001 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); | 913 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); |
1002 } | 914 } |
1003 | 915 |
1004 } // namespace wasm | 916 } // namespace wasm |
1005 } // namespace internal | 917 } // namespace internal |
1006 } // namespace v8 | 918 } // namespace v8 |
OLD | NEW |