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 |