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

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

Issue 1961973002: [wasm] Implement parallel compilation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 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/flag-definitions.h ('k') | test/mjsunit/wasm/parallel_compilation.js » ('j') | 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/macro-assembler.h" 6 #include "src/macro-assembler.h"
6 #include "src/objects.h" 7 #include "src/objects.h"
7 #include "src/property-descriptor.h" 8 #include "src/property-descriptor.h"
8 #include "src/v8.h" 9 #include "src/v8.h"
9 10
10 #include "src/simulator.h" 11 #include "src/simulator.h"
11 12
12 #include "src/wasm/ast-decoder.h" 13 #include "src/wasm/ast-decoder.h"
13 #include "src/wasm/module-decoder.h" 14 #include "src/wasm/module-decoder.h"
14 #include "src/wasm/wasm-function-name-table.h" 15 #include "src/wasm/wasm-function-name-table.h"
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 : isolate_(isolate), placeholder_code_(size), function_code_(size) {} 124 : isolate_(isolate), placeholder_code_(size), function_code_(size) {}
124 125
125 // Get the code object for a function, allocating a placeholder if it has 126 // Get the code object for a function, allocating a placeholder if it has
126 // not yet been compiled. 127 // not yet been compiled.
127 Handle<Code> GetFunctionCode(uint32_t index) { 128 Handle<Code> GetFunctionCode(uint32_t index) {
128 DCHECK(index < function_code_.size()); 129 DCHECK(index < function_code_.size());
129 if (function_code_[index].is_null()) { 130 if (function_code_[index].is_null()) {
130 // Create a placeholder code object and encode the corresponding index in 131 // Create a placeholder code object and encode the corresponding index in
131 // the {constant_pool_offset} field of the code object. 132 // the {constant_pool_offset} field of the code object.
132 // TODO(titzer): placeholder code objects are somewhat dangerous. 133 // TODO(titzer): placeholder code objects are somewhat dangerous.
133 Handle<Code> self(nullptr, isolate_);
134 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. 134 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions.
135 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; 135 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
136 Handle<Code> code = isolate_->factory()->NewCode( 136 Handle<Code> code = isolate_->factory()->NewCode(
137 desc, Code::KindField::encode(Code::WASM_FUNCTION), self); 137 desc, Code::KindField::encode(Code::WASM_FUNCTION),
138 Handle<Object>::null());
138 code->set_constant_pool_offset(index + kPlaceholderMarker); 139 code->set_constant_pool_offset(index + kPlaceholderMarker);
139 placeholder_code_[index] = code; 140 placeholder_code_[index] = code;
140 function_code_[index] = code; 141 function_code_[index] = code;
141 } 142 }
142 return function_code_[index]; 143 return function_code_[index];
143 } 144 }
144 145
145 void Finish(uint32_t index, Handle<Code> code) { 146 void Finish(uint32_t index, Handle<Code> code) {
146 DCHECK(index < function_code_.size()); 147 DCHECK(index < function_code_.size());
147 function_code_[index] = code; 148 function_code_[index] = code;
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 } 392 }
392 393
393 if (!function->IsJSFunction()) { 394 if (!function->IsJSFunction()) {
394 return ReportFFIError(thrower, "not a function", index, module_name, 395 return ReportFFIError(thrower, "not a function", index, module_name,
395 function_name); 396 function_name);
396 } 397 }
397 398
398 return Handle<JSFunction>::cast(function); 399 return Handle<JSFunction>::cast(function);
399 } 400 }
400 401
402 namespace {
403 // Fetches the compilation unit of a wasm function and executes its parallel
404 // phase.
405 bool FetchAndExecuteCompilationUnit(
406 Isolate* isolate,
407 std::vector<compiler::WasmCompilationUnit*>* compilation_units,
408 std::queue<compiler::WasmCompilationUnit*>* executed_units,
409 base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
410 DisallowHeapAllocation no_allocation;
411 DisallowHandleAllocation no_handles;
412 DisallowHandleDereference no_deref;
413 DisallowCodeDependencyChange no_dependency_change;
414
415 // - 1 because AtomicIntrement returns the value after the atomic increment.
416 size_t index = next_unit->Increment(1) - 1;
417 if (index >= compilation_units->size()) {
418 return false;
419 }
420
421 compiler::WasmCompilationUnit* unit = compilation_units->at(index);
422 if (unit != nullptr) {
423 compiler::ExecuteCompilation(unit);
424 {
425 base::LockGuard<base::Mutex> guard(result_mutex);
426 executed_units->push(unit);
427 }
428 }
429 return true;
430 }
431
432 class WasmCompilationTask : public CancelableTask {
433 public:
434 WasmCompilationTask(
435 Isolate* isolate,
436 std::vector<compiler::WasmCompilationUnit*>* compilation_units,
437 std::queue<compiler::WasmCompilationUnit*>* executed_units,
438 base::Semaphore* on_finished, base::Mutex* result_mutex,
439 base::AtomicNumber<size_t>* next_unit)
440 : CancelableTask(isolate),
441 isolate_(isolate),
442 compilation_units_(compilation_units),
443 executed_units_(executed_units),
444 on_finished_(on_finished),
445 result_mutex_(result_mutex),
446 next_unit_(next_unit) {}
447
448 void RunInternal() override {
449 while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_,
450 executed_units_, result_mutex_,
451 next_unit_)) {
452 }
453 on_finished_->Signal();
454 }
455
456 Isolate* isolate_;
457 std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
458 std::queue<compiler::WasmCompilationUnit*>* executed_units_;
459 base::Semaphore* on_finished_;
460 base::Mutex* result_mutex_;
461 base::AtomicNumber<size_t>* next_unit_;
462 };
463
464 void record_code_size(uint32_t& total_code_size, Code* code) {
465 if (FLAG_print_wasm_code_size) {
466 total_code_size += code->body_size() + code->relocation_info()->length();
467 }
468 }
469
470 bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module,
471 const Handle<JSReceiver> ffi,
472 WasmModuleInstance* instance,
473 ErrorThrower* thrower, Factory* factory,
474 ModuleEnv* module_env,
475 uint32_t& total_code_size) {
476 uint32_t index = 0;
477 if (module->import_table.size() > 0) {
478 instance->import_code.reserve(module->import_table.size());
479 for (const WasmImport& import : module->import_table) {
480 WasmName module_name = module->GetNameOrNull(import.module_name_offset,
481 import.module_name_length);
482 WasmName function_name = module->GetNameOrNull(
483 import.function_name_offset, import.function_name_length);
484 MaybeHandle<JSFunction> function = LookupFunction(
485 *thrower, factory, ffi, index, module_name, function_name);
486 if (function.is_null()) return false;
487
488 Handle<Code> code = compiler::CompileWasmToJSWrapper(
489 isolate, module_env, function.ToHandleChecked(), import.sig,
490 module_name, function_name);
491 instance->import_code.push_back(code);
492 record_code_size(total_code_size, *code);
493 index++;
494 }
495 }
496 return true;
497 }
498
499 void InitializeParallelCompilation(
500 Isolate* isolate, std::vector<WasmFunction>& functions,
501 std::vector<compiler::WasmCompilationUnit*>& compilation_units,
502 ModuleEnv& module_env, ErrorThrower& thrower) {
503 // Create a placeholder code object for all functions.
504 // TODO(ahaas): Maybe we could skip this for external functions.
505 for (uint32_t i = 0; i < functions.size(); i++) {
506 module_env.linker->GetFunctionCode(i);
507 }
508
509 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) {
510 if (!functions[i].external) {
511 compilation_units[i] = compiler::CreateWasmCompilationUnit(
512 &thrower, isolate, &module_env, &functions[i], i);
513 } else {
514 compilation_units[i] = nullptr;
515 }
516 }
517 }
518
519 uint32_t* StartCompilationTasks(
520 Isolate* isolate,
521 std::vector<compiler::WasmCompilationUnit*>& compilation_units,
522 std::queue<compiler::WasmCompilationUnit*>& executed_units,
523 const base::SmartPointer<base::Semaphore>& pending_tasks,
524 base::Mutex& result_mutex, base::AtomicNumber<size_t>& next_unit) {
525 const size_t num_tasks =
526 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
527 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
528 uint32_t* task_ids = new uint32_t[num_tasks];
529 for (size_t i = 0; i < num_tasks; i++) {
530 WasmCompilationTask* task =
531 new WasmCompilationTask(isolate, &compilation_units, &executed_units,
532 pending_tasks.get(), &result_mutex, &next_unit);
533 task_ids[i] = task->id();
534 V8::GetCurrentPlatform()->CallOnBackgroundThread(
535 task, v8::Platform::kShortRunningTask);
536 }
537 return task_ids;
538 }
539
540 void WaitForCompilationTasks(
541 Isolate* isolate, uint32_t* task_ids,
542 const base::SmartPointer<base::Semaphore>& pending_tasks) {
543 const size_t num_tasks =
544 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
545 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
546 for (size_t i = 0; i < num_tasks; i++) {
titzer 2016/05/11 12:38:50 Please add a comment here as per in-person discuss
ahaas 2016/05/11 13:43:08 Done.
547 if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
548 pending_tasks->Wait();
549 }
550 }
551 }
552
553 void FinishCompilationUnits(
554 WasmModule* module,
555 std::queue<compiler::WasmCompilationUnit*>& executed_units,
556 std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
557 // 3.b) If executed_units contains a compilation unit, the main thread
titzer 2016/05/11 12:38:50 Move this comment into the caller?
ahaas 2016/05/11 13:43:08 Done.
558 // dequeues it and finishes the compilation.
559 while (!executed_units.empty()) {
560 compiler::WasmCompilationUnit* unit = nullptr;
561 {
562 base::LockGuard<base::Mutex> guard(&result_mutex);
563 if (!executed_units.empty()) {
564 unit = executed_units.front();
565 executed_units.pop();
566 }
567 }
568 if (unit != nullptr) {
569 int j = compiler::GetIndexOfWasmCompilationUnit(unit);
570 if (!module->functions[j].external) {
571 results[j] = compiler::FinishCompilation(unit);
572 }
573 }
574 }
575 }
576
577 bool FinishCompilation(Isolate* isolate, WasmModule* module,
578 const Handle<JSReceiver> ffi,
579 const std::vector<Handle<Code>>& results,
580 const WasmModuleInstance& instance,
581 const Handle<FixedArray>& code_table,
582 ErrorThrower& thrower, Factory* factory,
583 ModuleEnv& module_env, uint32_t& total_code_size,
584 PropertyDescriptor& desc) {
585 for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
586 i < module->functions.size(); i++) {
587 const WasmFunction& func = module->functions[i];
588 if (thrower.error()) break;
589
590 DCHECK_EQ(i, func.func_index);
591 WasmName str = module->GetName(func.name_offset, func.name_length);
592 WasmName str_null = {nullptr, 0};
593 Handle<String> name = factory->InternalizeUtf8String(str);
594 Handle<Code> code = Handle<Code>::null();
595 Handle<JSFunction> function = Handle<JSFunction>::null();
596 if (func.external) {
597 // Lookup external function in FFI object.
598 MaybeHandle<JSFunction> function =
599 LookupFunction(thrower, factory, ffi, i, str, str_null);
600 if (function.is_null()) {
601 return false;
602 }
603 code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
604 function.ToHandleChecked(),
605 func.sig, str, str_null);
606 } else {
607 if (FLAG_wasm_num_compilation_tasks != 0) {
608 code = results[i];
609 } else {
610 // Compile the function.
611 code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
612 &func);
613 }
614 if (code.is_null()) {
615 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
616 str.start());
617 return false;
618 }
619 if (func.exported) {
620 function = compiler::CompileJSToWasmWrapper(
621 isolate, &module_env, name, code, instance.js_object, i);
622 record_code_size(total_code_size, function->code());
623 }
624 }
625 if (!code.is_null()) {
626 // Install the code into the linker table.
627 module_env.linker->Finish(i, code);
628 code_table->set(i, *code);
629 record_code_size(total_code_size, *code);
630 }
631 if (func.exported) {
632 // Exported functions are installed as read-only properties on the
633 // module.
634 desc.set_value(function);
635 Maybe<bool> status = JSReceiver::DefineOwnProperty(
636 isolate, instance.js_object, name, &desc, Object::THROW_ON_ERROR);
637 if (!status.IsJust())
638 thrower.Error("export of %.*s failed.", str.length(), str.start());
639 }
640 }
641 return true;
642 }
643 } // namespace
644
401 // Instantiates a wasm module as a JSObject. 645 // Instantiates a wasm module as a JSObject.
402 // * allocates a backing store of {mem_size} bytes. 646 // * allocates a backing store of {mem_size} bytes.
403 // * installs a named property "memory" for that buffer if exported 647 // * installs a named property "memory" for that buffer if exported
404 // * installs named properties on the object for exported functions 648 // * installs named properties on the object for exported functions
405 // * compiles wasm code to machine code 649 // * compiles wasm code to machine code
406 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, 650 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
407 Handle<JSReceiver> ffi, 651 Handle<JSReceiver> ffi,
408 Handle<JSArrayBuffer> memory) { 652 Handle<JSArrayBuffer> memory) {
409 HistogramTimerScope wasm_instantiate_module_time_scope( 653 HistogramTimerScope wasm_instantiate_module_time_scope(
410 isolate->counters()->wasm_instantiate_module_time()); 654 isolate->counters()->wasm_instantiate_module_time());
411 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate. 655 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
412 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); 656 ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
413 Factory* factory = isolate->factory(); 657 Factory* factory = isolate->factory();
414 658
415 PropertyDescriptor desc; 659 PropertyDescriptor desc;
416 desc.set_writable(false); 660 desc.set_writable(false);
417 661
418 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code 662 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code
419 // objects created for this module. 663 // objects created for this module.
420 // TODO(titzer): switch this to TRACE_EVENT 664 // TODO(titzer): switch this to TRACE_EVENT
421 uint32_t total_code_size = 0; 665 uint32_t total_code_size = 0;
422 auto record_code_size = [&total_code_size](Code* code) {
423 if (FLAG_print_wasm_code_size)
424 total_code_size += code->body_size() + code->relocation_info()->length();
425 };
426 666
427 //------------------------------------------------------------------------- 667 //-------------------------------------------------------------------------
428 // Allocate the instance and its JS counterpart. 668 // Allocate the instance and its JS counterpart.
429 //------------------------------------------------------------------------- 669 //-------------------------------------------------------------------------
430 Handle<Map> map = factory->NewMap( 670 Handle<Map> map = factory->NewMap(
431 JS_OBJECT_TYPE, 671 JS_OBJECT_TYPE,
432 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); 672 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
433 WasmModuleInstance instance(this); 673 WasmModuleInstance instance(this);
434 instance.context = isolate->native_context(); 674 instance.context = isolate->native_context();
435 instance.js_object = factory->NewJSObjectFromMap(map, TENURED); 675 instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
(...skipping 26 matching lines...) Expand all
462 return MaybeHandle<JSObject>(); 702 return MaybeHandle<JSObject>();
463 } 703 }
464 if (!instance.globals_buffer.is_null()) { 704 if (!instance.globals_buffer.is_null()) {
465 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, 705 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
466 *instance.globals_buffer); 706 *instance.globals_buffer);
467 } 707 }
468 708
469 HistogramTimerScope wasm_compile_module_time_scope( 709 HistogramTimerScope wasm_compile_module_time_scope(
470 isolate->counters()->wasm_compile_module_time()); 710 isolate->counters()->wasm_compile_module_time());
471 711
472 //-------------------------------------------------------------------------
473 // Compile wrappers to imported functions.
474 //-------------------------------------------------------------------------
475 uint32_t index = 0;
476 instance.function_table = BuildFunctionTable(isolate, this); 712 instance.function_table = BuildFunctionTable(isolate, this);
477 WasmLinker linker(isolate, functions.size()); 713 WasmLinker linker(isolate, functions.size());
478 ModuleEnv module_env; 714 ModuleEnv module_env;
479 module_env.module = this; 715 module_env.module = this;
480 module_env.instance = &instance; 716 module_env.instance = &instance;
481 module_env.linker = &linker; 717 module_env.linker = &linker;
482 module_env.origin = origin; 718 module_env.origin = origin;
483 719
484 if (import_table.size() > 0) { 720 //-------------------------------------------------------------------------
485 instance.import_code.reserve(import_table.size()); 721 // Compile wrappers to imported functions.
486 for (const WasmImport& import : import_table) { 722 //-------------------------------------------------------------------------
487 WasmName module_name = 723 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance,
488 GetNameOrNull(import.module_name_offset, import.module_name_length); 724 &thrower, factory, &module_env,
489 WasmName function_name = GetNameOrNull(import.function_name_offset, 725 total_code_size)) {
490 import.function_name_length); 726 return MaybeHandle<JSObject>();
491 MaybeHandle<JSFunction> function = LookupFunction(
492 thrower, factory, ffi, index, module_name, function_name);
493 if (function.is_null()) return MaybeHandle<JSObject>();
494 Handle<Code> code = compiler::CompileWasmToJSWrapper(
495 isolate, &module_env, function.ToHandleChecked(), import.sig,
496 module_name, function_name);
497 instance.import_code.push_back(code);
498 record_code_size(*code);
499 index++;
500 }
501 } 727 }
502
503 //------------------------------------------------------------------------- 728 //-------------------------------------------------------------------------
504 // Compile all functions in the module. 729 // Compile all functions in the module.
505 //------------------------------------------------------------------------- 730 //-------------------------------------------------------------------------
506 { 731 {
507 isolate->counters()->wasm_functions_per_module()->AddSample( 732 isolate->counters()->wasm_functions_per_module()->AddSample(
508 static_cast<int>(functions.size())); 733 static_cast<int>(functions.size()));
509 734
735 // Data structures for the parallel compilation.
510 std::vector<compiler::WasmCompilationUnit*> compilation_units( 736 std::vector<compiler::WasmCompilationUnit*> compilation_units(
511 functions.size()); 737 functions.size());
512 std::queue<compiler::WasmCompilationUnit*> executed_units; 738 std::queue<compiler::WasmCompilationUnit*> executed_units;
513 std::vector<Handle<Code>> results(functions.size()); 739 std::vector<Handle<Code>> results(functions.size());
514 740
515 if (FLAG_wasm_parallel_compilation) { 741 if (FLAG_wasm_num_compilation_tasks != 0) {
516 // Create a placeholder code object for all functions. 742 //-----------------------------------------------------------------------
517 // TODO(ahaas): Maybe we could skip this for external functions. 743 // For parallel compilation:
518 for (uint32_t i = 0; i < functions.size(); i++) { 744 // 1) The main thread allocates a compilation unit for each wasm function
519 linker.GetFunctionCode(i); 745 // and stores them in the vector {compilation_units}.
746 // 2) The main thread spawns {WasmCompilationTask} instances which run on
747 // the background threads.
748 // 3.a) The background threads and the main thread pick one compilation
749 // unit at a time and execute the parallel phase of the compilation
750 // unit. After finishing the execution of the parallel phase, the
751 // result is enqueued in {executed_units}.
752 // 3.b) If {executed_units} contains a compilation unit, the main thread
753 // dequeues it and finishes the compilation.
754 // 4) After the parallel phase of all compilation units has started, the
755 // main thread waits for all {WasmCompilationTask} instances to finish.
756 // 5) The main thread finishes the compilation.
757
758 // Turn on the {CanonicalHandleScope} so that the background threads can
759 // use the node cache.
760 CanonicalHandleScope canonical(isolate);
761
762 // 1) The main thread allocates a compilation unit for each wasm function
763 // and stores them in the vector {compilation_units}.
764 InitializeParallelCompilation(isolate, functions, compilation_units,
765 module_env, thrower);
766
767 // Objects for the synchronization with the background threads.
768 base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0));
769 base::Mutex result_mutex;
770 base::AtomicNumber<size_t> next_unit(
771 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
772
773 // 2) The main thread spawns {WasmCompilationTask} instances which run on
774 // the background threads.
775 base::SmartArrayPointer<uint32_t> task_ids(
776 StartCompilationTasks(isolate, compilation_units, executed_units,
777 pending_tasks, result_mutex, next_unit));
778
779 // 3.a) The background threads and the main thread pick one compilation
780 // unit at a time and execute the parallel phase of the compilation
781 // unit. After finishing the execution of the parallel phase, the
782 // result is enqueued in {executed_units}.
783 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
784 &executed_units, &result_mutex,
785 &next_unit)) {
786 // 3.b) If {executed_units} contains a compilation unit, the main thread
787 // dequeues it and finishes the compilation unit. Compilation units
788 // are finished concurrently to the background threads to save
789 // memory.
790 FinishCompilationUnits(this, executed_units, results, result_mutex);
520 } 791 }
521 792 // 4) After the parallel phase of all compilation units has started, the
522 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); 793 // main thread waits for all {WasmCompilationTask} instances to finish.
523 i++) { 794 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks);
524 if (!functions[i].external) { 795 // Finish the compilation of the remaining compilation units.
525 compilation_units[i] = compiler::CreateWasmCompilationUnit( 796 FinishCompilationUnits(this, executed_units, results, result_mutex);
526 &thrower, isolate, &module_env, &functions[i], i); 797 }
527 } 798 // 5) The main thread finishes the compilation.
528 } 799 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table,
529 800 thrower, factory, module_env, total_code_size,
530 index = FLAG_skip_compiling_wasm_funcs; 801 desc)) {
531 while (true) { 802 return MaybeHandle<JSObject>();
532 while (!executed_units.empty()) {
533 compiler::WasmCompilationUnit* unit = executed_units.front();
534 executed_units.pop();
535 int i = compiler::GetIndexOfWasmCompilationUnit(unit);
536 results[i] = compiler::FinishCompilation(unit);
537 }
538 if (index < functions.size()) {
539 if (!functions[index].external) {
540 compiler::ExecuteCompilation(compilation_units[index]);
541 executed_units.push(compilation_units[index]);
542 index++;
543 }
544 } else {
545 break;
546 }
547 }
548 } 803 }
549 804
550 // First pass: compile each function and initialize the code table. 805 // Patch all direct call sites.
551 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
552 i++) {
553 const WasmFunction& func = functions[i];
554 if (thrower.error()) break;
555 DCHECK_EQ(i, func.func_index);
556
557 WasmName str = GetName(func.name_offset, func.name_length);
558 WasmName str_null = {nullptr, 0};
559 Handle<String> name = factory->InternalizeUtf8String(str);
560 Handle<Code> code = Handle<Code>::null();
561 Handle<JSFunction> function = Handle<JSFunction>::null();
562 if (func.external) {
563 // Lookup external function in FFI object.
564 MaybeHandle<JSFunction> function =
565 LookupFunction(thrower, factory, ffi, i, str, str_null);
566 if (function.is_null()) return MaybeHandle<JSObject>();
567 code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
568 function.ToHandleChecked(),
569 func.sig, str, str_null);
570 } else {
571 if (FLAG_wasm_parallel_compilation) {
572 code = results[i];
573 } else {
574 // Compile the function.
575 code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
576 &func);
577 }
578 if (code.is_null()) {
579 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
580 str.start());
581 return MaybeHandle<JSObject>();
582 }
583 if (func.exported) {
584 function = compiler::CompileJSToWasmWrapper(
585 isolate, &module_env, name, code, instance.js_object, i);
586 record_code_size(function->code());
587 }
588 }
589 if (!code.is_null()) {
590 // Install the code into the linker table.
591 linker.Finish(i, code);
592 code_table->set(i, *code);
593 record_code_size(*code);
594 }
595 if (func.exported) {
596 // Exported functions are installed as read-only properties on the
597 // module.
598 desc.set_value(function);
599 Maybe<bool> status = JSReceiver::DefineOwnProperty(
600 isolate, instance.js_object, name, &desc, Object::THROW_ON_ERROR);
601 if (!status.IsJust())
602 thrower.Error("export of %.*s failed.", str.length(), str.start());
603 }
604 }
605
606 // Second pass: patch all direct call sites.
607 linker.Link(instance.function_table, this->function_table); 806 linker.Link(instance.function_table, this->function_table);
608 instance.js_object->SetInternalField(kWasmModuleFunctionTable, 807 instance.js_object->SetInternalField(kWasmModuleFunctionTable,
609 Smi::FromInt(0)); 808 Smi::FromInt(0));
610 809
611 //------------------------------------------------------------------------- 810 //-------------------------------------------------------------------------
612 // Create and populate the exports object. 811 // Create and populate the exports object.
613 //------------------------------------------------------------------------- 812 //-------------------------------------------------------------------------
614 if (export_table.size() > 0 || mem_export) { 813 if (export_table.size() > 0 || mem_export) {
615 // Create the "exports" object. 814 // Create the "exports" object.
616 Handle<JSFunction> object_function = Handle<JSFunction>( 815 Handle<JSFunction> object_function = Handle<JSFunction>(
617 isolate->native_context()->object_function(), isolate); 816 isolate->native_context()->object_function(), isolate);
618 Handle<JSObject> exports_object = 817 Handle<JSObject> exports_object =
619 factory->NewJSObject(object_function, TENURED); 818 factory->NewJSObject(object_function, TENURED);
620 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); 819 Handle<String> exports_name = factory->InternalizeUtf8String("exports");
621 JSObject::AddProperty(instance.js_object, exports_name, exports_object, 820 JSObject::AddProperty(instance.js_object, exports_name, exports_object,
622 READ_ONLY); 821 READ_ONLY);
623 822
624 // Compile wrappers and add them to the exports object. 823 // Compile wrappers and add them to the exports object.
625 for (const WasmExport& exp : export_table) { 824 for (const WasmExport& exp : export_table) {
626 if (thrower.error()) break; 825 if (thrower.error()) break;
627 WasmName str = GetName(exp.name_offset, exp.name_length); 826 WasmName str = GetName(exp.name_offset, exp.name_length);
628 Handle<String> name = factory->InternalizeUtf8String(str); 827 Handle<String> name = factory->InternalizeUtf8String(str);
629 Handle<Code> code = linker.GetFunctionCode(exp.func_index); 828 Handle<Code> code = linker.GetFunctionCode(exp.func_index);
630 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( 829 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
631 isolate, &module_env, name, code, instance.js_object, 830 isolate, &module_env, name, code, instance.js_object,
632 exp.func_index); 831 exp.func_index);
633 record_code_size(function->code()); 832 record_code_size(total_code_size, function->code());
634 desc.set_value(function); 833 desc.set_value(function);
635 Maybe<bool> status = JSReceiver::DefineOwnProperty( 834 Maybe<bool> status = JSReceiver::DefineOwnProperty(
636 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); 835 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
637 if (!status.IsJust()) 836 if (!status.IsJust())
638 thrower.Error("export of %.*s failed.", str.length(), str.start()); 837 thrower.Error("export of %.*s failed.", str.length(), str.start());
639 } 838 }
640 839
641 if (mem_export) { 840 if (mem_export) {
642 // Export the memory as a named property. 841 // Export the memory as a named property.
643 Handle<String> name = factory->InternalizeUtf8String("memory"); 842 Handle<String> name = factory->InternalizeUtf8String("memory");
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate()); 1014 wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate());
816 if (func_names_arr_obj->IsUndefined()) 1015 if (func_names_arr_obj->IsUndefined())
817 return func_names_arr_obj; // Return undefined. 1016 return func_names_arr_obj; // Return undefined.
818 return GetWasmFunctionNameFromTable( 1017 return GetWasmFunctionNameFromTable(
819 Handle<ByteArray>::cast(func_names_arr_obj), func_index); 1018 Handle<ByteArray>::cast(func_names_arr_obj), func_index);
820 } 1019 }
821 1020
822 } // namespace wasm 1021 } // namespace wasm
823 } // namespace internal 1022 } // namespace internal
824 } // namespace v8 1023 } // namespace v8
OLDNEW
« no previous file with comments | « src/flag-definitions.h ('k') | test/mjsunit/wasm/parallel_compilation.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698