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/wasm/wasm-objects.h" | 5 #include "src/wasm/wasm-objects.h" |
6 #include "src/utils.h" | 6 #include "src/utils.h" |
7 | 7 |
8 #include "src/assembler-inl.h" | 8 #include "src/assembler-inl.h" |
9 #include "src/base/iterator.h" | 9 #include "src/base/iterator.h" |
10 #include "src/compiler/wasm-compiler.h" | 10 #include "src/compiler/wasm-compiler.h" |
(...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 // WasmCompiledModule::cast would fail since fields are not set yet. | 765 // WasmCompiledModule::cast would fail since fields are not set yet. |
766 Handle<WasmCompiledModule> compiled_module( | 766 Handle<WasmCompiledModule> compiled_module( |
767 reinterpret_cast<WasmCompiledModule*>(*ret), isolate); | 767 reinterpret_cast<WasmCompiledModule*>(*ret), isolate); |
768 compiled_module->InitId(); | 768 compiled_module->InitId(); |
769 compiled_module->set_num_imported_functions(0); | 769 compiled_module->set_num_imported_functions(0); |
770 compiled_module->set_shared(shared); | 770 compiled_module->set_shared(shared); |
771 compiled_module->set_native_context(isolate->native_context()); | 771 compiled_module->set_native_context(isolate->native_context()); |
772 return compiled_module; | 772 return compiled_module; |
773 } | 773 } |
774 | 774 |
| 775 Handle<WasmCompiledModule> WasmCompiledModule::Clone( |
| 776 Isolate* isolate, Handle<WasmCompiledModule> module) { |
| 777 Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast( |
| 778 isolate->factory()->CopyFixedArray(module)); |
| 779 ret->InitId(); |
| 780 ret->reset_weak_owning_instance(); |
| 781 ret->reset_weak_next_instance(); |
| 782 ret->reset_weak_prev_instance(); |
| 783 ret->reset_weak_exported_functions(); |
| 784 if (ret->has_embedded_mem_start()) { |
| 785 WasmCompiledModule::recreate_embedded_mem_start(ret, isolate->factory(), |
| 786 ret->embedded_mem_start()); |
| 787 } |
| 788 if (ret->has_globals_start()) { |
| 789 WasmCompiledModule::recreate_globals_start(ret, isolate->factory(), |
| 790 ret->globals_start()); |
| 791 } |
| 792 if (ret->has_embedded_mem_size()) { |
| 793 WasmCompiledModule::recreate_embedded_mem_size(ret, isolate->factory(), |
| 794 ret->embedded_mem_size()); |
| 795 } |
| 796 return ret; |
| 797 } |
| 798 |
| 799 void WasmCompiledModule::Reset(Isolate* isolate, |
| 800 WasmCompiledModule* compiled_module) { |
| 801 DisallowHeapAllocation no_gc; |
| 802 TRACE("Resetting %d\n", compiled_module->instance_id()); |
| 803 Object* undefined = *isolate->factory()->undefined_value(); |
| 804 Object* fct_obj = compiled_module->ptr_to_code_table(); |
| 805 if (fct_obj != nullptr && fct_obj != undefined) { |
| 806 uint32_t old_mem_size = compiled_module->mem_size(); |
| 807 uint32_t default_mem_size = compiled_module->default_mem_size(); |
| 808 Address old_mem_start = compiled_module->GetEmbeddedMemStartOrNull(); |
| 809 |
| 810 // Patch code to update memory references, global references, and function |
| 811 // table references. |
| 812 Zone specialization_zone(isolate->allocator(), ZONE_NAME); |
| 813 CodeSpecialization code_specialization(isolate, &specialization_zone); |
| 814 |
| 815 if (old_mem_size > 0 && old_mem_start != nullptr) { |
| 816 code_specialization.RelocateMemoryReferences(old_mem_start, old_mem_size, |
| 817 nullptr, default_mem_size); |
| 818 } |
| 819 |
| 820 if (compiled_module->has_globals_start()) { |
| 821 Address globals_start = |
| 822 reinterpret_cast<Address>(compiled_module->globals_start()); |
| 823 code_specialization.RelocateGlobals(globals_start, nullptr); |
| 824 compiled_module->set_globals_start(0); |
| 825 } |
| 826 |
| 827 // Reset function tables. |
| 828 if (compiled_module->has_function_tables()) { |
| 829 FixedArray* function_tables = compiled_module->ptr_to_function_tables(); |
| 830 FixedArray* empty_function_tables = |
| 831 compiled_module->ptr_to_empty_function_tables(); |
| 832 if (function_tables != empty_function_tables) { |
| 833 DCHECK_EQ(function_tables->length(), empty_function_tables->length()); |
| 834 for (int i = 0, e = function_tables->length(); i < e; ++i) { |
| 835 code_specialization.RelocateObject( |
| 836 handle(function_tables->get(i), isolate), |
| 837 handle(empty_function_tables->get(i), isolate)); |
| 838 } |
| 839 compiled_module->set_ptr_to_function_tables(empty_function_tables); |
| 840 } |
| 841 } |
| 842 |
| 843 FixedArray* functions = FixedArray::cast(fct_obj); |
| 844 for (int i = compiled_module->num_imported_functions(), |
| 845 end = functions->length(); |
| 846 i < end; ++i) { |
| 847 Code* code = Code::cast(functions->get(i)); |
| 848 // Skip lazy compile stubs. |
| 849 if (code->builtin_index() == Builtins::kWasmCompileLazy) continue; |
| 850 if (code->kind() != Code::WASM_FUNCTION) { |
| 851 // From here on, there should only be wrappers for exported functions. |
| 852 for (; i < end; ++i) { |
| 853 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, |
| 854 Code::cast(functions->get(i))->kind()); |
| 855 } |
| 856 break; |
| 857 } |
| 858 bool changed = |
| 859 code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH); |
| 860 // TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED |
| 861 // above. |
| 862 if (changed) { |
| 863 Assembler::FlushICache(isolate, code->instruction_start(), |
| 864 code->instruction_size()); |
| 865 } |
| 866 } |
| 867 } |
| 868 compiled_module->ResetSpecializationMemInfoIfNeeded(); |
| 869 } |
| 870 |
775 void WasmCompiledModule::InitId() { | 871 void WasmCompiledModule::InitId() { |
776 #if DEBUG | 872 #if DEBUG |
777 static uint32_t instance_id_counter = 0; | 873 static uint32_t instance_id_counter = 0; |
778 set(kID_instance_id, Smi::FromInt(instance_id_counter++)); | 874 set(kID_instance_id, Smi::FromInt(instance_id_counter++)); |
779 TRACE("New compiled module id: %d\n", instance_id()); | 875 TRACE("New compiled module id: %d\n", instance_id()); |
780 #endif | 876 #endif |
781 } | 877 } |
782 | 878 |
| 879 void WasmCompiledModule::ResetSpecializationMemInfoIfNeeded() { |
| 880 DisallowHeapAllocation no_gc; |
| 881 if (has_embedded_mem_start()) { |
| 882 set_embedded_mem_size(0); |
| 883 set_embedded_mem_start(0); |
| 884 } |
| 885 } |
| 886 |
| 887 void WasmCompiledModule::SetSpecializationMemInfoFrom( |
| 888 Factory* factory, Handle<WasmCompiledModule> compiled_module, |
| 889 Handle<JSArrayBuffer> buffer) { |
| 890 DCHECK(!buffer.is_null()); |
| 891 size_t start_address = reinterpret_cast<size_t>(buffer->backing_store()); |
| 892 uint32_t size = static_cast<uint32_t>(buffer->byte_length()->Number()); |
| 893 if (!compiled_module->has_embedded_mem_start()) { |
| 894 DCHECK(!compiled_module->has_embedded_mem_size()); |
| 895 WasmCompiledModule::recreate_embedded_mem_start(compiled_module, factory, |
| 896 start_address); |
| 897 WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory, |
| 898 size); |
| 899 } else { |
| 900 compiled_module->set_embedded_mem_start(start_address); |
| 901 compiled_module->set_embedded_mem_size(size); |
| 902 } |
| 903 } |
| 904 |
| 905 void WasmCompiledModule::SetGlobalsStartAddressFrom( |
| 906 Factory* factory, Handle<WasmCompiledModule> compiled_module, |
| 907 Handle<JSArrayBuffer> buffer) { |
| 908 DCHECK(!buffer.is_null()); |
| 909 size_t start_address = reinterpret_cast<size_t>(buffer->backing_store()); |
| 910 if (!compiled_module->has_globals_start()) { |
| 911 WasmCompiledModule::recreate_globals_start(compiled_module, factory, |
| 912 start_address); |
| 913 } else { |
| 914 compiled_module->set_globals_start(start_address); |
| 915 } |
| 916 } |
| 917 |
783 MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes( | 918 MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes( |
784 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, | 919 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, |
785 uint32_t offset, uint32_t size) { | 920 uint32_t offset, uint32_t size) { |
786 // TODO(wasm): cache strings from modules if it's a performance win. | 921 // TODO(wasm): cache strings from modules if it's a performance win. |
787 Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(), | 922 Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(), |
788 isolate); | 923 isolate); |
789 DCHECK_GE(module_bytes->length(), offset); | 924 DCHECK_GE(module_bytes->length(), offset); |
790 DCHECK_GE(module_bytes->length() - offset, size); | 925 DCHECK_GE(module_bytes->length() - offset, size); |
791 Address raw = module_bytes->GetCharsAddress() + offset; | 926 Address raw = module_bytes->GetCharsAddress() + offset; |
792 if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size)) | 927 if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size)) |
793 return {}; // UTF8 decoding error for name. | 928 return {}; // UTF8 decoding error for name. |
794 DCHECK_GE(kMaxInt, offset); | 929 DCHECK_GE(kMaxInt, offset); |
795 DCHECK_GE(kMaxInt, size); | 930 DCHECK_GE(kMaxInt, size); |
796 return isolate->factory()->NewStringFromUtf8SubString( | 931 return isolate->factory()->NewStringFromUtf8SubString( |
797 module_bytes, static_cast<int>(offset), static_cast<int>(size)); | 932 module_bytes, static_cast<int>(offset), static_cast<int>(size)); |
798 } | 933 } |
799 | 934 |
800 bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { | 935 bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { |
801 if (!obj->IsFixedArray()) return false; | 936 if (!obj->IsFixedArray()) return false; |
802 FixedArray* arr = FixedArray::cast(obj); | 937 FixedArray* arr = FixedArray::cast(obj); |
803 if (arr->length() != PropertyIndices::Count) return false; | 938 if (arr->length() != PropertyIndices::Count) return false; |
804 Isolate* isolate = arr->GetIsolate(); | 939 Isolate* isolate = arr->GetIsolate(); |
805 #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \ | 940 #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \ |
806 do { \ | 941 do { \ |
807 Object* obj = arr->get(kID_##NAME); \ | 942 Object* obj = arr->get(kID_##NAME); \ |
808 if (!(TYPE_CHECK)) return false; \ | 943 if (!(TYPE_CHECK)) return false; \ |
809 } while (false); | 944 } while (false); |
| 945 // We're OK with undefined, generally, because maybe we don't |
| 946 // have a value for that item. For example, we may not have a |
| 947 // memory, or globals. |
| 948 // We're not OK with the fixed numbers being undefined. We want |
| 949 // to set once all of them. |
810 #define WCM_CHECK_OBJECT(TYPE, NAME) \ | 950 #define WCM_CHECK_OBJECT(TYPE, NAME) \ |
811 WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE()) | 951 WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE()) |
812 #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \ | 952 #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \ |
813 WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj)) | 953 WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj)) |
814 #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME) | 954 #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME) |
815 #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) WCM_CHECK_TYPE(NAME, obj->IsSmi()) | 955 #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \ |
| 956 WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsSmi()) |
816 #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME) | 957 #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME) |
| 958 #define WCM_CHECK_SMALL_FIXED_NUMBER(TYPE, NAME) \ |
| 959 WCM_CHECK_TYPE(NAME, obj->IsSmi()) |
| 960 #define WCM_CHECK_LARGE_NUMBER(TYPE, NAME) \ |
| 961 WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsMutableHeapNumber()) |
817 WCM_PROPERTY_TABLE(WCM_CHECK) | 962 WCM_PROPERTY_TABLE(WCM_CHECK) |
818 #undef WCM_CHECK | 963 #undef WCM_CHECK |
819 | 964 |
820 // All checks passed. | 965 // All checks passed. |
821 return true; | 966 return true; |
822 } | 967 } |
823 | 968 |
824 void WasmCompiledModule::PrintInstancesChain() { | 969 void WasmCompiledModule::PrintInstancesChain() { |
825 #if DEBUG | 970 #if DEBUG |
826 if (!FLAG_trace_wasm_instances) return; | 971 if (!FLAG_trace_wasm_instances) return; |
(...skipping 11 matching lines...) Expand all Loading... |
838 void WasmCompiledModule::ReinitializeAfterDeserialization( | 983 void WasmCompiledModule::ReinitializeAfterDeserialization( |
839 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { | 984 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { |
840 // This method must only be called immediately after deserialization. | 985 // This method must only be called immediately after deserialization. |
841 // At this point, no module wrapper exists, so the shared module data is | 986 // At this point, no module wrapper exists, so the shared module data is |
842 // incomplete. | 987 // incomplete. |
843 Handle<WasmSharedModuleData> shared( | 988 Handle<WasmSharedModuleData> shared( |
844 static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)), | 989 static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)), |
845 isolate); | 990 isolate); |
846 DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared)); | 991 DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared)); |
847 WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared); | 992 WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared); |
| 993 WasmCompiledModule::Reset(isolate, *compiled_module); |
848 DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared)); | 994 DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared)); |
849 } | 995 } |
850 | 996 |
851 uint32_t WasmCompiledModule::mem_size() const { | 997 uint32_t WasmCompiledModule::mem_size() const { |
852 return has_memory() ? memory()->byte_length()->Number() : default_mem_size(); | 998 DCHECK(has_embedded_mem_size() == has_embedded_mem_start()); |
| 999 return has_embedded_mem_start() ? embedded_mem_size() : default_mem_size(); |
853 } | 1000 } |
854 | 1001 |
855 uint32_t WasmCompiledModule::default_mem_size() const { | 1002 uint32_t WasmCompiledModule::default_mem_size() const { |
856 return min_mem_pages() * WasmModule::kPageSize; | 1003 return min_mem_pages() * WasmModule::kPageSize; |
857 } | 1004 } |
858 | 1005 |
859 MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull( | 1006 MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull( |
860 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, | 1007 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, |
861 uint32_t func_index) { | 1008 uint32_t func_index) { |
862 DCHECK_LT(func_index, compiled_module->module()->functions.size()); | 1009 DCHECK_LT(func_index, compiled_module->module()->functions.size()); |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false; | 1361 if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false; |
1215 Isolate* isolate = array->GetIsolate(); | 1362 Isolate* isolate = array->GetIsolate(); |
1216 if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) && | 1363 if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) && |
1217 !array->get(kNextInstanceWrapper)->IsFixedArray()) | 1364 !array->get(kNextInstanceWrapper)->IsFixedArray()) |
1218 return false; | 1365 return false; |
1219 if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) && | 1366 if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) && |
1220 !array->get(kPreviousInstanceWrapper)->IsFixedArray()) | 1367 !array->get(kPreviousInstanceWrapper)->IsFixedArray()) |
1221 return false; | 1368 return false; |
1222 return true; | 1369 return true; |
1223 } | 1370 } |
OLD | NEW |