| 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 <memory> | 5 #include <memory> |
| 6 | 6 |
| 7 #include "src/assembler-inl.h" | 7 #include "src/assembler-inl.h" |
| 8 #include "src/base/adapters.h" | 8 #include "src/base/adapters.h" |
| 9 #include "src/base/atomic-utils.h" | 9 #include "src/base/atomic-utils.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 } while (false) | 34 } while (false) |
| 35 | 35 |
| 36 #define TRACE_CHAIN(instance) \ | 36 #define TRACE_CHAIN(instance) \ |
| 37 do { \ | 37 do { \ |
| 38 instance->PrintInstancesChain(); \ | 38 instance->PrintInstancesChain(); \ |
| 39 } while (false) | 39 } while (false) |
| 40 | 40 |
| 41 namespace { | 41 namespace { |
| 42 | 42 |
| 43 static const int kInvalidSigIndex = -1; | 43 static const int kInvalidSigIndex = -1; |
| 44 static const int kPlaceholderMarker = 1000000000; | |
| 45 | 44 |
| 46 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { | 45 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { |
| 47 return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset; | 46 return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset; |
| 48 } | 47 } |
| 49 | 48 |
| 50 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, | 49 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, |
| 51 Handle<Object> new_ref) { | 50 Handle<Object> new_ref) { |
| 52 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); | 51 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); |
| 53 it.next()) { | 52 it.next()) { |
| 54 if (it.rinfo()->target_object() == *old_ref) { | 53 if (it.rinfo()->target_object() == *old_ref) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 DCHECK(code_table->get(i)->IsCode()); | 140 DCHECK(code_table->get(i)->IsCode()); |
| 142 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 141 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); |
| 143 AllowDeferredHandleDereference embedding_raw_address; | 142 AllowDeferredHandleDereference embedding_raw_address; |
| 144 int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; | 143 int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; |
| 145 for (RelocIterator it(*code, mask); !it.done(); it.next()) { | 144 for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
| 146 it.rinfo()->update_wasm_global_reference(old_start, globals_start); | 145 it.rinfo()->update_wasm_global_reference(old_start, globals_start); |
| 147 } | 146 } |
| 148 } | 147 } |
| 149 } | 148 } |
| 150 | 149 |
| 151 Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index, | 150 Handle<Code> CreatePlaceholder(Factory* factory, Code::Kind kind) { |
| 152 Code::Kind kind) { | 151 byte buffer[] = {0, 0, 0, 0}; // fake instructions. |
| 153 // Create a placeholder code object and encode the corresponding index in | 152 CodeDesc desc = { |
| 154 // the {constant_pool_offset} field of the code object. | |
| 155 // TODO(titzer): instead of placeholders, use a reloc_info mode. | |
| 156 static byte buffer[] = {0, 0, 0, 0}; // fake instructions. | |
| 157 static CodeDesc desc = { | |
| 158 buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; | 153 buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; |
| 159 Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind), | 154 return factory->NewCode(desc, Code::KindField::encode(kind), |
| 160 Handle<Object>::null()); | 155 Handle<Object>::null()); |
| 161 code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker); | |
| 162 return code; | |
| 163 } | |
| 164 | |
| 165 bool LinkFunction(Handle<Code> unlinked, | |
| 166 std::vector<Handle<Code>>& code_table) { | |
| 167 bool modified = false; | |
| 168 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | |
| 169 AllowDeferredHandleDereference embedding_raw_address; | |
| 170 for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) { | |
| 171 RelocInfo::Mode mode = it.rinfo()->rmode(); | |
| 172 if (RelocInfo::IsCodeTarget(mode)) { | |
| 173 Code* target = | |
| 174 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | |
| 175 if (target->constant_pool_offset() < kPlaceholderMarker) continue; | |
| 176 switch (target->kind()) { | |
| 177 case Code::WASM_FUNCTION: // fall through | |
| 178 case Code::WASM_TO_JS_FUNCTION: // fall through | |
| 179 case Code::JS_TO_WASM_FUNCTION: { | |
| 180 // Patch direct calls to placeholder code objects. | |
| 181 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; | |
| 182 Handle<Code> new_target = code_table[index]; | |
| 183 if (target != *new_target) { | |
| 184 it.rinfo()->set_target_address(new_target->instruction_start(), | |
| 185 UPDATE_WRITE_BARRIER, | |
| 186 SKIP_ICACHE_FLUSH); | |
| 187 modified = true; | |
| 188 } | |
| 189 break; | |
| 190 } | |
| 191 default: | |
| 192 break; | |
| 193 } | |
| 194 } | |
| 195 } | |
| 196 return modified; | |
| 197 } | 156 } |
| 198 | 157 |
| 199 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { | 158 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { |
| 200 for (int i = 0; i < code_table->length(); ++i) { | 159 for (int i = 0; i < code_table->length(); ++i) { |
| 201 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | 160 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); |
| 202 Assembler::FlushICache(isolate, code->instruction_start(), | 161 Assembler::FlushICache(isolate, code->instruction_start(), |
| 203 code->instruction_size()); | 162 code->instruction_size()); |
| 204 } | 163 } |
| 205 } | 164 } |
| 206 | 165 |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 PatchContext(it, context); | 502 PatchContext(it, context); |
| 544 continue; | 503 continue; |
| 545 } | 504 } |
| 546 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); | 505 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); |
| 547 Code::Kind kind = | 506 Code::Kind kind = |
| 548 Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind(); | 507 Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind(); |
| 549 if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION) | 508 if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION) |
| 550 continue; | 509 continue; |
| 551 ++num_wasm_calls; | 510 ++num_wasm_calls; |
| 552 Code* new_code = Code::cast(new_functions->get(exp.index)); | 511 Code* new_code = Code::cast(new_functions->get(exp.index)); |
| 553 DCHECK_EQ(kind, new_code->kind()); | 512 DCHECK(new_code->kind() == Code::WASM_FUNCTION || |
| 513 new_code->kind() == Code::WASM_TO_JS_FUNCTION); |
| 554 it.rinfo()->set_target_address(new_code->instruction_start(), | 514 it.rinfo()->set_target_address(new_code->instruction_start(), |
| 555 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | 515 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| 556 } | 516 } |
| 557 DCHECK_EQ(1, num_wasm_calls); | 517 DCHECK_EQ(1, num_wasm_calls); |
| 558 func_index++; | 518 func_index++; |
| 559 } | 519 } |
| 560 DCHECK_EQ(new_functions->length(), func_index); | 520 DCHECK_EQ(new_functions->length(), func_index); |
| 561 } | 521 } |
| 562 | 522 |
| 563 static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner, | 523 static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner, |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 947 ModuleBytesEnv module_env(this, &temp_instance, wire_bytes); | 907 ModuleBytesEnv module_env(this, &temp_instance, wire_bytes); |
| 948 | 908 |
| 949 // The {code_table} array contains import wrappers and functions (which | 909 // The {code_table} array contains import wrappers and functions (which |
| 950 // are both included in {functions.size()}, and export wrappers. | 910 // are both included in {functions.size()}, and export wrappers. |
| 951 int code_table_size = | 911 int code_table_size = |
| 952 static_cast<int>(functions.size() + num_exported_functions); | 912 static_cast<int>(functions.size() + num_exported_functions); |
| 953 Handle<FixedArray> code_table = | 913 Handle<FixedArray> code_table = |
| 954 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); | 914 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); |
| 955 | 915 |
| 956 // Initialize the code table with placeholders. | 916 // Initialize the code table with placeholders. |
| 917 Handle<Code> code_placeholder = |
| 918 CreatePlaceholder(factory, Code::WASM_FUNCTION); |
| 957 for (uint32_t i = 0; i < functions.size(); ++i) { | 919 for (uint32_t i = 0; i < functions.size(); ++i) { |
| 958 Code::Kind kind = Code::WASM_FUNCTION; | 920 code_table->set(static_cast<int>(i), *code_placeholder); |
| 959 if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION; | 921 temp_instance.function_code[i] = code_placeholder; |
| 960 Handle<Code> placeholder = CreatePlaceholder(factory, i, kind); | |
| 961 code_table->set(static_cast<int>(i), *placeholder); | |
| 962 temp_instance.function_code[i] = placeholder; | |
| 963 } | 922 } |
| 964 | 923 |
| 965 isolate->counters()->wasm_functions_per_module()->AddSample( | 924 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 966 static_cast<int>(functions.size())); | 925 static_cast<int>(functions.size())); |
| 967 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { | 926 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { |
| 968 // Avoid a race condition by collecting results into a second vector. | 927 // Avoid a race condition by collecting results into a second vector. |
| 969 std::vector<Handle<Code>> results; | 928 std::vector<Handle<Code>> results; |
| 970 results.reserve(temp_instance.function_code.size()); | 929 results.reserve(temp_instance.function_code.size()); |
| 971 for (size_t i = 0; i < temp_instance.function_code.size(); ++i) { | 930 for (size_t i = 0; i < temp_instance.function_code.size(); ++i) { |
| 972 results.push_back(temp_instance.function_code[i]); | 931 results.push_back(temp_instance.function_code[i]); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 983 if (thrower->error()) return nothing; | 942 if (thrower->error()) return nothing; |
| 984 | 943 |
| 985 // At this point, compilation has completed. Update the code table. | 944 // At this point, compilation has completed. Update the code table. |
| 986 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 945 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
| 987 i < temp_instance.function_code.size(); ++i) { | 946 i < temp_instance.function_code.size(); ++i) { |
| 988 Code* code = *temp_instance.function_code[i]; | 947 Code* code = *temp_instance.function_code[i]; |
| 989 code_table->set(static_cast<int>(i), code); | 948 code_table->set(static_cast<int>(i), code); |
| 990 RecordStats(isolate, code); | 949 RecordStats(isolate, code); |
| 991 } | 950 } |
| 992 | 951 |
| 993 // Link the functions in the module. | |
| 994 for (size_t i = FLAG_skip_compiling_wasm_funcs; | |
| 995 i < temp_instance.function_code.size(); ++i) { | |
| 996 Handle<Code> code = temp_instance.function_code[i]; | |
| 997 bool modified = LinkFunction(code, temp_instance.function_code); | |
| 998 if (modified) { | |
| 999 // TODO(mtrofin): do we need to flush the cache here? | |
| 1000 Assembler::FlushICache(isolate, code->instruction_start(), | |
| 1001 code->instruction_size()); | |
| 1002 } | |
| 1003 } | |
| 1004 | |
| 1005 // Create heap objects for script, module bytes and asm.js offset table to be | 952 // Create heap objects for script, module bytes and asm.js offset table to be |
| 1006 // stored in the shared module data. | 953 // stored in the shared module data. |
| 1007 Handle<Script> script; | 954 Handle<Script> script; |
| 1008 Handle<ByteArray> asm_js_offset_table; | 955 Handle<ByteArray> asm_js_offset_table; |
| 1009 if (asm_js_script.is_null()) { | 956 if (asm_js_script.is_null()) { |
| 1010 script = CreateWasmScript(isolate, wire_bytes); | 957 script = CreateWasmScript(isolate, wire_bytes); |
| 1011 } else { | 958 } else { |
| 1012 script = asm_js_script; | 959 script = asm_js_script; |
| 1013 asm_js_offset_table = | 960 asm_js_offset_table = |
| 1014 isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length()); | 961 isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length()); |
| (...skipping 1525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2540 | 2487 |
| 2541 JSObject::AddProperty(entry, name_string, export_name.ToHandleChecked(), | 2488 JSObject::AddProperty(entry, name_string, export_name.ToHandleChecked(), |
| 2542 NONE); | 2489 NONE); |
| 2543 JSObject::AddProperty(entry, kind_string, export_kind, NONE); | 2490 JSObject::AddProperty(entry, kind_string, export_kind, NONE); |
| 2544 | 2491 |
| 2545 storage->set(index, *entry); | 2492 storage->set(index, *entry); |
| 2546 } | 2493 } |
| 2547 | 2494 |
| 2548 return array_object; | 2495 return array_object; |
| 2549 } | 2496 } |
| OLD | NEW |