| 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 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 DCHECK(code_table->get(i)->IsCode()); | 153 DCHECK(code_table->get(i)->IsCode()); |
| 154 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 154 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); |
| 155 AllowDeferredHandleDereference embedding_raw_address; | 155 AllowDeferredHandleDereference embedding_raw_address; |
| 156 int mask = 1 << RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE; | 156 int mask = 1 << RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE; |
| 157 for (RelocIterator it(*code, mask); !it.done(); it.next()) { | 157 for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
| 158 it.rinfo()->update_wasm_function_table_size_reference(old_size, new_size); | 158 it.rinfo()->update_wasm_function_table_size_reference(old_size, new_size); |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 } | 161 } |
| 162 | 162 |
| 163 Handle<Code> CreatePlaceholder(Factory* factory, Code::Kind kind) { | |
| 164 byte buffer[] = {0, 0, 0, 0}; // fake instructions. | |
| 165 CodeDesc desc = { | |
| 166 buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; | |
| 167 return factory->NewCode(desc, Code::KindField::encode(kind), | |
| 168 Handle<Object>::null()); | |
| 169 } | |
| 170 | |
| 171 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { | 163 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { |
| 172 for (int i = 0; i < code_table->length(); ++i) { | 164 for (int i = 0; i < code_table->length(); ++i) { |
| 173 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | 165 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); |
| 174 Assembler::FlushICache(isolate, code->instruction_start(), | 166 Assembler::FlushICache(isolate, code->instruction_start(), |
| 175 code->instruction_size()); | 167 code->instruction_size()); |
| 176 } | 168 } |
| 177 } | 169 } |
| 178 | 170 |
| 179 // Fetches the compilation unit of a wasm function and executes its parallel | 171 // Fetches the compilation unit of a wasm function and executes its parallel |
| 180 // phase. | 172 // phase. |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 Handle<Code> code = Handle<Code>::null(); | 397 Handle<Code> code = Handle<Code>::null(); |
| 406 // Compile the function. | 398 // Compile the function. |
| 407 code = compiler::WasmCompilationUnit::CompileWasmFunction( | 399 code = compiler::WasmCompilationUnit::CompileWasmFunction( |
| 408 thrower, isolate, module_env, &func); | 400 thrower, isolate, module_env, &func); |
| 409 if (code.is_null()) { | 401 if (code.is_null()) { |
| 410 WasmName str = module_env->GetName(&func); | 402 WasmName str = module_env->GetName(&func); |
| 411 thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(), | 403 thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(), |
| 412 str.start()); | 404 str.start()); |
| 413 break; | 405 break; |
| 414 } | 406 } |
| 415 // Install the code into the linker table. | 407 // Install the code into the linker table. |
| 416 functions[i] = code; | 408 functions[i] = code; |
| 417 } | 409 } |
| 418 } | 410 } |
| 419 | 411 |
| 420 int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) { | 412 int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) { |
| 421 DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc)); | 413 DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc)); |
| 422 decoder.Reset(pc + 1, pc + 6); | 414 decoder.Reset(pc + 1, pc + 6); |
| 423 uint32_t call_idx = decoder.consume_u32v("call index"); | 415 uint32_t call_idx = decoder.consume_u32v("call index"); |
| 424 DCHECK(decoder.ok()); | 416 DCHECK(decoder.ok()); |
| 425 DCHECK_GE(kMaxInt, call_idx); | 417 DCHECK_GE(kMaxInt, call_idx); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 DCHECK_EQ(start, compiled_module->module()->num_imported_functions); | 454 DCHECK_EQ(start, compiled_module->module()->num_imported_functions); |
| 463 Context* context = compiled_module->ptr_to_native_context(); | 455 Context* context = compiled_module->ptr_to_native_context(); |
| 464 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | | 456 int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | |
| 465 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | 457 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 466 | 458 |
| 467 // Allocate decoder outside of the loop and reuse it to decode all function | 459 // Allocate decoder outside of the loop and reuse it to decode all function |
| 468 // indexes. | 460 // indexes. |
| 469 wasm::Decoder decoder(nullptr, nullptr); | 461 wasm::Decoder decoder(nullptr, nullptr); |
| 470 int num_wasm_functions = static_cast<int>(wasm_functions->size()); | 462 int num_wasm_functions = static_cast<int>(wasm_functions->size()); |
| 471 int func_index = start; | 463 int func_index = start; |
| 464 // We patch WASM_FUNCTION and WASM_TO_JS_FUNCTION during re-instantiation, |
| 465 // and illegal builtins initially and after deserialization. |
| 466 auto is_at_wasm_call = [](RelocIterator& it) { |
| 467 Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| 468 return code->kind() == Code::WASM_FUNCTION || |
| 469 code->kind() == Code::WASM_TO_JS_FUNCTION || |
| 470 code->builtin_index() == Builtins::kIllegal; |
| 471 }; |
| 472 |
| 472 // Patch all wasm functions. | 473 // Patch all wasm functions. |
| 473 for (; func_index < num_wasm_functions; ++func_index) { | 474 for (; func_index < num_wasm_functions; ++func_index) { |
| 474 Code* wasm_function = Code::cast(new_functions->get(func_index)); | 475 Code* wasm_function = Code::cast(new_functions->get(func_index)); |
| 475 DCHECK(wasm_function->kind() == Code::WASM_FUNCTION); | 476 DCHECK(wasm_function->kind() == Code::WASM_FUNCTION); |
| 476 // Iterate simultaneously over the relocation information and the source | 477 // Iterate simultaneously over the relocation information and the source |
| 477 // position table. For each call in the reloc info, move the source position | 478 // position table. For each call in the reloc info, move the source position |
| 478 // iterator forward to that position to find the byte offset of the | 479 // iterator forward to that position to find the byte offset of the |
| 479 // respective call. Then extract the call index from the module wire bytes | 480 // respective call. Then extract the call index from the module wire bytes |
| 480 // to find the new compiled function. | 481 // to find the new compiled function. |
| 481 SourcePositionTableIterator source_pos_iterator( | 482 SourcePositionTableIterator source_pos_iterator( |
| 482 wasm_function->source_position_table()); | 483 wasm_function->source_position_table()); |
| 483 const byte* func_bytes = | 484 const byte* func_bytes = |
| 484 module_bytes->GetChars() + | 485 module_bytes->GetChars() + |
| 485 compiled_module->module()->functions[func_index].code_start_offset; | 486 compiled_module->module()->functions[func_index].code_start_offset; |
| 486 for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) { | 487 for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) { |
| 487 if (RelocInfo::IsEmbeddedObject(it.rinfo()->rmode())) { | 488 if (RelocInfo::IsEmbeddedObject(it.rinfo()->rmode())) { |
| 488 PatchContext(it, context); | 489 PatchContext(it, context); |
| 489 continue; | 490 continue; |
| 490 } | 491 } |
| 491 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); | 492 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); |
| 492 Code::Kind kind = | 493 if (!is_at_wasm_call(it)) continue; |
| 493 Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind(); | |
| 494 if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION) | |
| 495 continue; | |
| 496 size_t offset = it.rinfo()->pc() - wasm_function->instruction_start(); | 494 size_t offset = it.rinfo()->pc() - wasm_function->instruction_start(); |
| 497 int byte_pos = | 495 int byte_pos = |
| 498 AdvanceSourcePositionTableIterator(source_pos_iterator, offset); | 496 AdvanceSourcePositionTableIterator(source_pos_iterator, offset); |
| 499 int called_func_index = | 497 int called_func_index = |
| 500 ExtractDirectCallIndex(decoder, func_bytes + byte_pos); | 498 ExtractDirectCallIndex(decoder, func_bytes + byte_pos); |
| 501 Code* new_code = Code::cast(new_functions->get(called_func_index)); | 499 Code* new_code = Code::cast(new_functions->get(called_func_index)); |
| 502 it.rinfo()->set_target_address(new_code->instruction_start(), | 500 it.rinfo()->set_target_address(new_code->instruction_start(), |
| 503 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | 501 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| 504 } | 502 } |
| 505 } | 503 } |
| 506 // Patch all exported functions. | 504 // Patch all exported functions. |
| 507 for (auto exp : module->export_table) { | 505 for (auto exp : module->export_table) { |
| 508 if (exp.kind != kExternalFunction) continue; | 506 if (exp.kind != kExternalFunction) continue; |
| 509 Code* export_wrapper = Code::cast(new_functions->get(func_index)); | 507 Code* export_wrapper = Code::cast(new_functions->get(func_index)); |
| 510 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); | 508 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); |
| 511 // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION. | 509 // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION. |
| 512 int num_wasm_calls = 0; | 510 int num_wasm_calls = 0; |
| 513 for (RelocIterator it(export_wrapper, mode_mask); !it.done(); it.next()) { | 511 for (RelocIterator it(export_wrapper, mode_mask); !it.done(); it.next()) { |
| 514 if (RelocInfo::IsEmbeddedObject(it.rinfo()->rmode())) { | 512 if (RelocInfo::IsEmbeddedObject(it.rinfo()->rmode())) { |
| 515 PatchContext(it, context); | 513 PatchContext(it, context); |
| 516 continue; | 514 continue; |
| 517 } | 515 } |
| 518 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); | 516 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode())); |
| 519 Code::Kind kind = | 517 if (!is_at_wasm_call(it)) continue; |
| 520 Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind(); | |
| 521 if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION) | |
| 522 continue; | |
| 523 ++num_wasm_calls; | 518 ++num_wasm_calls; |
| 524 Code* new_code = Code::cast(new_functions->get(exp.index)); | 519 Code* new_code = Code::cast(new_functions->get(exp.index)); |
| 525 DCHECK(new_code->kind() == Code::WASM_FUNCTION || | 520 DCHECK(new_code->kind() == Code::WASM_FUNCTION || |
| 526 new_code->kind() == Code::WASM_TO_JS_FUNCTION); | 521 new_code->kind() == Code::WASM_TO_JS_FUNCTION); |
| 527 it.rinfo()->set_target_address(new_code->instruction_start(), | 522 it.rinfo()->set_target_address(new_code->instruction_start(), |
| 528 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | 523 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); |
| 529 } | 524 } |
| 530 DCHECK_EQ(1, num_wasm_calls); | 525 DCHECK_EQ(1, num_wasm_calls); |
| 531 func_index++; | 526 func_index++; |
| 532 } | 527 } |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 | 914 |
| 920 ModuleBytesEnv module_env(this, &temp_instance, wire_bytes); | 915 ModuleBytesEnv module_env(this, &temp_instance, wire_bytes); |
| 921 | 916 |
| 922 // The {code_table} array contains import wrappers and functions (which | 917 // The {code_table} array contains import wrappers and functions (which |
| 923 // are both included in {functions.size()}, and export wrappers. | 918 // are both included in {functions.size()}, and export wrappers. |
| 924 int code_table_size = | 919 int code_table_size = |
| 925 static_cast<int>(functions.size() + num_exported_functions); | 920 static_cast<int>(functions.size() + num_exported_functions); |
| 926 Handle<FixedArray> code_table = | 921 Handle<FixedArray> code_table = |
| 927 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); | 922 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); |
| 928 | 923 |
| 929 // Initialize the code table with placeholders. | 924 // Initialize the code table with the illegal builtin. All call sites will be |
| 930 Handle<Code> code_placeholder = | 925 // patched at instantiation. |
| 931 CreatePlaceholder(factory, Code::WASM_FUNCTION); | 926 Handle<Code> illegal_builtin = isolate->builtins()->Illegal(); |
| 932 for (uint32_t i = 0; i < functions.size(); ++i) { | 927 for (uint32_t i = 0; i < functions.size(); ++i) { |
| 933 code_table->set(static_cast<int>(i), *code_placeholder); | 928 code_table->set(static_cast<int>(i), *illegal_builtin); |
| 934 temp_instance.function_code[i] = code_placeholder; | 929 temp_instance.function_code[i] = illegal_builtin; |
| 935 } | 930 } |
| 936 | 931 |
| 937 isolate->counters()->wasm_functions_per_module()->AddSample( | 932 isolate->counters()->wasm_functions_per_module()->AddSample( |
| 938 static_cast<int>(functions.size())); | 933 static_cast<int>(functions.size())); |
| 939 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { | 934 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) { |
| 940 // Avoid a race condition by collecting results into a second vector. | 935 // Avoid a race condition by collecting results into a second vector. |
| 941 std::vector<Handle<Code>> results; | 936 std::vector<Handle<Code>> results(temp_instance.function_code); |
| 942 results.reserve(temp_instance.function_code.size()); | |
| 943 for (size_t i = 0; i < temp_instance.function_code.size(); ++i) { | |
| 944 results.push_back(temp_instance.function_code[i]); | |
| 945 } | |
| 946 CompileInParallel(isolate, &module_env, results, thrower); | 937 CompileInParallel(isolate, &module_env, results, thrower); |
| 947 | 938 temp_instance.function_code.swap(results); |
| 948 for (size_t i = 0; i < results.size(); ++i) { | |
| 949 temp_instance.function_code[i] = results[i]; | |
| 950 } | |
| 951 } else { | 939 } else { |
| 952 CompileSequentially(isolate, &module_env, temp_instance.function_code, | 940 CompileSequentially(isolate, &module_env, temp_instance.function_code, |
| 953 thrower); | 941 thrower); |
| 954 } | 942 } |
| 955 if (thrower->error()) return nothing; | 943 if (thrower->error()) return nothing; |
| 956 | 944 |
| 957 // At this point, compilation has completed. Update the code table. | 945 // At this point, compilation has completed. Update the code table. |
| 958 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 946 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
| 959 i < temp_instance.function_code.size(); ++i) { | 947 i < temp_instance.function_code.size(); ++i) { |
| 960 Code* code = *temp_instance.function_code[i]; | 948 Code* code = *temp_instance.function_code[i]; |
| (...skipping 1610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2571 | 2559 |
| 2572 JSObject::AddProperty(entry, name_string, export_name.ToHandleChecked(), | 2560 JSObject::AddProperty(entry, name_string, export_name.ToHandleChecked(), |
| 2573 NONE); | 2561 NONE); |
| 2574 JSObject::AddProperty(entry, kind_string, export_kind, NONE); | 2562 JSObject::AddProperty(entry, kind_string, export_kind, NONE); |
| 2575 | 2563 |
| 2576 storage->set(index, *entry); | 2564 storage->set(index, *entry); |
| 2577 } | 2565 } |
| 2578 | 2566 |
| 2579 return array_object; | 2567 return array_object; |
| 2580 } | 2568 } |
| OLD | NEW |