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 |