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 |
25 static const char* wasmSections[] = { | 27 static const char* wasmSections[] = { |
26 #define F(enumerator, order, string) string, | 28 #define F(enumerator, order, string) string, |
27 FOR_EACH_WASM_SECTION_TYPE(F) | 29 FOR_EACH_WASM_SECTION_TYPE(F) |
28 #undef F | 30 #undef F |
29 "<unknown>" // entry for "Max" | 31 "<unknown>" // entry for "Max" |
30 }; | 32 }; |
31 | 33 |
32 static uint8_t wasmSectionsLengths[]{ | 34 static uint8_t wasmSectionsLengths[]{ |
33 #define F(enumerator, order, string) sizeof(string) - 1, | 35 #define F(enumerator, order, string) sizeof(string) - 1, |
34 FOR_EACH_WASM_SECTION_TYPE(F) | 36 FOR_EACH_WASM_SECTION_TYPE(F) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 } else { | 108 } else { |
107 os << "?"; | 109 os << "?"; |
108 } | 110 } |
109 return os; | 111 return os; |
110 } | 112 } |
111 | 113 |
112 // A helper class for compiling multiple wasm functions that offers | 114 // A helper class for compiling multiple wasm functions that offers |
113 // placeholder code objects for calling functions that are not yet compiled. | 115 // placeholder code objects for calling functions that are not yet compiled. |
114 class WasmLinker { | 116 class WasmLinker { |
115 public: | 117 public: |
116 WasmLinker(Isolate* isolate, size_t size) | 118 WasmLinker(Isolate* isolate, std::vector<Handle<Code>>* functions) |
117 : isolate_(isolate), placeholder_code_(size), function_code_(size) {} | 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 } |
118 | 126 |
119 // Get the code object for a function, allocating a placeholder if it has | 127 Handle<Code> GetPlaceholderCode(uint32_t index) const { |
120 // not yet been compiled. | 128 return placeholder_code_[index]; |
121 Handle<Code> GetFunctionCode(uint32_t index) { | |
122 DCHECK(index < function_code_.size()); | |
123 if (function_code_[index].is_null()) { | |
124 // Create a placeholder code object and encode the corresponding index in | |
125 // the {constant_pool_offset} field of the code object. | |
126 // TODO(titzer): placeholder code objects are somewhat dangerous. | |
127 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. | |
128 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; | |
129 Handle<Code> code = isolate_->factory()->NewCode( | |
130 desc, Code::KindField::encode(Code::WASM_FUNCTION), | |
131 Handle<Object>::null()); | |
132 code->set_constant_pool_offset(index + kPlaceholderMarker); | |
133 placeholder_code_[index] = code; | |
134 function_code_[index] = code; | |
135 } | |
136 return function_code_[index]; | |
137 } | 129 } |
138 | 130 |
139 void Finish(uint32_t index, Handle<Code> code) { | 131 void Finish(uint32_t index, Handle<Code> code) { |
140 DCHECK(index < function_code_.size()); | 132 DCHECK(index < function_code().size()); |
141 function_code_[index] = code; | 133 function_code()[index] = code; |
142 } | 134 } |
143 | 135 |
144 void Link(Handle<FixedArray> function_table, | 136 void Link(Handle<FixedArray> function_table, |
145 const std::vector<uint16_t>& functions) { | 137 const std::vector<uint16_t>& functions) { |
146 for (size_t i = 0; i < function_code_.size(); i++) { | 138 for (size_t i = 0; i < function_code().size(); i++) { |
147 LinkFunction(function_code_[i]); | 139 LinkFunction(function_code()[i]); |
148 } | 140 } |
149 if (!function_table.is_null()) { | 141 if (!function_table.is_null()) { |
150 int table_size = static_cast<int>(functions.size()); | 142 int table_size = static_cast<int>(functions.size()); |
151 DCHECK_EQ(function_table->length(), table_size * 2); | 143 DCHECK_EQ(function_table->length(), table_size * 2); |
152 for (int i = 0; i < table_size; i++) { | 144 for (int i = 0; i < table_size; i++) { |
153 function_table->set(i + table_size, *function_code_[functions[i]]); | 145 function_table->set(i + table_size, *function_code()[functions[i]]); |
154 } | 146 } |
155 } | 147 } |
156 } | 148 } |
157 | 149 |
158 private: | 150 private: |
159 static const int kPlaceholderMarker = 1000000000; | 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 } |
160 | 169 |
161 Isolate* isolate_; | 170 Isolate* isolate_; |
162 std::vector<Handle<Code>> placeholder_code_; | 171 std::vector<Handle<Code>> placeholder_code_; |
163 std::vector<Handle<Code>> function_code_; | 172 std::vector<Handle<Code>>* function_code_; |
164 | 173 |
165 void LinkFunction(Handle<Code> code) { | 174 void LinkFunction(Handle<Code> code) { |
166 bool modified = false; | 175 bool modified = false; |
167 int mode_mask = RelocInfo::kCodeTargetMask; | 176 int mode_mask = RelocInfo::kCodeTargetMask; |
168 AllowDeferredHandleDereference embedding_raw_address; | 177 AllowDeferredHandleDereference embedding_raw_address; |
169 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { | 178 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
170 RelocInfo::Mode mode = it.rinfo()->rmode(); | 179 RelocInfo::Mode mode = it.rinfo()->rmode(); |
171 if (RelocInfo::IsCodeTarget(mode)) { | 180 if (RelocInfo::IsCodeTarget(mode)) { |
172 Code* target = | 181 Code* target = |
173 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 182 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
174 if (target->kind() == Code::WASM_FUNCTION && | 183 if (target->kind() == Code::WASM_FUNCTION && |
175 target->constant_pool_offset() >= kPlaceholderMarker) { | 184 target->constant_pool_offset() >= kPlaceholderMarker) { |
176 // Patch direct calls to placeholder code objects. | 185 // Patch direct calls to placeholder code objects. |
177 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; | 186 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
178 CHECK(index < function_code_.size()); | 187 CHECK(index < function_code().size()); |
179 Handle<Code> new_target = function_code_[index]; | 188 Handle<Code> new_target = function_code()[index]; |
180 if (target != *new_target) { | 189 if (target != *new_target) { |
181 CHECK_EQ(*placeholder_code_[index], target); | 190 CHECK_EQ(*placeholder_code_[index], target); |
182 it.rinfo()->set_target_address(new_target->instruction_start(), | 191 it.rinfo()->set_target_address(new_target->instruction_start(), |
183 SKIP_WRITE_BARRIER, | 192 SKIP_WRITE_BARRIER, |
184 SKIP_ICACHE_FLUSH); | 193 SKIP_ICACHE_FLUSH); |
185 modified = true; | 194 modified = true; |
186 } | 195 } |
187 } | 196 } |
188 } | 197 } |
189 } | 198 } |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 index++; | 496 index++; |
488 } | 497 } |
489 } | 498 } |
490 return true; | 499 return true; |
491 } | 500 } |
492 | 501 |
493 void InitializeParallelCompilation( | 502 void InitializeParallelCompilation( |
494 Isolate* isolate, const std::vector<WasmFunction>& functions, | 503 Isolate* isolate, const std::vector<WasmFunction>& functions, |
495 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 504 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
496 ModuleEnv& module_env, ErrorThrower& thrower) { | 505 ModuleEnv& module_env, ErrorThrower& thrower) { |
497 // Create a placeholder code object for all functions. | |
498 // TODO(ahaas): Maybe we could skip this for external functions. | |
499 for (uint32_t i = 0; i < functions.size(); i++) { | |
500 module_env.linker->GetFunctionCode(i); | |
501 } | |
502 | |
503 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) { | 506 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) { |
504 compilation_units[i] = new compiler::WasmCompilationUnit( | 507 compilation_units[i] = new compiler::WasmCompilationUnit( |
505 &thrower, isolate, &module_env, &functions[i], i); | 508 &thrower, isolate, &module_env, &functions[i], i); |
506 } | 509 } |
507 } | 510 } |
508 | 511 |
509 uint32_t* StartCompilationTasks( | 512 uint32_t* StartCompilationTasks( |
510 Isolate* isolate, | 513 Isolate* isolate, |
511 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 514 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
512 std::queue<compiler::WasmCompilationUnit*>& executed_units, | 515 std::queue<compiler::WasmCompilationUnit*>& executed_units, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 } | 557 } |
555 unit = executed_units.front(); | 558 unit = executed_units.front(); |
556 executed_units.pop(); | 559 executed_units.pop(); |
557 } | 560 } |
558 int j = unit->index(); | 561 int j = unit->index(); |
559 results[j] = unit->FinishCompilation(); | 562 results[j] = unit->FinishCompilation(); |
560 delete unit; | 563 delete unit; |
561 } | 564 } |
562 } | 565 } |
563 | 566 |
564 bool FinishCompilation(Isolate* isolate, const WasmModule* module, | 567 void CompileInParallel(Isolate* isolate, const WasmModule* module, |
565 const Handle<JSReceiver> ffi, | 568 std::vector<Handle<Code>>& functions, |
566 const std::vector<Handle<Code>>& results, | 569 ErrorThrower* thrower, ModuleEnv* module_env) { |
567 const WasmModuleInstance& instance, | 570 // Data structures for the parallel compilation. |
568 const Handle<FixedArray>& code_table, | 571 std::vector<compiler::WasmCompilationUnit*> compilation_units( |
569 ErrorThrower& thrower, Factory* factory, | 572 module->functions.size()); |
570 ModuleEnv& module_env, CodeStats& code_stats, | 573 std::queue<compiler::WasmCompilationUnit*> executed_units; |
571 PropertyDescriptor& desc) { | 574 |
572 if (thrower.error()) return false; | 575 //----------------------------------------------------------------------- |
| 576 // For parallel compilation: |
| 577 // 1) The main thread allocates a compilation unit for each wasm function |
| 578 // and stores them in the vector {compilation_units}. |
| 579 // 2) The main thread spawns {WasmCompilationTask} instances which run on |
| 580 // the background threads. |
| 581 // 3.a) The background threads and the main thread pick one compilation |
| 582 // unit at a time and execute the parallel phase of the compilation |
| 583 // unit. After finishing the execution of the parallel phase, the |
| 584 // result is enqueued in {executed_units}. |
| 585 // 3.b) If {executed_units} contains a compilation unit, the main thread |
| 586 // dequeues it and finishes the compilation. |
| 587 // 4) After the parallel phase of all compilation units has started, the |
| 588 // main thread waits for all {WasmCompilationTask} instances to finish. |
| 589 // 5) The main thread finishes the compilation. |
| 590 |
| 591 // Turn on the {CanonicalHandleScope} so that the background threads can |
| 592 // use the node cache. |
| 593 CanonicalHandleScope canonical(isolate); |
| 594 |
| 595 // 1) The main thread allocates a compilation unit for each wasm function |
| 596 // and stores them in the vector {compilation_units}. |
| 597 InitializeParallelCompilation(isolate, module->functions, compilation_units, |
| 598 *module_env, *thrower); |
| 599 |
| 600 // Objects for the synchronization with the background threads. |
| 601 base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0)); |
| 602 base::Mutex result_mutex; |
| 603 base::AtomicNumber<size_t> next_unit( |
| 604 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs)); |
| 605 |
| 606 // 2) The main thread spawns {WasmCompilationTask} instances which run on |
| 607 // the background threads. |
| 608 base::SmartArrayPointer<uint32_t> task_ids( |
| 609 StartCompilationTasks(isolate, compilation_units, executed_units, |
| 610 pending_tasks, result_mutex, next_unit)); |
| 611 |
| 612 // 3.a) The background threads and the main thread pick one compilation |
| 613 // unit at a time and execute the parallel phase of the compilation |
| 614 // unit. After finishing the execution of the parallel phase, the |
| 615 // result is enqueued in {executed_units}. |
| 616 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units, |
| 617 &executed_units, &result_mutex, |
| 618 &next_unit)) { |
| 619 // 3.b) If {executed_units} contains a compilation unit, the main thread |
| 620 // dequeues it and finishes the compilation unit. Compilation units |
| 621 // are finished concurrently to the background threads to save |
| 622 // memory. |
| 623 FinishCompilationUnits(executed_units, functions, result_mutex); |
| 624 } |
| 625 // 4) After the parallel phase of all compilation units has started, the |
| 626 // main thread waits for all {WasmCompilationTask} instances to finish. |
| 627 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); |
| 628 // Finish the compilation of the remaining compilation units. |
| 629 FinishCompilationUnits(executed_units, functions, result_mutex); |
| 630 } |
| 631 |
| 632 void CompileSequentially(Isolate* isolate, const WasmModule* module, |
| 633 std::vector<Handle<Code>>& functions, |
| 634 ErrorThrower* thrower, ModuleEnv* module_env) { |
| 635 DCHECK(!thrower->error()); |
| 636 |
573 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; | 637 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; |
574 i < module->functions.size(); i++) { | 638 i < module->functions.size(); i++) { |
575 const WasmFunction& func = module->functions[i]; | 639 const WasmFunction& func = module->functions[i]; |
576 | 640 |
577 DCHECK_EQ(i, func.func_index); | 641 DCHECK_EQ(i, func.func_index); |
578 WasmName str = module->GetName(func.name_offset, func.name_length); | 642 WasmName str = module->GetName(func.name_offset, func.name_length); |
579 Handle<Code> code = Handle<Code>::null(); | 643 Handle<Code> code = Handle<Code>::null(); |
580 if (FLAG_wasm_num_compilation_tasks != 0) { | 644 // Compile the function. |
581 code = results[i]; | 645 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
582 } else { | 646 thrower, isolate, module_env, &func); |
583 // Compile the function. | 647 if (code.is_null()) { |
584 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 648 thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(), |
585 &thrower, isolate, &module_env, &func); | 649 str.start()); |
| 650 break; |
586 } | 651 } |
587 if (code.is_null()) { | |
588 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(), | |
589 str.start()); | |
590 return false; | |
591 } | |
592 if (!code.is_null()) { | |
593 // Install the code into the linker table. | 652 // Install the code into the linker table. |
594 module_env.linker->Finish(i, code); | 653 functions[i] = code; |
595 code_table->set(i, *code); | |
596 code_stats.Record(*code); | |
597 } | |
598 } | 654 } |
599 return true; | |
600 } | 655 } |
601 } // namespace | 656 } // namespace |
602 | 657 |
| 658 void SetDeoptimizationData(Factory* factory, Handle<JSObject> js_object, |
| 659 std::vector<Handle<Code>>& functions) { |
| 660 for (size_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { |
| 661 Handle<Code> code = functions[i]; |
| 662 DCHECK(code->deoptimization_data() == nullptr || |
| 663 code->deoptimization_data()->length() == 0); |
| 664 Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED); |
| 665 if (!js_object.is_null()) { |
| 666 deopt_data->set(0, *js_object); |
| 667 } |
| 668 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); |
| 669 deopt_data->set_length(2); |
| 670 code->set_deoptimization_data(*deopt_data); |
| 671 } |
| 672 } |
| 673 |
603 // Instantiates a wasm module as a JSObject. | 674 // Instantiates a wasm module as a JSObject. |
604 // * allocates a backing store of {mem_size} bytes. | 675 // * allocates a backing store of {mem_size} bytes. |
605 // * installs a named property "memory" for that buffer if exported | 676 // * installs a named property "memory" for that buffer if exported |
606 // * installs named properties on the object for exported functions | 677 // * installs named properties on the object for exported functions |
607 // * compiles wasm code to machine code | 678 // * compiles wasm code to machine code |
608 MaybeHandle<JSObject> WasmModule::Instantiate( | 679 MaybeHandle<JSObject> WasmModule::Instantiate( |
609 Isolate* isolate, Handle<JSReceiver> ffi, | 680 Isolate* isolate, Handle<JSReceiver> ffi, |
610 Handle<JSArrayBuffer> memory) const { | 681 Handle<JSArrayBuffer> memory) const { |
611 HistogramTimerScope wasm_instantiate_module_time_scope( | 682 HistogramTimerScope wasm_instantiate_module_time_scope( |
612 isolate->counters()->wasm_instantiate_module_time()); | 683 isolate->counters()->wasm_instantiate_module_time()); |
613 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 684 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
614 Factory* factory = isolate->factory(); | 685 Factory* factory = isolate->factory(); |
615 | 686 |
616 PropertyDescriptor desc; | |
617 desc.set_writable(false); | |
618 | |
619 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code | 687 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code |
620 // objects created for this module. | 688 // objects created for this module. |
621 // TODO(titzer): switch this to TRACE_EVENT | 689 // TODO(titzer): switch this to TRACE_EVENT |
622 CodeStats code_stats; | 690 CodeStats code_stats; |
623 | 691 |
624 //------------------------------------------------------------------------- | 692 //------------------------------------------------------------------------- |
625 // Allocate the instance and its JS counterpart. | 693 // Allocate the instance and its JS counterpart. |
626 //------------------------------------------------------------------------- | 694 //------------------------------------------------------------------------- |
627 Handle<Map> map = factory->NewMap( | 695 Handle<Map> map = factory->NewMap( |
628 JS_OBJECT_TYPE, | 696 JS_OBJECT_TYPE, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 } | 728 } |
661 if (!instance.globals_buffer.is_null()) { | 729 if (!instance.globals_buffer.is_null()) { |
662 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, | 730 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, |
663 *instance.globals_buffer); | 731 *instance.globals_buffer); |
664 } | 732 } |
665 | 733 |
666 HistogramTimerScope wasm_compile_module_time_scope( | 734 HistogramTimerScope wasm_compile_module_time_scope( |
667 isolate->counters()->wasm_compile_module_time()); | 735 isolate->counters()->wasm_compile_module_time()); |
668 | 736 |
669 instance.function_table = BuildFunctionTable(isolate, this); | 737 instance.function_table = BuildFunctionTable(isolate, this); |
670 WasmLinker linker(isolate, functions.size()); | 738 WasmLinker linker(isolate, &instance.function_code); |
671 ModuleEnv module_env; | 739 ModuleEnv module_env; |
672 module_env.module = this; | 740 module_env.module = this; |
673 module_env.instance = &instance; | 741 module_env.instance = &instance; |
674 module_env.linker = &linker; | 742 module_env.linker = &linker; |
675 module_env.origin = origin; | 743 module_env.origin = origin; |
676 | 744 |
677 //------------------------------------------------------------------------- | 745 //------------------------------------------------------------------------- |
678 // Compile wrappers to imported functions. | 746 // Compile wrappers to imported functions. |
679 //------------------------------------------------------------------------- | 747 //------------------------------------------------------------------------- |
680 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, | 748 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, |
681 &thrower, factory, &module_env, | 749 &thrower, factory, &module_env, |
682 code_stats)) { | 750 code_stats)) { |
683 return MaybeHandle<JSObject>(); | 751 return MaybeHandle<JSObject>(); |
684 } | 752 } |
685 //------------------------------------------------------------------------- | 753 //------------------------------------------------------------------------- |
686 // Compile all functions in the module. | 754 // Compile all functions in the module. |
687 //------------------------------------------------------------------------- | 755 //------------------------------------------------------------------------- |
688 { | 756 { |
689 isolate->counters()->wasm_functions_per_module()->AddSample( | 757 isolate->counters()->wasm_functions_per_module()->AddSample( |
690 static_cast<int>(functions.size())); | 758 static_cast<int>(functions.size())); |
| 759 if (FLAG_wasm_num_compilation_tasks != 0) { |
| 760 CompileInParallel(isolate, this, instance.function_code, &thrower, |
| 761 &module_env); |
| 762 } else { |
| 763 // 5) The main thread finishes the compilation. |
| 764 CompileSequentially(isolate, this, instance.function_code, &thrower, |
| 765 &module_env); |
| 766 } |
| 767 if (thrower.error()) { |
| 768 return Handle<JSObject>::null(); |
| 769 } |
691 | 770 |
692 // Data structures for the parallel compilation. | 771 // At this point, compilation has completed. Update the code table |
693 std::vector<compiler::WasmCompilationUnit*> compilation_units( | 772 // and record sizes. |
694 functions.size()); | 773 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
695 std::queue<compiler::WasmCompilationUnit*> executed_units; | 774 i < instance.function_code.size(); ++i) { |
696 std::vector<Handle<Code>> results(functions.size()); | 775 Code* code = *instance.function_code[i]; |
697 | 776 code_table->set(static_cast<int>(i), code); |
698 if (FLAG_wasm_num_compilation_tasks != 0) { | 777 code_stats.Record(code); |
699 //----------------------------------------------------------------------- | |
700 // For parallel compilation: | |
701 // 1) The main thread allocates a compilation unit for each wasm function | |
702 // and stores them in the vector {compilation_units}. | |
703 // 2) The main thread spawns {WasmCompilationTask} instances which run on | |
704 // the background threads. | |
705 // 3.a) The background threads and the main thread pick one compilation | |
706 // unit at a time and execute the parallel phase of the compilation | |
707 // unit. After finishing the execution of the parallel phase, the | |
708 // result is enqueued in {executed_units}. | |
709 // 3.b) If {executed_units} contains a compilation unit, the main thread | |
710 // dequeues it and finishes the compilation. | |
711 // 4) After the parallel phase of all compilation units has started, the | |
712 // main thread waits for all {WasmCompilationTask} instances to finish. | |
713 // 5) The main thread finishes the compilation. | |
714 | |
715 // Turn on the {CanonicalHandleScope} so that the background threads can | |
716 // use the node cache. | |
717 CanonicalHandleScope canonical(isolate); | |
718 | |
719 // 1) The main thread allocates a compilation unit for each wasm function | |
720 // and stores them in the vector {compilation_units}. | |
721 InitializeParallelCompilation(isolate, functions, compilation_units, | |
722 module_env, thrower); | |
723 | |
724 // Objects for the synchronization with the background threads. | |
725 base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0)); | |
726 base::Mutex result_mutex; | |
727 base::AtomicNumber<size_t> next_unit( | |
728 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs)); | |
729 | |
730 // 2) The main thread spawns {WasmCompilationTask} instances which run on | |
731 // the background threads. | |
732 base::SmartArrayPointer<uint32_t> task_ids( | |
733 StartCompilationTasks(isolate, compilation_units, executed_units, | |
734 pending_tasks, result_mutex, next_unit)); | |
735 | |
736 // 3.a) The background threads and the main thread pick one compilation | |
737 // unit at a time and execute the parallel phase of the compilation | |
738 // unit. After finishing the execution of the parallel phase, the | |
739 // result is enqueued in {executed_units}. | |
740 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units, | |
741 &executed_units, &result_mutex, | |
742 &next_unit)) { | |
743 // 3.b) If {executed_units} contains a compilation unit, the main thread | |
744 // dequeues it and finishes the compilation unit. Compilation units | |
745 // are finished concurrently to the background threads to save | |
746 // memory. | |
747 FinishCompilationUnits(executed_units, results, result_mutex); | |
748 } | |
749 // 4) After the parallel phase of all compilation units has started, the | |
750 // main thread waits for all {WasmCompilationTask} instances to finish. | |
751 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); | |
752 // Finish the compilation of the remaining compilation units. | |
753 FinishCompilationUnits(executed_units, results, result_mutex); | |
754 } | |
755 // 5) The main thread finishes the compilation. | |
756 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table, | |
757 thrower, factory, module_env, code_stats, desc)) { | |
758 instance.js_object = Handle<JSObject>::null(); | |
759 return instance.js_object; | |
760 } | 778 } |
761 | 779 |
762 // Patch all direct call sites. | 780 // Patch all direct call sites. |
763 linker.Link(instance.function_table, this->function_table); | 781 linker.Link(instance.function_table, this->function_table); |
764 instance.js_object->SetInternalField(kWasmModuleFunctionTable, | 782 instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
765 Smi::FromInt(0)); | 783 Smi::FromInt(0)); |
766 | 784 |
| 785 SetDeoptimizationData(factory, instance.js_object, instance.function_code); |
| 786 |
767 //------------------------------------------------------------------------- | 787 //------------------------------------------------------------------------- |
768 // Create and populate the exports object. | 788 // Create and populate the exports object. |
769 //------------------------------------------------------------------------- | 789 //------------------------------------------------------------------------- |
770 if (export_table.size() > 0 || mem_export) { | 790 if (export_table.size() > 0 || mem_export) { |
771 Handle<JSObject> exports_object; | 791 Handle<JSObject> exports_object; |
772 if (origin == kWasmOrigin) { | 792 if (origin == kWasmOrigin) { |
773 // Create the "exports" object. | 793 // Create the "exports" object. |
774 Handle<JSFunction> object_function = Handle<JSFunction>( | 794 Handle<JSFunction> object_function = Handle<JSFunction>( |
775 isolate->native_context()->object_function(), isolate); | 795 isolate->native_context()->object_function(), isolate); |
776 exports_object = factory->NewJSObject(object_function, TENURED); | 796 exports_object = factory->NewJSObject(object_function, TENURED); |
777 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | 797 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); |
778 JSObject::AddProperty(instance.js_object, exports_name, exports_object, | 798 JSObject::AddProperty(instance.js_object, exports_name, exports_object, |
779 READ_ONLY); | 799 READ_ONLY); |
780 } else { | 800 } else { |
781 // Just export the functions directly on the object returned. | 801 // Just export the functions directly on the object returned. |
782 exports_object = instance.js_object; | 802 exports_object = instance.js_object; |
783 } | 803 } |
784 | 804 |
| 805 PropertyDescriptor desc; |
| 806 desc.set_writable(false); |
| 807 |
785 // Compile wrappers and add them to the exports object. | 808 // Compile wrappers and add them to the exports object. |
786 for (const WasmExport& exp : export_table) { | 809 for (const WasmExport& exp : export_table) { |
787 if (thrower.error()) break; | 810 if (thrower.error()) break; |
788 WasmName str = GetName(exp.name_offset, exp.name_length); | 811 WasmName str = GetName(exp.name_offset, exp.name_length); |
789 Handle<String> name = factory->InternalizeUtf8String(str); | 812 Handle<String> name = factory->InternalizeUtf8String(str); |
790 Handle<Code> code = linker.GetFunctionCode(exp.func_index); | 813 Handle<Code> code = instance.function_code[exp.func_index]; |
791 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( | 814 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( |
792 isolate, &module_env, name, code, instance.js_object, | 815 isolate, &module_env, name, code, instance.js_object, |
793 exp.func_index); | 816 exp.func_index); |
794 code_stats.Record(function->code()); | 817 code_stats.Record(function->code()); |
795 desc.set_value(function); | 818 desc.set_value(function); |
796 Maybe<bool> status = JSReceiver::DefineOwnProperty( | 819 Maybe<bool> status = JSReceiver::DefineOwnProperty( |
797 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | 820 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); |
798 if (!status.IsJust()) { | 821 if (!status.IsJust()) { |
799 thrower.Error("export of %.*s failed.", str.length(), str.start()); | 822 thrower.Error("export of %.*s failed.", str.length(), str.start()); |
800 break; | 823 break; |
(...skipping 18 matching lines...) Expand all Loading... |
819 instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr); | 842 instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr); |
820 } | 843 } |
821 | 844 |
822 code_stats.Report(); | 845 code_stats.Report(); |
823 | 846 |
824 // Run the start function if one was specified. | 847 // Run the start function if one was specified. |
825 if (this->start_function_index >= 0) { | 848 if (this->start_function_index >= 0) { |
826 HandleScope scope(isolate); | 849 HandleScope scope(isolate); |
827 uint32_t index = static_cast<uint32_t>(this->start_function_index); | 850 uint32_t index = static_cast<uint32_t>(this->start_function_index); |
828 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start"); | 851 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start"); |
829 Handle<Code> code = linker.GetFunctionCode(index); | 852 Handle<Code> code = instance.function_code[index]; |
830 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( | 853 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
831 isolate, &module_env, name, code, instance.js_object, index); | 854 isolate, &module_env, name, code, instance.js_object, index); |
832 | 855 |
833 // Call the JS function. | 856 // Call the JS function. |
834 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); | 857 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); |
835 MaybeHandle<Object> retval = | 858 MaybeHandle<Object> retval = |
836 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); | 859 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
837 | 860 |
838 if (retval.is_null()) { | 861 if (retval.is_null()) { |
839 thrower.Error("WASM.instantiateModule(): start function failed"); | 862 thrower.Error("WASM.instantiateModule(): start function failed"); |
840 } | 863 } |
841 } | 864 } |
842 return instance.js_object; | 865 return instance.js_object; |
843 } | 866 } |
844 | 867 |
845 Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) { | 868 Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const { |
846 DCHECK(IsValidFunction(index)); | 869 DCHECK(IsValidFunction(index)); |
847 if (linker) return linker->GetFunctionCode(index); | 870 if (linker != nullptr) return linker->GetPlaceholderCode(index); |
848 return instance ? instance->function_code[index] : Handle<Code>::null(); | 871 DCHECK_NOT_NULL(instance); |
| 872 return instance->function_code[index]; |
849 } | 873 } |
850 | 874 |
851 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { | 875 Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { |
852 DCHECK(IsValidImport(index)); | 876 DCHECK(IsValidImport(index)); |
853 return instance ? instance->import_code[index] : Handle<Code>::null(); | 877 return instance ? instance->import_code[index] : Handle<Code>::null(); |
854 } | 878 } |
855 | 879 |
856 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, | 880 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, |
857 uint32_t index) { | 881 uint32_t index) { |
858 DCHECK(IsValidFunction(index)); | 882 DCHECK(IsValidFunction(index)); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 | 924 |
901 // Allocate the globals area if necessary. | 925 // Allocate the globals area if necessary. |
902 if (!AllocateGlobals(&thrower, isolate, &instance)) { | 926 if (!AllocateGlobals(&thrower, isolate, &instance)) { |
903 return -1; | 927 return -1; |
904 } | 928 } |
905 | 929 |
906 // Build the function table. | 930 // Build the function table. |
907 instance.function_table = BuildFunctionTable(isolate, module); | 931 instance.function_table = BuildFunctionTable(isolate, module); |
908 | 932 |
909 // Create module environment. | 933 // Create module environment. |
910 WasmLinker linker(isolate, module->functions.size()); | 934 WasmLinker linker(isolate, &instance.function_code); |
911 ModuleEnv module_env; | 935 ModuleEnv module_env; |
912 module_env.module = module; | 936 module_env.module = module; |
913 module_env.instance = &instance; | 937 module_env.instance = &instance; |
914 module_env.linker = &linker; | 938 module_env.linker = &linker; |
915 module_env.origin = module->origin; | 939 module_env.origin = module->origin; |
916 | 940 |
917 if (module->export_table.size() == 0) { | 941 if (module->export_table.size() == 0) { |
918 thrower.Error("WASM.compileRun() failed: no exported functions"); | 942 thrower.Error("WASM.compileRun() failed: no exported functions"); |
919 return -2; | 943 return -2; |
920 } | 944 } |
921 | 945 |
922 // Compile all functions. | 946 // Compile all functions. |
923 for (const WasmFunction& func : module->functions) { | 947 for (const WasmFunction& func : module->functions) { |
924 // Compile the function and install it in the linker. | 948 // Compile the function and install it in the linker. |
925 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( | 949 Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction( |
926 &thrower, isolate, &module_env, &func); | 950 &thrower, isolate, &module_env, &func); |
927 if (!code.is_null()) linker.Finish(func.func_index, code); | 951 if (!code.is_null()) linker.Finish(func.func_index, code); |
928 if (thrower.error()) return -1; | 952 if (thrower.error()) return -1; |
929 } | 953 } |
930 | 954 |
931 linker.Link(instance.function_table, instance.module->function_table); | 955 linker.Link(instance.function_table, instance.module->function_table); |
932 | 956 |
933 // Wrap the main code so it can be called as a JS function. | 957 // Wrap the main code so it can be called as a JS function. |
934 uint32_t main_index = module->export_table.back().func_index; | 958 uint32_t main_index = module->export_table.back().func_index; |
935 Handle<Code> main_code = linker.GetFunctionCode(main_index); | 959 Handle<Code> main_code = instance.function_code[main_index]; |
936 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); | 960 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); |
937 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); | 961 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); |
938 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( | 962 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
939 isolate, &module_env, name, main_code, module_object, main_index); | 963 isolate, &module_env, name, main_code, module_object, main_index); |
940 | 964 |
941 // Call the JS function. | 965 // Call the JS function. |
942 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); | 966 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); |
943 MaybeHandle<Object> retval = | 967 MaybeHandle<Object> retval = |
944 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); | 968 Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
945 | 969 |
(...skipping 27 matching lines...) Expand all Loading... |
973 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && | 997 return object->GetInternalFieldCount() == kWasmModuleInternalFieldCount && |
974 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && | 998 object->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() && |
975 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && | 999 object->GetInternalField(kWasmMemArrayBuffer)->IsJSArrayBuffer() && |
976 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || | 1000 (object->GetInternalField(kWasmFunctionNamesArray)->IsByteArray() || |
977 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); | 1001 object->GetInternalField(kWasmFunctionNamesArray)->IsUndefined()); |
978 } | 1002 } |
979 | 1003 |
980 } // namespace wasm | 1004 } // namespace wasm |
981 } // namespace internal | 1005 } // namespace internal |
982 } // namespace v8 | 1006 } // namespace v8 |
OLD | NEW |