Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/atomic-utils.h" | 5 #include "src/base/atomic-utils.h" |
| 6 #include "src/macro-assembler.h" | 6 #include "src/macro-assembler.h" |
| 7 #include "src/objects.h" | 7 #include "src/objects.h" |
| 8 #include "src/property-descriptor.h" | 8 #include "src/property-descriptor.h" |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 index++; | 412 index++; |
| 413 } | 413 } |
| 414 } | 414 } |
| 415 return true; | 415 return true; |
| 416 } | 416 } |
| 417 | 417 |
| 418 void InitializeParallelCompilation( | 418 void InitializeParallelCompilation( |
| 419 Isolate* isolate, const std::vector<WasmFunction>& functions, | 419 Isolate* isolate, const std::vector<WasmFunction>& functions, |
| 420 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 420 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
| 421 ModuleEnv& module_env, ErrorThrower& thrower) { | 421 ModuleEnv& module_env, ErrorThrower& thrower) { |
| 422 // Create a placeholder code object for all functions. | |
| 423 // TODO(ahaas): Maybe we could skip this for external functions. | |
|
titzer
2016/05/26 15:12:25
Why did you delete this code? It's necessary to cr
Mircea Trofin
2016/05/26 15:53:18
The CL has the refactoring one as a dependency. Th
| |
| 424 for (uint32_t i = 0; i < functions.size(); i++) { | |
| 425 module_env.linker->GetFunctionCode(i); | |
| 426 } | |
| 427 | |
| 428 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) { | 422 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) { |
| 429 compilation_units[i] = new compiler::WasmCompilationUnit( | 423 compilation_units[i] = new compiler::WasmCompilationUnit( |
| 430 &thrower, isolate, &module_env, &functions[i], i); | 424 &thrower, isolate, &module_env, &functions[i], i); |
| 431 } | 425 } |
| 432 } | 426 } |
| 433 | 427 |
| 434 uint32_t* StartCompilationTasks( | 428 uint32_t* StartCompilationTasks( |
| 435 Isolate* isolate, | 429 Isolate* isolate, |
| 436 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 430 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
| 437 std::queue<compiler::WasmCompilationUnit*>& executed_units, | 431 std::queue<compiler::WasmCompilationUnit*>& executed_units, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 } | 473 } |
| 480 unit = executed_units.front(); | 474 unit = executed_units.front(); |
| 481 executed_units.pop(); | 475 executed_units.pop(); |
| 482 } | 476 } |
| 483 int j = unit->index(); | 477 int j = unit->index(); |
| 484 results[j] = unit->FinishCompilation(); | 478 results[j] = unit->FinishCompilation(); |
| 485 delete unit; | 479 delete unit; |
| 486 } | 480 } |
| 487 } | 481 } |
| 488 | 482 |
| 489 bool FinishCompilation(Isolate* isolate, const WasmModule* module, | 483 void CompileSequentially(Isolate* isolate, WasmModuleInstance* instance, |
|
titzer
2016/05/26 15:12:25
I like the old name better.
Mircea Trofin
2016/05/26 15:53:18
It doesn't finish anything anymore now. It does th
| |
| 490 const Handle<JSReceiver> ffi, | 484 ErrorThrower* thrower, ModuleEnv* module_env) { |
| 491 const std::vector<Handle<Code>>& results, | 485 DCHECK(!thrower->error()); |
| 492 const WasmModuleInstance& instance, | 486 const WasmModule* module = instance->module(); |
| 493 const Handle<FixedArray>& code_table, | 487 |
| 494 ErrorThrower& thrower, Factory* factory, | |
| 495 ModuleEnv& module_env, CodeStats& code_stats, | |
| 496 PropertyDescriptor& desc) { | |
| 497 if (thrower.error()) return false; | |
| 498 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; | 488 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; |
| 499 i < module->functions.size(); i++) { | 489 i < module->functions.size(); i++) { |
| 500 const WasmFunction& func = module->functions[i]; | 490 const WasmFunction& func = module->functions[i]; |
| 501 | 491 |
| 502 DCHECK_EQ(i, func.func_index); | 492 DCHECK_EQ(i, func.func_index); |
| 503 WasmName str = module->GetName(func.name_offset, func.name_length); | 493 WasmName str = module->GetName(func.name_offset, func.name_length); |
| 504 Handle<Code> code = Handle<Code>::null(); | 494 Handle<Code> code = Handle<Code>::null(); |
| 505 if (FLAG_wasm_num_compilation_tasks != 0) { | 495 // Compile the function. |
|
titzer
2016/05/26 15:12:25
wat
Mircea Trofin
2016/05/26 15:53:17
Typo?
| |
| 506 code = results[i]; | 496 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
| 507 } else { | 497 thrower, isolate, module_env, &func); |
| 508 // Compile the function. | 498 if (code.is_null()) { |
| 509 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 499 thrower->Error("Compilation of #%d:%.*s failed.", i, str.length(), |
| 510 &thrower, isolate, &module_env, &func); | 500 str.start()); |
| 501 break; | |
| 511 } | 502 } |
| 512 if (code.is_null()) { | |
| 513 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(), | |
| 514 str.start()); | |
| 515 return false; | |
| 516 } | |
| 517 if (!code.is_null()) { | |
| 518 // Install the code into the linker table. | 503 // Install the code into the linker table. |
| 519 module_env.linker->Finish(i, code); | 504 instance->function_code()[i] = code; |
| 520 code_table->set(i, *code); | |
| 521 code_stats.Record(*code); | |
| 522 } | |
| 523 } | 505 } |
| 524 return true; | |
| 525 } | 506 } |
| 526 } // namespace | 507 } // namespace |
| 527 | 508 |
| 528 void WasmModuleInstance::LoadDataSegments() { | 509 void WasmModuleInstance::LoadDataSegments() { |
| 529 for (const WasmDataSegment& segment : module()->data_segments) { | 510 for (const WasmDataSegment& segment : module()->data_segments) { |
| 530 if (!segment.init) continue; | 511 if (!segment.init) continue; |
| 531 if (!segment.source_size) continue; | 512 if (!segment.source_size) continue; |
| 532 CHECK_LT(segment.dest_addr, mem_size()); | 513 CHECK_LT(segment.dest_addr, mem_size()); |
| 533 CHECK_LE(segment.source_size, mem_size()); | 514 CHECK_LE(segment.source_size, mem_size()); |
| 534 CHECK_LE(segment.dest_addr + segment.source_size, mem_size()); | 515 CHECK_LE(segment.dest_addr + segment.source_size, mem_size()); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; | 595 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; |
| 615 Handle<Code> code = isolate_->factory()->NewCode( | 596 Handle<Code> code = isolate_->factory()->NewCode( |
| 616 desc, Code::KindField::encode(Code::WASM_FUNCTION), | 597 desc, Code::KindField::encode(Code::WASM_FUNCTION), |
| 617 Handle<Object>::null()); | 598 Handle<Object>::null()); |
| 618 code->set_constant_pool_offset(static_cast<int>(index) + | 599 code->set_constant_pool_offset(static_cast<int>(index) + |
| 619 kPlaceholderMarker); | 600 kPlaceholderMarker); |
| 620 function_code()[index] = code; | 601 function_code()[index] = code; |
| 621 } | 602 } |
| 622 } | 603 } |
| 623 | 604 |
| 605 void WasmModuleInstance::ProcessFunctionsPostLinking() { | |
|
titzer
2016/05/26 15:12:25
Please name this function for what it does. SetDeo
Mircea Trofin
2016/05/26 15:53:18
Agreed.
Mircea Trofin
2016/05/27 01:17:33
Actually... Perhaps SetStackTracingHelpers may be
| |
| 606 for (size_t i = FLAG_skip_compiling_wasm_funcs; i < function_code().size(); | |
| 607 ++i) { | |
| 608 Handle<Code> code = function_code()[i]; | |
| 609 DCHECK(code->deoptimization_data() == nullptr || | |
| 610 code->deoptimization_data()->length() == 0); | |
| 611 Handle<FixedArray> deopt_data = | |
| 612 isolate_->factory()->NewFixedArray(2, TENURED); | |
| 613 if (!js_object().is_null()) { | |
| 614 deopt_data->set(0, *js_object()); | |
| 615 } | |
| 616 deopt_data->set(1, Smi::FromInt(static_cast<int>(i))); | |
| 617 deopt_data->set_length(2); | |
| 618 code->set_deoptimization_data(*deopt_data); | |
| 619 } | |
| 620 } | |
| 621 | |
| 624 // Instantiates a wasm module as a JSObject. | 622 // Instantiates a wasm module as a JSObject. |
| 625 // * allocates a backing store of {mem_size} bytes. | 623 // * allocates a backing store of {mem_size} bytes. |
| 626 // * installs a named property "memory" for that buffer if exported | 624 // * installs a named property "memory" for that buffer if exported |
| 627 // * installs named properties on the object for exported functions | 625 // * installs named properties on the object for exported functions |
| 628 // * compiles wasm code to machine code | 626 // * compiles wasm code to machine code |
| 629 MaybeHandle<JSObject> WasmModule::Instantiate( | 627 MaybeHandle<JSObject> WasmModule::Instantiate( |
| 630 Isolate* isolate, Handle<JSReceiver> ffi, | 628 Isolate* isolate, Handle<JSReceiver> ffi, |
| 631 Handle<JSArrayBuffer> memory) const { | 629 Handle<JSArrayBuffer> memory) const { |
| 632 HistogramTimerScope wasm_instantiate_module_time_scope( | 630 HistogramTimerScope wasm_instantiate_module_time_scope( |
| 633 isolate->counters()->wasm_instantiate_module_time()); | 631 isolate->counters()->wasm_instantiate_module_time()); |
| 634 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 632 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
| 635 Factory* factory = isolate->factory(); | 633 Factory* factory = isolate->factory(); |
| 636 | 634 |
| 637 PropertyDescriptor desc; | |
| 638 desc.set_writable(false); | |
| 639 | |
| 640 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code | 635 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code |
| 641 // objects created for this module. | 636 // objects created for this module. |
| 642 // TODO(titzer): switch this to TRACE_EVENT | 637 // TODO(titzer): switch this to TRACE_EVENT |
| 643 CodeStats code_stats; | 638 CodeStats code_stats; |
| 644 | 639 |
| 645 //------------------------------------------------------------------------- | 640 //------------------------------------------------------------------------- |
| 646 // Allocate the instance and its JS counterpart. | 641 // Allocate the instance and its JS counterpart. |
| 647 //------------------------------------------------------------------------- | 642 //------------------------------------------------------------------------- |
| 648 WasmModuleInstance instance(this, isolate); | 643 WasmModuleInstance instance(this, isolate); |
| 649 instance.set_native_context(isolate->native_context()); | 644 instance.set_native_context(isolate->native_context()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 // Compile all functions in the module. | 690 // Compile all functions in the module. |
| 696 //------------------------------------------------------------------------- | 691 //------------------------------------------------------------------------- |
| 697 { | 692 { |
| 698 isolate->counters()->wasm_functions_per_module()->AddSample( | 693 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 699 static_cast<int>(functions.size())); | 694 static_cast<int>(functions.size())); |
| 700 | 695 |
| 701 // Data structures for the parallel compilation. | 696 // Data structures for the parallel compilation. |
| 702 std::vector<compiler::WasmCompilationUnit*> compilation_units( | 697 std::vector<compiler::WasmCompilationUnit*> compilation_units( |
| 703 functions.size()); | 698 functions.size()); |
| 704 std::queue<compiler::WasmCompilationUnit*> executed_units; | 699 std::queue<compiler::WasmCompilationUnit*> executed_units; |
| 705 std::vector<Handle<Code>> results(functions.size()); | |
| 706 | 700 |
| 707 if (FLAG_wasm_num_compilation_tasks != 0) { | 701 if (FLAG_wasm_num_compilation_tasks != 0) { |
| 708 //----------------------------------------------------------------------- | 702 //----------------------------------------------------------------------- |
| 709 // For parallel compilation: | 703 // For parallel compilation: |
| 710 // 1) The main thread allocates a compilation unit for each wasm function | 704 // 1) The main thread allocates a compilation unit for each wasm function |
| 711 // and stores them in the vector {compilation_units}. | 705 // and stores them in the vector {compilation_units}. |
| 712 // 2) The main thread spawns {WasmCompilationTask} instances which run on | 706 // 2) The main thread spawns {WasmCompilationTask} instances which run on |
| 713 // the background threads. | 707 // the background threads. |
| 714 // 3.a) The background threads and the main thread pick one compilation | 708 // 3.a) The background threads and the main thread pick one compilation |
| 715 // unit at a time and execute the parallel phase of the compilation | 709 // unit at a time and execute the parallel phase of the compilation |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 746 // unit at a time and execute the parallel phase of the compilation | 740 // unit at a time and execute the parallel phase of the compilation |
| 747 // unit. After finishing the execution of the parallel phase, the | 741 // unit. After finishing the execution of the parallel phase, the |
| 748 // result is enqueued in {executed_units}. | 742 // result is enqueued in {executed_units}. |
| 749 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units, | 743 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units, |
| 750 &executed_units, &result_mutex, | 744 &executed_units, &result_mutex, |
| 751 &next_unit)) { | 745 &next_unit)) { |
| 752 // 3.b) If {executed_units} contains a compilation unit, the main thread | 746 // 3.b) If {executed_units} contains a compilation unit, the main thread |
| 753 // dequeues it and finishes the compilation unit. Compilation units | 747 // dequeues it and finishes the compilation unit. Compilation units |
| 754 // are finished concurrently to the background threads to save | 748 // are finished concurrently to the background threads to save |
| 755 // memory. | 749 // memory. |
| 756 FinishCompilationUnits(executed_units, results, result_mutex); | 750 FinishCompilationUnits(executed_units, instance.function_code(), |
| 751 result_mutex); | |
| 757 } | 752 } |
| 758 // 4) After the parallel phase of all compilation units has started, the | 753 // 4) After the parallel phase of all compilation units has started, the |
| 759 // main thread waits for all {WasmCompilationTask} instances to finish. | 754 // main thread waits for all {WasmCompilationTask} instances to finish. |
| 760 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); | 755 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); |
| 761 // Finish the compilation of the remaining compilation units. | 756 // Finish the compilation of the remaining compilation units. |
| 762 FinishCompilationUnits(executed_units, results, result_mutex); | 757 FinishCompilationUnits(executed_units, instance.function_code(), |
| 758 result_mutex); | |
| 759 } else { | |
| 760 // 5) The main thread finishes the compilation. | |
| 761 CompileSequentially(isolate, &instance, &thrower, &module_env); | |
| 763 } | 762 } |
| 764 // 5) The main thread finishes the compilation. | 763 if (thrower.error()) { |
| 765 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table, | |
| 766 thrower, factory, module_env, code_stats, desc)) { | |
| 767 return Handle<JSObject>::null(); | 764 return Handle<JSObject>::null(); |
| 768 } | 765 } |
| 769 | 766 |
| 767 // At this point, compilation has completed. Update the code table | |
| 768 // and record sizes. | |
| 769 for (size_t i = FLAG_skip_compiling_wasm_funcs; | |
| 770 i < instance.function_code().size(); ++i) { | |
| 771 Code* code = *instance.function_code()[i]; | |
| 772 code_table->set(static_cast<int>(i), code); | |
| 773 code_stats.Record(code); | |
| 774 } | |
| 775 | |
| 770 // Patch all direct call sites. | 776 // Patch all direct call sites. |
| 771 linker.Link(instance.function_table(), this->function_table); | 777 linker.Link(instance.function_table(), this->function_table); |
| 772 instance.js_object()->SetInternalField(kWasmModuleFunctionTable, | 778 instance.js_object()->SetInternalField(kWasmModuleFunctionTable, |
| 773 Smi::FromInt(0)); | 779 Smi::FromInt(0)); |
| 774 | 780 |
| 781 instance.ProcessFunctionsPostLinking(); | |
| 782 | |
| 775 //------------------------------------------------------------------------- | 783 //------------------------------------------------------------------------- |
| 776 // Create and populate the exports object. | 784 // Create and populate the exports object. |
| 777 //------------------------------------------------------------------------- | 785 //------------------------------------------------------------------------- |
| 778 if (export_table.size() > 0 || mem_export) { | 786 if (export_table.size() > 0 || mem_export) { |
| 779 Handle<JSObject> exports_object; | 787 Handle<JSObject> exports_object; |
| 780 if (origin == kWasmOrigin) { | 788 if (origin == kWasmOrigin) { |
| 781 // Create the "exports" object. | 789 // Create the "exports" object. |
| 782 Handle<JSFunction> object_function = Handle<JSFunction>( | 790 Handle<JSFunction> object_function = Handle<JSFunction>( |
| 783 isolate->native_context()->object_function(), isolate); | 791 isolate->native_context()->object_function(), isolate); |
| 784 exports_object = factory->NewJSObject(object_function, TENURED); | 792 exports_object = factory->NewJSObject(object_function, TENURED); |
| 785 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); | 793 Handle<String> exports_name = factory->InternalizeUtf8String("exports"); |
| 786 JSObject::AddProperty(instance.js_object(), exports_name, | 794 JSObject::AddProperty(instance.js_object(), exports_name, |
| 787 exports_object, READ_ONLY); | 795 exports_object, READ_ONLY); |
| 788 } else { | 796 } else { |
| 789 // Just export the functions directly on the object returned. | 797 // Just export the functions directly on the object returned. |
| 790 exports_object = instance.js_object(); | 798 exports_object = instance.js_object(); |
| 791 } | 799 } |
| 792 | 800 |
| 801 PropertyDescriptor desc; | |
| 802 desc.set_writable(false); | |
| 803 | |
| 793 // Compile wrappers and add them to the exports object. | 804 // Compile wrappers and add them to the exports object. |
| 794 for (const WasmExport& exp : export_table) { | 805 for (const WasmExport& exp : export_table) { |
| 795 if (thrower.error()) break; | 806 if (thrower.error()) break; |
| 796 WasmName str = GetName(exp.name_offset, exp.name_length); | 807 WasmName str = GetName(exp.name_offset, exp.name_length); |
| 797 Handle<String> name = factory->InternalizeUtf8String(str); | 808 Handle<String> name = factory->InternalizeUtf8String(str); |
| 798 Handle<Code> code = linker.GetFunctionCode(exp.func_index); | 809 Handle<Code> code = linker.GetFunctionCode(exp.func_index); |
| 799 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( | 810 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( |
| 800 isolate, &module_env, name, code, instance.js_object(), | 811 isolate, &module_env, name, code, instance.js_object(), |
| 801 exp.func_index); | 812 exp.func_index); |
| 802 code_stats.Record(function->code()); | 813 code_stats.Record(function->code()); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 969 uint32_t func_index) { | 980 uint32_t func_index) { |
| 970 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); | 981 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); |
| 971 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); | 982 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); |
| 972 return GetWasmFunctionNameFromTable( | 983 return GetWasmFunctionNameFromTable( |
| 973 handle(ByteArray::cast(func_names_arr_obj)), func_index); | 984 handle(ByteArray::cast(func_names_arr_obj)), func_index); |
| 974 } | 985 } |
| 975 | 986 |
| 976 } // namespace wasm | 987 } // namespace wasm |
| 977 } // namespace internal | 988 } // namespace internal |
| 978 } // namespace v8 | 989 } // namespace v8 |
| OLD | NEW |