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 |