Chromium Code Reviews| 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 placeholder_code_.insert(placeholder_code_.begin(), function_code().begin(), | |
| 123 function_code().end()); | |
| 124 } | |
| 125 | |
| 126 void CreatePlaceholder(uint32_t index) { | |
| 127 DCHECK(index < function_code().size()); | |
|
ahaas
2016/05/30 14:02:32
Could you add a DCHECK(function_code()[index].is_n
Mircea Trofin
2016/05/30 16:55:49
Done.
| |
| 128 // Create a placeholder code object and encode the corresponding index in | |
| 129 // the {constant_pool_offset} field of the code object. | |
| 130 // TODO(titzer): placeholder code objects are somewhat dangerous. | |
| 131 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. | |
| 132 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; | |
| 133 Handle<Code> code = isolate_->factory()->NewCode( | |
| 134 desc, Code::KindField::encode(Code::WASM_FUNCTION), | |
| 135 Handle<Object>::null()); | |
| 136 code->set_constant_pool_offset(static_cast<int>(index) + | |
| 137 kPlaceholderMarker); | |
| 138 placeholder_code_[index] = code; | |
| 139 function_code()[index] = code; | |
| 140 } | |
| 118 | 141 |
| 119 // Get the code object for a function, allocating a placeholder if it has | 142 // Get the code object for a function, allocating a placeholder if it has |
| 120 // not yet been compiled. | 143 // not yet been compiled. |
| 121 Handle<Code> GetFunctionCode(uint32_t index) { | 144 Handle<Code> GetFunctionCode(uint32_t index) { |
| 122 DCHECK(index < function_code_.size()); | 145 DCHECK(index < function_code().size()); |
| 123 if (function_code_[index].is_null()) { | 146 if (function_code()[index].is_null()) { |
| 124 // Create a placeholder code object and encode the corresponding index in | 147 CreatePlaceholder(index); |
| 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 } | 148 } |
| 136 return function_code_[index]; | 149 return function_code()[index]; |
| 137 } | 150 } |
| 138 | 151 |
| 139 void Finish(uint32_t index, Handle<Code> code) { | 152 void Finish(uint32_t index, Handle<Code> code) { |
| 140 DCHECK(index < function_code_.size()); | 153 DCHECK(index < function_code().size()); |
| 141 function_code_[index] = code; | 154 function_code()[index] = code; |
| 142 } | 155 } |
| 143 | 156 |
| 144 void Link(Handle<FixedArray> function_table, | 157 void Link(Handle<FixedArray> function_table, |
| 145 const std::vector<uint16_t>& functions) { | 158 const std::vector<uint16_t>& functions) { |
| 146 for (size_t i = 0; i < function_code_.size(); i++) { | 159 for (size_t i = 0; i < function_code().size(); i++) { |
| 147 LinkFunction(function_code_[i]); | 160 LinkFunction(function_code()[i]); |
| 148 } | 161 } |
| 149 if (!function_table.is_null()) { | 162 if (!function_table.is_null()) { |
| 150 int table_size = static_cast<int>(functions.size()); | 163 int table_size = static_cast<int>(functions.size()); |
| 151 DCHECK_EQ(function_table->length(), table_size * 2); | 164 DCHECK_EQ(function_table->length(), table_size * 2); |
| 152 for (int i = 0; i < table_size; i++) { | 165 for (int i = 0; i < table_size; i++) { |
| 153 function_table->set(i + table_size, *function_code_[functions[i]]); | 166 function_table->set(i + table_size, *function_code()[functions[i]]); |
| 154 } | 167 } |
| 155 } | 168 } |
| 156 } | 169 } |
| 157 | 170 |
| 158 private: | 171 private: |
| 159 static const int kPlaceholderMarker = 1000000000; | 172 std::vector<Handle<Code>>& function_code() { return *function_code_; } |
| 160 | 173 |
| 161 Isolate* isolate_; | 174 Isolate* isolate_; |
| 162 std::vector<Handle<Code>> placeholder_code_; | 175 std::vector<Handle<Code>> placeholder_code_; |
| 163 std::vector<Handle<Code>> function_code_; | 176 std::vector<Handle<Code>>* function_code_; |
| 164 | 177 |
| 165 void LinkFunction(Handle<Code> code) { | 178 void LinkFunction(Handle<Code> code) { |
| 166 bool modified = false; | 179 bool modified = false; |
| 167 int mode_mask = RelocInfo::kCodeTargetMask; | 180 int mode_mask = RelocInfo::kCodeTargetMask; |
| 168 AllowDeferredHandleDereference embedding_raw_address; | 181 AllowDeferredHandleDereference embedding_raw_address; |
| 169 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { | 182 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
| 170 RelocInfo::Mode mode = it.rinfo()->rmode(); | 183 RelocInfo::Mode mode = it.rinfo()->rmode(); |
| 171 if (RelocInfo::IsCodeTarget(mode)) { | 184 if (RelocInfo::IsCodeTarget(mode)) { |
| 172 Code* target = | 185 Code* target = |
| 173 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 186 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| 174 if (target->kind() == Code::WASM_FUNCTION && | 187 if (target->kind() == Code::WASM_FUNCTION && |
| 175 target->constant_pool_offset() >= kPlaceholderMarker) { | 188 target->constant_pool_offset() >= kPlaceholderMarker) { |
| 176 // Patch direct calls to placeholder code objects. | 189 // Patch direct calls to placeholder code objects. |
| 177 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; | 190 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
| 178 CHECK(index < function_code_.size()); | 191 CHECK(index < function_code().size()); |
| 179 Handle<Code> new_target = function_code_[index]; | 192 Handle<Code> new_target = function_code()[index]; |
| 180 if (target != *new_target) { | 193 if (target != *new_target) { |
| 181 CHECK_EQ(*placeholder_code_[index], target); | 194 CHECK_EQ(*placeholder_code_[index], target); |
| 182 it.rinfo()->set_target_address(new_target->instruction_start(), | 195 it.rinfo()->set_target_address(new_target->instruction_start(), |
| 183 SKIP_WRITE_BARRIER, | 196 SKIP_WRITE_BARRIER, |
| 184 SKIP_ICACHE_FLUSH); | 197 SKIP_ICACHE_FLUSH); |
| 185 modified = true; | 198 modified = true; |
| 186 } | 199 } |
| 187 } | 200 } |
| 188 } | 201 } |
| 189 } | 202 } |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 487 index++; | 500 index++; |
| 488 } | 501 } |
| 489 } | 502 } |
| 490 return true; | 503 return true; |
| 491 } | 504 } |
| 492 | 505 |
| 493 void InitializeParallelCompilation( | 506 void InitializeParallelCompilation( |
| 494 Isolate* isolate, const std::vector<WasmFunction>& functions, | 507 Isolate* isolate, const std::vector<WasmFunction>& functions, |
| 495 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 508 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
| 496 ModuleEnv& module_env, ErrorThrower& thrower) { | 509 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++) { | 510 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) { |
| 504 compilation_units[i] = new compiler::WasmCompilationUnit( | 511 compilation_units[i] = new compiler::WasmCompilationUnit( |
| 505 &thrower, isolate, &module_env, &functions[i], i); | 512 &thrower, isolate, &module_env, &functions[i], i); |
| 506 } | 513 } |
| 507 } | 514 } |
| 508 | 515 |
| 509 uint32_t* StartCompilationTasks( | 516 uint32_t* StartCompilationTasks( |
| 510 Isolate* isolate, | 517 Isolate* isolate, |
| 511 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 518 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
| 512 std::queue<compiler::WasmCompilationUnit*>& executed_units, | 519 std::queue<compiler::WasmCompilationUnit*>& executed_units, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 compiler::WasmCompilationUnit* unit = nullptr; | 556 compiler::WasmCompilationUnit* unit = nullptr; |
| 550 { | 557 { |
| 551 base::LockGuard<base::Mutex> guard(&result_mutex); | 558 base::LockGuard<base::Mutex> guard(&result_mutex); |
| 552 if (executed_units.empty()) { | 559 if (executed_units.empty()) { |
| 553 break; | 560 break; |
| 554 } | 561 } |
| 555 unit = executed_units.front(); | 562 unit = executed_units.front(); |
| 556 executed_units.pop(); | 563 executed_units.pop(); |
| 557 } | 564 } |
| 558 int j = unit->index(); | 565 int j = unit->index(); |
| 559 results[j] = unit->FinishCompilation(); | 566 results[j] = unit->FinishCompilation(); |
|
ahaas
2016/05/30 14:02:32
I think this will be a data race with the GetFunct
Mircea Trofin
2016/05/30 16:55:49
Good catch, thanks!
Replaced WasmLinker::GetFunct
| |
| 560 delete unit; | 567 delete unit; |
| 561 } | 568 } |
| 562 } | 569 } |
| 563 | 570 |
| 564 bool FinishCompilation(Isolate* isolate, const WasmModule* module, | 571 void CompileInParallel(Isolate* isolate, const WasmModule* module, |
| 565 const Handle<JSReceiver> ffi, | 572 std::vector<Handle<Code>>& functions, |
| 566 const std::vector<Handle<Code>>& results, | 573 ErrorThrower* thrower, ModuleEnv* module_env) { |
| 567 const WasmModuleInstance& instance, | 574 // Data structures for the parallel compilation. |
| 568 const Handle<FixedArray>& code_table, | 575 std::vector<compiler::WasmCompilationUnit*> compilation_units( |
| 569 ErrorThrower& thrower, Factory* factory, | 576 module->functions.size()); |
| 570 ModuleEnv& module_env, CodeStats& code_stats, | 577 std::queue<compiler::WasmCompilationUnit*> executed_units; |
| 571 PropertyDescriptor& desc) { | 578 |
| 572 if (thrower.error()) return false; | 579 // Create placeholders for all functions. |
| 580 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { | |
| 581 module_env->linker->CreatePlaceholder(i); | |
| 582 } | |
| 583 | |
| 584 //----------------------------------------------------------------------- | |
| 585 // For parallel compilation: | |
| 586 // 1) The main thread allocates a compilation unit for each wasm function | |
| 587 // and stores them in the vector {compilation_units}. | |
| 588 // 2) The main thread spawns {WasmCompilationTask} instances which run on | |
| 589 // the background threads. | |
| 590 // 3.a) The background threads and the main thread pick one compilation | |
| 591 // unit at a time and execute the parallel phase of the compilation | |
| 592 // unit. After finishing the execution of the parallel phase, the | |
| 593 // result is enqueued in {executed_units}. | |
| 594 // 3.b) If {executed_units} contains a compilation unit, the main thread | |
| 595 // dequeues it and finishes the compilation. | |
| 596 // 4) After the parallel phase of all compilation units has started, the | |
| 597 // main thread waits for all {WasmCompilationTask} instances to finish. | |
| 598 // 5) The main thread finishes the compilation. | |
| 599 | |
| 600 // Turn on the {CanonicalHandleScope} so that the background threads can | |
| 601 // use the node cache. | |
| 602 CanonicalHandleScope canonical(isolate); | |
| 603 | |
| 604 // 1) The main thread allocates a compilation unit for each wasm function | |
| 605 // and stores them in the vector {compilation_units}. | |
| 606 InitializeParallelCompilation(isolate, module->functions, compilation_units, | |
| 607 *module_env, *thrower); | |
| 608 | |
| 609 // Objects for the synchronization with the background threads. | |
| 610 base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0)); | |
| 611 base::Mutex result_mutex; | |
| 612 base::AtomicNumber<size_t> next_unit( | |
| 613 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs)); | |
| 614 | |
| 615 // 2) The main thread spawns {WasmCompilationTask} instances which run on | |
| 616 // the background threads. | |
| 617 base::SmartArrayPointer<uint32_t> task_ids( | |
| 618 StartCompilationTasks(isolate, compilation_units, executed_units, | |
| 619 pending_tasks, result_mutex, next_unit)); | |
| 620 | |
| 621 // 3.a) The background threads and the main thread pick one compilation | |
| 622 // unit at a time and execute the parallel phase of the compilation | |
| 623 // unit. After finishing the execution of the parallel phase, the | |
| 624 // result is enqueued in {executed_units}. | |
| 625 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units, | |
| 626 &executed_units, &result_mutex, | |
| 627 &next_unit)) { | |
| 628 // 3.b) If {executed_units} contains a compilation unit, the main thread | |
| 629 // dequeues it and finishes the compilation unit. Compilation units | |
| 630 // are finished concurrently to the background threads to save | |
| 631 // memory. | |
| 632 FinishCompilationUnits(executed_units, functions, result_mutex); | |
| 633 } | |
| 634 // 4) After the parallel phase of all compilation units has started, the | |
| 635 // main thread waits for all {WasmCompilationTask} instances to finish. | |
| 636 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); | |
| 637 // Finish the compilation of the remaining compilation units. | |
| 638 FinishCompilationUnits(executed_units, functions, result_mutex); | |
| 639 } | |
| 640 | |
| 641 void CompileSequentially(Isolate* isolate, const WasmModule* module, | |
| 642 std::vector<Handle<Code>>& functions, | |
| 643 ErrorThrower* thrower, ModuleEnv* module_env) { | |
| 644 DCHECK(!thrower->error()); | |
| 645 | |
| 573 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; | 646 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; |
| 574 i < module->functions.size(); i++) { | 647 i < module->functions.size(); i++) { |
| 575 const WasmFunction& func = module->functions[i]; | 648 const WasmFunction& func = module->functions[i]; |
| 576 | 649 |
| 577 DCHECK_EQ(i, func.func_index); | 650 DCHECK_EQ(i, func.func_index); |
| 578 WasmName str = module->GetName(func.name_offset, func.name_length); | 651 WasmName str = module->GetName(func.name_offset, func.name_length); |
| 579 Handle<Code> code = Handle<Code>::null(); | 652 Handle<Code> code = Handle<Code>::null(); |
| 580 if (FLAG_wasm_num_compilation_tasks != 0) { | 653 // Compile the function. |
| 581 code = results[i]; | 654 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
| 582 } else { | 655 thrower, isolate, module_env, &func); |
| 583 // Compile the function. | 656 if (code.is_null()) { |
| 584 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 657 thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(), |
| 585 &thrower, isolate, &module_env, &func); | 658 str.start()); |
| 659 break; | |
| 586 } | 660 } |
| 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. | 661 // Install the code into the linker table. |
| 594 module_env.linker->Finish(i, code); | 662 functions[i] = code; |
| 595 code_table->set(i, *code); | |
| 596 code_stats.Record(*code); | |
| 597 } | |
| 598 } | 663 } |
| 599 return true; | |
| 600 } | 664 } |
| 601 } // namespace | 665 } // namespace |
| 602 | 666 |
| 667 void SetDeoptimizationData(Factory* factory, Handle<JSObject> js_object, | |
| 668 std::vector<Handle<Code>>& functions) { | |
| 669 for (size_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { | |
| 670 Handle<Code> code = functions[i]; | |
| 671 DCHECK(code->deoptimization_data() == nullptr || | |
| 672 code->deoptimization_data()->length() == 0); | |
| 673 Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED); | |
| 674 if (!js_object.is_null()) { | |
| 675 deopt_data->set(0, *js_object); | |
| 676 } | |
| 677 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); | |
| 678 deopt_data->set_length(2); | |
| 679 code->set_deoptimization_data(*deopt_data); | |
| 680 } | |
| 681 } | |
| 682 | |
| 603 // Instantiates a wasm module as a JSObject. | 683 // Instantiates a wasm module as a JSObject. |
| 604 // * allocates a backing store of {mem_size} bytes. | 684 // * allocates a backing store of {mem_size} bytes. |
| 605 // * installs a named property "memory" for that buffer if exported | 685 // * installs a named property "memory" for that buffer if exported |
| 606 // * installs named properties on the object for exported functions | 686 // * installs named properties on the object for exported functions |
| 607 // * compiles wasm code to machine code | 687 // * compiles wasm code to machine code |
| 608 MaybeHandle<JSObject> WasmModule::Instantiate( | 688 MaybeHandle<JSObject> WasmModule::Instantiate( |
| 609 Isolate* isolate, Handle<JSReceiver> ffi, | 689 Isolate* isolate, Handle<JSReceiver> ffi, |
| 610 Handle<JSArrayBuffer> memory) const { | 690 Handle<JSArrayBuffer> memory) const { |
| 611 HistogramTimerScope wasm_instantiate_module_time_scope( | 691 HistogramTimerScope wasm_instantiate_module_time_scope( |
| 612 isolate->counters()->wasm_instantiate_module_time()); | 692 isolate->counters()->wasm_instantiate_module_time()); |
| 613 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 693 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
| 614 Factory* factory = isolate->factory(); | 694 Factory* factory = isolate->factory(); |
| 615 | 695 |
| 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 | 696 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code |
| 620 // objects created for this module. | 697 // objects created for this module. |
| 621 // TODO(titzer): switch this to TRACE_EVENT | 698 // TODO(titzer): switch this to TRACE_EVENT |
| 622 CodeStats code_stats; | 699 CodeStats code_stats; |
| 623 | 700 |
| 624 //------------------------------------------------------------------------- | 701 //------------------------------------------------------------------------- |
| 625 // Allocate the instance and its JS counterpart. | 702 // Allocate the instance and its JS counterpart. |
| 626 //------------------------------------------------------------------------- | 703 //------------------------------------------------------------------------- |
| 627 Handle<Map> map = factory->NewMap( | 704 Handle<Map> map = factory->NewMap( |
| 628 JS_OBJECT_TYPE, | 705 JS_OBJECT_TYPE, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 660 } | 737 } |
| 661 if (!instance.globals_buffer.is_null()) { | 738 if (!instance.globals_buffer.is_null()) { |
| 662 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, | 739 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, |
| 663 *instance.globals_buffer); | 740 *instance.globals_buffer); |
| 664 } | 741 } |
| 665 | 742 |
| 666 HistogramTimerScope wasm_compile_module_time_scope( | 743 HistogramTimerScope wasm_compile_module_time_scope( |
| 667 isolate->counters()->wasm_compile_module_time()); | 744 isolate->counters()->wasm_compile_module_time()); |
| 668 | 745 |
| 669 instance.function_table = BuildFunctionTable(isolate, this); | 746 instance.function_table = BuildFunctionTable(isolate, this); |
| 670 WasmLinker linker(isolate, functions.size()); | 747 WasmLinker linker(isolate, &instance.function_code); |
| 671 ModuleEnv module_env; | 748 ModuleEnv module_env; |
| 672 module_env.module = this; | 749 module_env.module = this; |
| 673 module_env.instance = &instance; | 750 module_env.instance = &instance; |
| 674 module_env.linker = &linker; | 751 module_env.linker = &linker; |
| 675 module_env.origin = origin; | 752 module_env.origin = origin; |
| 676 | 753 |
| 677 //------------------------------------------------------------------------- | 754 //------------------------------------------------------------------------- |
| 678 // Compile wrappers to imported functions. | 755 // Compile wrappers to imported functions. |
| 679 //------------------------------------------------------------------------- | 756 //------------------------------------------------------------------------- |
| 680 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, | 757 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, |
| 681 &thrower, factory, &module_env, | 758 &thrower, factory, &module_env, |
| 682 code_stats)) { | 759 code_stats)) { |
| 683 return MaybeHandle<JSObject>(); | 760 return MaybeHandle<JSObject>(); |
| 684 } | 761 } |
| 685 //------------------------------------------------------------------------- | 762 //------------------------------------------------------------------------- |
| 686 // Compile all functions in the module. | 763 // Compile all functions in the module. |
| 687 //------------------------------------------------------------------------- | 764 //------------------------------------------------------------------------- |
| 688 { | 765 { |
| 689 isolate->counters()->wasm_functions_per_module()->AddSample( | 766 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 690 static_cast<int>(functions.size())); | 767 static_cast<int>(functions.size())); |
| 768 if (FLAG_wasm_num_compilation_tasks != 0) { | |
| 769 CompileInParallel(isolate, this, instance.function_code, &thrower, | |
| 770 &module_env); | |
| 771 } else { | |
| 772 // 5) The main thread finishes the compilation. | |
| 773 CompileSequentially(isolate, this, instance.function_code, &thrower, | |
| 774 &module_env); | |
| 775 } | |
| 776 if (thrower.error()) { | |
| 777 return Handle<JSObject>::null(); | |
| 778 } | |
| 691 | 779 |
| 692 // Data structures for the parallel compilation. | 780 // At this point, compilation has completed. Update the code table |
| 693 std::vector<compiler::WasmCompilationUnit*> compilation_units( | 781 // and record sizes. |
| 694 functions.size()); | 782 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
| 695 std::queue<compiler::WasmCompilationUnit*> executed_units; | 783 i < instance.function_code.size(); ++i) { |
| 696 std::vector<Handle<Code>> results(functions.size()); | 784 Code* code = *instance.function_code[i]; |
| 697 | 785 code_table->set(static_cast<int>(i), code); |
| 698 if (FLAG_wasm_num_compilation_tasks != 0) { | 786 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. | |
|
titzer
2016/05/27 16:03:28
Looks like this step somehow go left out of the pa
Mircea Trofin
2016/05/27 16:09:09
Not quite. It was doing 2 things:
- compile sequen
| |
| 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 } | 787 } |
| 761 | 788 |
| 762 // Patch all direct call sites. | 789 // Patch all direct call sites. |
| 763 linker.Link(instance.function_table, this->function_table); | 790 linker.Link(instance.function_table, this->function_table); |
| 764 instance.js_object->SetInternalField(kWasmModuleFunctionTable, | 791 instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
| 765 Smi::FromInt(0)); | 792 Smi::FromInt(0)); |
| 766 | 793 |
| 794 SetDeoptimizationData(factory, instance.js_object, instance.function_code); | |
| 795 | |
| 767 //------------------------------------------------------------------------- | 796 //------------------------------------------------------------------------- |
| 768 // Create and populate the exports object. | 797 // Create and populate the exports object. |
| 769 //------------------------------------------------------------------------- | 798 //------------------------------------------------------------------------- |
| 770 if (export_table.size() > 0 || mem_export) { | 799 if (export_table.size() > 0 || mem_export) { |
| 771 Handle<JSObject> exports_object; | 800 Handle<JSObject> exports_object; |
| 772 if (origin == kWasmOrigin) { | 801 if (origin == kWasmOrigin) { |
| 773 // Create the "exports" object. | 802 // Create the "exports" object. |
| 774 Handle<JSFunction> object_function = Handle<JSFunction>( | 803 Handle<JSFunction> object_function = Handle<JSFunction>( |
| 775 isolate->native_context()->object_function(), isolate); | 804 isolate->native_context()->object_function(), isolate); |
| 776 exports_object = factory->NewJSObject(object_function, TENURED); | 805 exports_object = factory->NewJSObject(object_function, TENURED); |
| 777 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | 806 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); |
| 778 JSObject::AddProperty(instance.js_object, exports_name, exports_object, | 807 JSObject::AddProperty(instance.js_object, exports_name, exports_object, |
| 779 READ_ONLY); | 808 READ_ONLY); |
| 780 } else { | 809 } else { |
| 781 // Just export the functions directly on the object returned. | 810 // Just export the functions directly on the object returned. |
| 782 exports_object = instance.js_object; | 811 exports_object = instance.js_object; |
| 783 } | 812 } |
| 784 | 813 |
| 814 PropertyDescriptor desc; | |
| 815 desc.set_writable(false); | |
| 816 | |
| 785 // Compile wrappers and add them to the exports object. | 817 // Compile wrappers and add them to the exports object. |
| 786 for (const WasmExport& exp : export_table) { | 818 for (const WasmExport& exp : export_table) { |
| 787 if (thrower.error()) break; | 819 if (thrower.error()) break; |
| 788 WasmName str = GetName(exp.name_offset, exp.name_length); | 820 WasmName str = GetName(exp.name_offset, exp.name_length); |
| 789 Handle<String> name = factory->InternalizeUtf8String(str); | 821 Handle<String> name = factory->InternalizeUtf8String(str); |
| 790 Handle<Code> code = linker.GetFunctionCode(exp.func_index); | 822 Handle<Code> code = linker.GetFunctionCode(exp.func_index); |
| 791 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( | 823 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( |
| 792 isolate, &module_env, name, code, instance.js_object, | 824 isolate, &module_env, name, code, instance.js_object, |
| 793 exp.func_index); | 825 exp.func_index); |
| 794 code_stats.Record(function->code()); | 826 code_stats.Record(function->code()); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 900 | 932 |
| 901 // Allocate the globals area if necessary. | 933 // Allocate the globals area if necessary. |
| 902 if (!AllocateGlobals(&thrower, isolate, &instance)) { | 934 if (!AllocateGlobals(&thrower, isolate, &instance)) { |
| 903 return -1; | 935 return -1; |
| 904 } | 936 } |
| 905 | 937 |
| 906 // Build the function table. | 938 // Build the function table. |
| 907 instance.function_table = BuildFunctionTable(isolate, module); | 939 instance.function_table = BuildFunctionTable(isolate, module); |
| 908 | 940 |
| 909 // Create module environment. | 941 // Create module environment. |
| 910 WasmLinker linker(isolate, module->functions.size()); | 942 WasmLinker linker(isolate, &instance.function_code); |
| 911 ModuleEnv module_env; | 943 ModuleEnv module_env; |
| 912 module_env.module = module; | 944 module_env.module = module; |
| 913 module_env.instance = &instance; | 945 module_env.instance = &instance; |
| 914 module_env.linker = &linker; | 946 module_env.linker = &linker; |
| 915 module_env.origin = module->origin; | 947 module_env.origin = module->origin; |
| 916 | 948 |
| 917 if (module->export_table.size() == 0) { | 949 if (module->export_table.size() == 0) { |
| 918 thrower.Error("WASM.compileRun() failed: no exported functions"); | 950 thrower.Error("WASM.compileRun() failed: no exported functions"); |
| 919 return -2; | 951 return -2; |
| 920 } | 952 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 963 uint32_t func_index) { | 995 uint32_t func_index) { |
| 964 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); | 996 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); |
| 965 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); | 997 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); |
| 966 return GetWasmFunctionNameFromTable( | 998 return GetWasmFunctionNameFromTable( |
| 967 handle(ByteArray::cast(func_names_arr_obj)), func_index); | 999 handle(ByteArray::cast(func_names_arr_obj)), func_index); |
| 968 } | 1000 } |
| 969 | 1001 |
| 970 } // namespace wasm | 1002 } // namespace wasm |
| 971 } // namespace internal | 1003 } // namespace internal |
| 972 } // namespace v8 | 1004 } // namespace v8 |
| OLD | NEW |