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 |