| 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 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 } | 444 } |
| 445 | 445 |
| 446 Isolate* isolate_; | 446 Isolate* isolate_; |
| 447 std::vector<compiler::WasmCompilationUnit*>* compilation_units_; | 447 std::vector<compiler::WasmCompilationUnit*>* compilation_units_; |
| 448 std::queue<compiler::WasmCompilationUnit*>* executed_units_; | 448 std::queue<compiler::WasmCompilationUnit*>* executed_units_; |
| 449 base::Semaphore* on_finished_; | 449 base::Semaphore* on_finished_; |
| 450 base::Mutex* result_mutex_; | 450 base::Mutex* result_mutex_; |
| 451 base::AtomicNumber<size_t>* next_unit_; | 451 base::AtomicNumber<size_t>* next_unit_; |
| 452 }; | 452 }; |
| 453 | 453 |
| 454 void record_code_size(uint32_t& total_code_size, Code* code) { | 454 // Records statistics on the code generated by compiling WASM functions. |
| 455 if (FLAG_print_wasm_code_size) { | 455 struct CodeStats { |
| 456 total_code_size += code->body_size() + code->relocation_info()->length(); | 456 size_t code_size; |
| 457 size_t reloc_size; |
| 458 |
| 459 inline CodeStats() : code_size(0), reloc_size(0) {} |
| 460 |
| 461 inline void Record(Code* code) { |
| 462 if (FLAG_print_wasm_code_size) { |
| 463 code_size += code->body_size(); |
| 464 reloc_size += code->relocation_info()->length(); |
| 465 } |
| 457 } | 466 } |
| 458 } | 467 |
| 468 inline void Report() { |
| 469 if (FLAG_print_wasm_code_size) { |
| 470 PrintF("Total generated wasm code: %zu bytes\n", code_size); |
| 471 PrintF("Total generated wasm reloc: %zu bytes\n", reloc_size); |
| 472 } |
| 473 } |
| 474 }; |
| 459 | 475 |
| 460 bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module, | 476 bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module, |
| 461 const Handle<JSReceiver> ffi, | 477 const Handle<JSReceiver> ffi, |
| 462 WasmModuleInstance* instance, | 478 WasmModuleInstance* instance, |
| 463 ErrorThrower* thrower, Factory* factory, | 479 ErrorThrower* thrower, Factory* factory, |
| 464 ModuleEnv* module_env, | 480 ModuleEnv* module_env, |
| 465 uint32_t& total_code_size) { | 481 CodeStats& code_stats) { |
| 466 uint32_t index = 0; | 482 uint32_t index = 0; |
| 467 if (module->import_table.size() > 0) { | 483 if (module->import_table.size() > 0) { |
| 468 instance->import_code.reserve(module->import_table.size()); | 484 instance->import_code.reserve(module->import_table.size()); |
| 469 for (const WasmImport& import : module->import_table) { | 485 for (const WasmImport& import : module->import_table) { |
| 470 WasmName module_name = module->GetNameOrNull(import.module_name_offset, | 486 WasmName module_name = module->GetNameOrNull(import.module_name_offset, |
| 471 import.module_name_length); | 487 import.module_name_length); |
| 472 WasmName function_name = module->GetNameOrNull( | 488 WasmName function_name = module->GetNameOrNull( |
| 473 import.function_name_offset, import.function_name_length); | 489 import.function_name_offset, import.function_name_length); |
| 474 MaybeHandle<JSFunction> function = LookupFunction( | 490 MaybeHandle<JSFunction> function = LookupFunction( |
| 475 *thrower, factory, ffi, index, module_name, function_name); | 491 *thrower, factory, ffi, index, module_name, function_name); |
| 476 if (function.is_null()) return false; | 492 if (function.is_null()) return false; |
| 477 | 493 |
| 478 Handle<Code> code = compiler::CompileWasmToJSWrapper( | 494 Handle<Code> code = compiler::CompileWasmToJSWrapper( |
| 479 isolate, module_env, function.ToHandleChecked(), import.sig, | 495 isolate, module_env, function.ToHandleChecked(), import.sig, |
| 480 module_name, function_name); | 496 module_name, function_name); |
| 481 instance->import_code.push_back(code); | 497 instance->import_code.push_back(code); |
| 482 record_code_size(total_code_size, *code); | 498 code_stats.Record(*code); |
| 483 index++; | 499 index++; |
| 484 } | 500 } |
| 485 } | 501 } |
| 486 return true; | 502 return true; |
| 487 } | 503 } |
| 488 | 504 |
| 489 void InitializeParallelCompilation( | 505 void InitializeParallelCompilation( |
| 490 Isolate* isolate, std::vector<WasmFunction>& functions, | 506 Isolate* isolate, std::vector<WasmFunction>& functions, |
| 491 std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 507 std::vector<compiler::WasmCompilationUnit*>& compilation_units, |
| 492 ModuleEnv& module_env, ErrorThrower& thrower) { | 508 ModuleEnv& module_env, ErrorThrower& thrower) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 delete unit; | 573 delete unit; |
| 558 } | 574 } |
| 559 } | 575 } |
| 560 | 576 |
| 561 bool FinishCompilation(Isolate* isolate, WasmModule* module, | 577 bool FinishCompilation(Isolate* isolate, WasmModule* module, |
| 562 const Handle<JSReceiver> ffi, | 578 const Handle<JSReceiver> ffi, |
| 563 const std::vector<Handle<Code>>& results, | 579 const std::vector<Handle<Code>>& results, |
| 564 const WasmModuleInstance& instance, | 580 const WasmModuleInstance& instance, |
| 565 const Handle<FixedArray>& code_table, | 581 const Handle<FixedArray>& code_table, |
| 566 ErrorThrower& thrower, Factory* factory, | 582 ErrorThrower& thrower, Factory* factory, |
| 567 ModuleEnv& module_env, uint32_t& total_code_size, | 583 ModuleEnv& module_env, CodeStats& code_stats, |
| 568 PropertyDescriptor& desc) { | 584 PropertyDescriptor& desc) { |
| 569 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; | 585 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; |
| 570 i < module->functions.size(); i++) { | 586 i < module->functions.size(); i++) { |
| 571 const WasmFunction& func = module->functions[i]; | 587 const WasmFunction& func = module->functions[i]; |
| 572 if (thrower.error()) break; | 588 if (thrower.error()) break; |
| 573 | 589 |
| 574 DCHECK_EQ(i, func.func_index); | 590 DCHECK_EQ(i, func.func_index); |
| 575 WasmName str = module->GetName(func.name_offset, func.name_length); | 591 WasmName str = module->GetName(func.name_offset, func.name_length); |
| 576 Handle<Code> code = Handle<Code>::null(); | 592 Handle<Code> code = Handle<Code>::null(); |
| 577 Handle<JSFunction> function = Handle<JSFunction>::null(); | 593 Handle<JSFunction> function = Handle<JSFunction>::null(); |
| 578 Handle<String> function_name = Handle<String>::null(); | 594 Handle<String> function_name = Handle<String>::null(); |
| 579 if (FLAG_wasm_num_compilation_tasks != 0) { | 595 if (FLAG_wasm_num_compilation_tasks != 0) { |
| 580 code = results[i]; | 596 code = results[i]; |
| 581 } else { | 597 } else { |
| 582 // Compile the function. | 598 // Compile the function. |
| 583 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 599 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
| 584 &thrower, isolate, &module_env, &func); | 600 &thrower, isolate, &module_env, &func); |
| 585 } | 601 } |
| 586 if (code.is_null()) { | 602 if (code.is_null()) { |
| 587 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(), | 603 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(), |
| 588 str.start()); | 604 str.start()); |
| 589 return false; | 605 return false; |
| 590 } | 606 } |
| 591 if (func.exported) { | 607 if (func.exported) { |
| 592 function_name = factory->InternalizeUtf8String(str); | 608 function_name = factory->InternalizeUtf8String(str); |
| 593 function = compiler::CompileJSToWasmWrapper( | 609 function = compiler::CompileJSToWasmWrapper( |
| 594 isolate, &module_env, function_name, code, instance.js_object, i); | 610 isolate, &module_env, function_name, code, instance.js_object, i); |
| 595 record_code_size(total_code_size, function->code()); | 611 code_stats.Record(function->code()); |
| 596 } | 612 } |
| 597 if (!code.is_null()) { | 613 if (!code.is_null()) { |
| 598 // Install the code into the linker table. | 614 // Install the code into the linker table. |
| 599 module_env.linker->Finish(i, code); | 615 module_env.linker->Finish(i, code); |
| 600 code_table->set(i, *code); | 616 code_table->set(i, *code); |
| 601 record_code_size(total_code_size, *code); | 617 code_stats.Record(*code); |
| 602 } | 618 } |
| 603 if (func.exported) { | 619 if (func.exported) { |
| 604 // Exported functions are installed as read-only properties on the | 620 // Exported functions are installed as read-only properties on the |
| 605 // module. | 621 // module. |
| 606 desc.set_value(function); | 622 desc.set_value(function); |
| 607 Maybe<bool> status = JSReceiver::DefineOwnProperty( | 623 Maybe<bool> status = JSReceiver::DefineOwnProperty( |
| 608 isolate, instance.js_object, function_name, &desc, | 624 isolate, instance.js_object, function_name, &desc, |
| 609 Object::THROW_ON_ERROR); | 625 Object::THROW_ON_ERROR); |
| 610 if (!status.IsJust()) | 626 if (!status.IsJust()) |
| 611 thrower.Error("export of %.*s failed.", str.length(), str.start()); | 627 thrower.Error("export of %.*s failed.", str.length(), str.start()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 627 isolate->counters()->wasm_instantiate_module_time()); | 643 isolate->counters()->wasm_instantiate_module_time()); |
| 628 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 644 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
| 629 Factory* factory = isolate->factory(); | 645 Factory* factory = isolate->factory(); |
| 630 | 646 |
| 631 PropertyDescriptor desc; | 647 PropertyDescriptor desc; |
| 632 desc.set_writable(false); | 648 desc.set_writable(false); |
| 633 | 649 |
| 634 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code | 650 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code |
| 635 // objects created for this module. | 651 // objects created for this module. |
| 636 // TODO(titzer): switch this to TRACE_EVENT | 652 // TODO(titzer): switch this to TRACE_EVENT |
| 637 uint32_t total_code_size = 0; | 653 CodeStats code_stats; |
| 638 | 654 |
| 639 //------------------------------------------------------------------------- | 655 //------------------------------------------------------------------------- |
| 640 // Allocate the instance and its JS counterpart. | 656 // Allocate the instance and its JS counterpart. |
| 641 //------------------------------------------------------------------------- | 657 //------------------------------------------------------------------------- |
| 642 Handle<Map> map = factory->NewMap( | 658 Handle<Map> map = factory->NewMap( |
| 643 JS_OBJECT_TYPE, | 659 JS_OBJECT_TYPE, |
| 644 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); | 660 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
| 645 WasmModuleInstance instance(this); | 661 WasmModuleInstance instance(this); |
| 646 instance.context = isolate->native_context(); | 662 instance.context = isolate->native_context(); |
| 647 instance.js_object = factory->NewJSObjectFromMap(map, TENURED); | 663 instance.js_object = factory->NewJSObjectFromMap(map, TENURED); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 module_env.module = this; | 703 module_env.module = this; |
| 688 module_env.instance = &instance; | 704 module_env.instance = &instance; |
| 689 module_env.linker = &linker; | 705 module_env.linker = &linker; |
| 690 module_env.origin = origin; | 706 module_env.origin = origin; |
| 691 | 707 |
| 692 //------------------------------------------------------------------------- | 708 //------------------------------------------------------------------------- |
| 693 // Compile wrappers to imported functions. | 709 // Compile wrappers to imported functions. |
| 694 //------------------------------------------------------------------------- | 710 //------------------------------------------------------------------------- |
| 695 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, | 711 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance, |
| 696 &thrower, factory, &module_env, | 712 &thrower, factory, &module_env, |
| 697 total_code_size)) { | 713 code_stats)) { |
| 698 return MaybeHandle<JSObject>(); | 714 return MaybeHandle<JSObject>(); |
| 699 } | 715 } |
| 700 //------------------------------------------------------------------------- | 716 //------------------------------------------------------------------------- |
| 701 // Compile all functions in the module. | 717 // Compile all functions in the module. |
| 702 //------------------------------------------------------------------------- | 718 //------------------------------------------------------------------------- |
| 703 { | 719 { |
| 704 isolate->counters()->wasm_functions_per_module()->AddSample( | 720 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 705 static_cast<int>(functions.size())); | 721 static_cast<int>(functions.size())); |
| 706 | 722 |
| 707 // Data structures for the parallel compilation. | 723 // Data structures for the parallel compilation. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 FinishCompilationUnits(this, executed_units, results, result_mutex); | 778 FinishCompilationUnits(this, executed_units, results, result_mutex); |
| 763 } | 779 } |
| 764 // 4) After the parallel phase of all compilation units has started, the | 780 // 4) After the parallel phase of all compilation units has started, the |
| 765 // main thread waits for all {WasmCompilationTask} instances to finish. | 781 // main thread waits for all {WasmCompilationTask} instances to finish. |
| 766 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); | 782 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks); |
| 767 // Finish the compilation of the remaining compilation units. | 783 // Finish the compilation of the remaining compilation units. |
| 768 FinishCompilationUnits(this, executed_units, results, result_mutex); | 784 FinishCompilationUnits(this, executed_units, results, result_mutex); |
| 769 } | 785 } |
| 770 // 5) The main thread finishes the compilation. | 786 // 5) The main thread finishes the compilation. |
| 771 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table, | 787 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table, |
| 772 thrower, factory, module_env, total_code_size, | 788 thrower, factory, module_env, code_stats, desc)) { |
| 773 desc)) { | |
| 774 instance.js_object = Handle<JSObject>::null(); | 789 instance.js_object = Handle<JSObject>::null(); |
| 775 } | 790 } |
| 776 | 791 |
| 777 // Patch all direct call sites. | 792 // Patch all direct call sites. |
| 778 linker.Link(instance.function_table, this->function_table); | 793 linker.Link(instance.function_table, this->function_table); |
| 779 instance.js_object->SetInternalField(kWasmModuleFunctionTable, | 794 instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
| 780 Smi::FromInt(0)); | 795 Smi::FromInt(0)); |
| 781 | 796 |
| 782 //------------------------------------------------------------------------- | 797 //------------------------------------------------------------------------- |
| 783 // Create and populate the exports object. | 798 // Create and populate the exports object. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 794 | 809 |
| 795 // Compile wrappers and add them to the exports object. | 810 // Compile wrappers and add them to the exports object. |
| 796 for (const WasmExport& exp : export_table) { | 811 for (const WasmExport& exp : export_table) { |
| 797 if (thrower.error()) break; | 812 if (thrower.error()) break; |
| 798 WasmName str = GetName(exp.name_offset, exp.name_length); | 813 WasmName str = GetName(exp.name_offset, exp.name_length); |
| 799 Handle<String> name = factory->InternalizeUtf8String(str); | 814 Handle<String> name = factory->InternalizeUtf8String(str); |
| 800 Handle<Code> code = linker.GetFunctionCode(exp.func_index); | 815 Handle<Code> code = linker.GetFunctionCode(exp.func_index); |
| 801 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( | 816 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( |
| 802 isolate, &module_env, name, code, instance.js_object, | 817 isolate, &module_env, name, code, instance.js_object, |
| 803 exp.func_index); | 818 exp.func_index); |
| 804 record_code_size(total_code_size, function->code()); | 819 code_stats.Record(function->code()); |
| 805 desc.set_value(function); | 820 desc.set_value(function); |
| 806 Maybe<bool> status = JSReceiver::DefineOwnProperty( | 821 Maybe<bool> status = JSReceiver::DefineOwnProperty( |
| 807 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | 822 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); |
| 808 if (!status.IsJust()) | 823 if (!status.IsJust()) |
| 809 thrower.Error("export of %.*s failed.", str.length(), str.start()); | 824 thrower.Error("export of %.*s failed.", str.length(), str.start()); |
| 810 } | 825 } |
| 811 | 826 |
| 812 if (mem_export) { | 827 if (mem_export) { |
| 813 // Export the memory as a named property. | 828 // Export the memory as a named property. |
| 814 Handle<String> name = factory->InternalizeUtf8String("memory"); | 829 Handle<String> name = factory->InternalizeUtf8String("memory"); |
| 815 JSObject::AddProperty(exports_object, name, instance.mem_buffer, | 830 JSObject::AddProperty(exports_object, name, instance.mem_buffer, |
| 816 READ_ONLY); | 831 READ_ONLY); |
| 817 } | 832 } |
| 818 } | 833 } |
| 819 } | 834 } |
| 820 | 835 |
| 821 //------------------------------------------------------------------------- | 836 //------------------------------------------------------------------------- |
| 822 // Attach an array with function names and an array with offsets into that | 837 // Attach an array with function names and an array with offsets into that |
| 823 // first array. | 838 // first array. |
| 824 //------------------------------------------------------------------------- | 839 //------------------------------------------------------------------------- |
| 825 { | 840 { |
| 826 Handle<Object> arr = BuildFunctionNamesTable(isolate, module_env.module); | 841 Handle<Object> arr = BuildFunctionNamesTable(isolate, module_env.module); |
| 827 instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr); | 842 instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr); |
| 828 } | 843 } |
| 829 | 844 |
| 830 if (FLAG_print_wasm_code_size) | 845 code_stats.Report(); |
| 831 printf("Total generated wasm code: %u bytes\n", total_code_size); | |
| 832 | 846 |
| 833 // Run the start function if one was specified. | 847 // Run the start function if one was specified. |
| 834 if (this->start_function_index >= 0) { | 848 if (this->start_function_index >= 0) { |
| 835 HandleScope scope(isolate); | 849 HandleScope scope(isolate); |
| 836 uint32_t index = static_cast<uint32_t>(this->start_function_index); | 850 uint32_t index = static_cast<uint32_t>(this->start_function_index); |
| 837 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start"); | 851 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start"); |
| 838 Handle<Code> code = linker.GetFunctionCode(index); | 852 Handle<Code> code = linker.GetFunctionCode(index); |
| 839 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( | 853 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
| 840 isolate, &module_env, name, code, instance.js_object, index); | 854 isolate, &module_env, name, code, instance.js_object, index); |
| 841 | 855 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 uint32_t func_index) { | 994 uint32_t func_index) { |
| 981 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); | 995 Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray); |
| 982 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); | 996 if (func_names_arr_obj->IsUndefined()) return Handle<String>::null(); |
| 983 return GetWasmFunctionNameFromTable( | 997 return GetWasmFunctionNameFromTable( |
| 984 handle(ByteArray::cast(func_names_arr_obj)), func_index); | 998 handle(ByteArray::cast(func_names_arr_obj)), func_index); |
| 985 } | 999 } |
| 986 | 1000 |
| 987 } // namespace wasm | 1001 } // namespace wasm |
| 988 } // namespace internal | 1002 } // namespace internal |
| 989 } // namespace v8 | 1003 } // namespace v8 |
| OLD | NEW |