Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(583)

Side by Side Diff: src/wasm/wasm-module.cc

Issue 2008043006: [wasm] separate snapshot-able stages (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@refactoring
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-module.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/wasm/wasm-module.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698