| 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 |