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" |
11 #include "src/compiler/wasm-compiler.h" | 11 #include "src/compiler/wasm-compiler.h" |
12 #include "src/debug/interface-types.h" | 12 #include "src/debug/interface-types.h" |
| 13 #include "src/frames-inl.h" |
13 #include "src/objects.h" | 14 #include "src/objects.h" |
14 #include "src/property-descriptor.h" | 15 #include "src/property-descriptor.h" |
15 #include "src/simulator.h" | 16 #include "src/simulator.h" |
16 #include "src/snapshot/snapshot.h" | 17 #include "src/snapshot/snapshot.h" |
17 #include "src/v8.h" | 18 #include "src/v8.h" |
18 | 19 |
19 #include "src/asmjs/asm-wasm-builder.h" | 20 #include "src/asmjs/asm-wasm-builder.h" |
20 #include "src/wasm/function-body-decoder.h" | 21 #include "src/wasm/function-body-decoder.h" |
21 #include "src/wasm/module-decoder.h" | 22 #include "src/wasm/module-decoder.h" |
22 #include "src/wasm/wasm-code-specialization.h" | 23 #include "src/wasm/wasm-code-specialization.h" |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 int cached_idx = sig_map_.Find(func->sig); | 176 int cached_idx = sig_map_.Find(func->sig); |
176 if (cached_idx >= 0) { | 177 if (cached_idx >= 0) { |
177 Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]); | 178 Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]); |
178 // Now patch the call to wasm code. | 179 // Now patch the call to wasm code. |
179 for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) { | 180 for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) { |
180 DCHECK(!it.done()); | 181 DCHECK(!it.done()); |
181 Code* target = | 182 Code* target = |
182 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 183 Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
183 if (target->kind() == Code::WASM_FUNCTION || | 184 if (target->kind() == Code::WASM_FUNCTION || |
184 target->kind() == Code::WASM_TO_JS_FUNCTION || | 185 target->kind() == Code::WASM_TO_JS_FUNCTION || |
185 target->builtin_index() == Builtins::kIllegal) { | 186 target->builtin_index() == Builtins::kIllegal || |
| 187 target->builtin_index() == Builtins::kWasmCompileLazy) { |
186 it.rinfo()->set_target_address(wasm_code->instruction_start()); | 188 it.rinfo()->set_target_address(wasm_code->instruction_start()); |
187 break; | 189 break; |
188 } | 190 } |
189 } | 191 } |
190 return code; | 192 return code; |
191 } | 193 } |
192 | 194 |
193 Handle<Code> code = | 195 Handle<Code> code = |
194 compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index); | 196 compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index); |
195 uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig); | 197 uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig); |
196 DCHECK_EQ(code_cache_.size(), new_cache_idx); | 198 DCHECK_EQ(code_cache_.size(), new_cache_idx); |
197 USE(new_cache_idx); | 199 USE(new_cache_idx); |
198 code_cache_.push_back(code); | 200 code_cache_.push_back(code); |
199 return code; | 201 return code; |
200 } | 202 } |
201 | 203 |
202 private: | 204 private: |
203 // sig_map_ maps signatures to an index in code_cache_. | 205 // sig_map_ maps signatures to an index in code_cache_. |
204 wasm::SignatureMap sig_map_; | 206 wasm::SignatureMap sig_map_; |
205 std::vector<Handle<Code>> code_cache_; | 207 std::vector<Handle<Code>> code_cache_; |
206 }; | 208 }; |
207 | 209 |
| 210 // Ensure that the code object in <code_table> at offset <func_index> has |
| 211 // deoptimization data attached. This is needed for lazy compile stubs which are |
| 212 // called from JS_TO_WASM functions or via exported function tables. The deopt |
| 213 // data is used to determine which function this lazy compile stub belongs to. |
| 214 Handle<Code> EnsureExportedLazyDeoptData( |
| 215 Isolate* isolate, Handle<WasmInstanceObject> instance, |
| 216 Handle<FixedArray> code_table, int func_index, |
| 217 Handle<FixedArray> exp_table = Handle<FixedArray>::null(), |
| 218 int exp_index = -1) { |
| 219 Handle<Code> code(Code::cast(code_table->get(func_index)), isolate); |
| 220 if (code->builtin_index() != Builtins::kWasmCompileLazy) { |
| 221 // No special deopt data needed for compiled functions, and imported |
| 222 // functions, which map to Illegal at this point (they get compiled at |
| 223 // instantiation time). |
| 224 DCHECK(code->kind() == Code::WASM_FUNCTION || |
| 225 code->kind() == Code::WASM_TO_JS_FUNCTION || |
| 226 code->builtin_index() == Builtins::kIllegal); |
| 227 return code; |
| 228 } |
| 229 // deopt_data: |
| 230 // #0: weak instance |
| 231 // #1: func_index |
| 232 // [#2: export table |
| 233 // #3: export table index] |
| 234 // [#4: export table |
| 235 // #5: export table index] |
| 236 // ... |
| 237 Handle<FixedArray> deopt_data(code->deoptimization_data()); |
| 238 if (deopt_data->length() == 0) { |
| 239 code = isolate->factory()->CopyCode(code); |
| 240 code_table->set(func_index, *code); |
| 241 deopt_data = |
| 242 isolate->factory()->NewFixedArray(exp_table.is_null() ? 2 : 4, TENURED); |
| 243 code->set_deoptimization_data(*deopt_data); |
| 244 if (!instance.is_null()) { |
| 245 Handle<WeakCell> weak_instance = |
| 246 isolate->factory()->NewWeakCell(instance); |
| 247 deopt_data->set(0, *weak_instance); |
| 248 } |
| 249 deopt_data->set(1, Smi::FromInt(func_index)); |
| 250 } |
| 251 DCHECK_IMPLIES(!instance.is_null(), |
| 252 WeakCell::cast(code->deoptimization_data()->get(0))->value() == |
| 253 *instance); |
| 254 DCHECK_EQ(func_index, |
| 255 Smi::cast(code->deoptimization_data()->get(1))->value()); |
| 256 if (!exp_table.is_null()) { |
| 257 int idx = 2; |
| 258 // TODO(clemensh): Make this linear instead of quadratic in the number of |
| 259 // exports per function. We observe four-digit number of exports in unity |
| 260 // for a single function. |
| 261 for (int l = deopt_data->length(); idx < l; idx += 2) { |
| 262 if (deopt_data->get(idx)->IsUndefined(isolate)) break; |
| 263 // We should not produce duplicates. |
| 264 DCHECK(deopt_data->get(idx) != *exp_table || |
| 265 Smi::cast(deopt_data->get(idx + 1))->value() != exp_index); |
| 266 } |
| 267 if (idx >= deopt_data->length()) { |
| 268 int add = Max(2, deopt_data->length() / 4 * 2); |
| 269 deopt_data = |
| 270 isolate->factory()->CopyFixedArrayAndGrow(deopt_data, add, TENURED); |
| 271 code->set_deoptimization_data(*deopt_data); |
| 272 } |
| 273 deopt_data->set(idx, *exp_table); |
| 274 deopt_data->set(idx + 1, Smi::FromInt(exp_index)); |
| 275 } |
| 276 return code; |
| 277 } |
| 278 |
208 // A helper for compiling an entire module. | 279 // A helper for compiling an entire module. |
209 class CompilationHelper { | 280 class CompilationHelper { |
210 public: | 281 public: |
211 CompilationHelper(Isolate* isolate, WasmModule* module) | 282 CompilationHelper(Isolate* isolate, WasmModule* module) |
212 : isolate_(isolate), module_(module) {} | 283 : isolate_(isolate), module_(module) {} |
213 | 284 |
214 // The actual runnable task that performs compilations in the background. | 285 // The actual runnable task that performs compilations in the background. |
215 class CompilationTask : public CancelableTask { | 286 class CompilationTask : public CancelableTask { |
216 public: | 287 public: |
217 CompilationHelper* helper_; | 288 CompilationHelper* helper_; |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 | 501 |
431 ModuleBytesEnv module_env(module_, &temp_instance, wire_bytes); | 502 ModuleBytesEnv module_env(module_, &temp_instance, wire_bytes); |
432 | 503 |
433 // The {code_table} array contains import wrappers and functions (which | 504 // The {code_table} array contains import wrappers and functions (which |
434 // are both included in {functions.size()}, and export wrappers. | 505 // are both included in {functions.size()}, and export wrappers. |
435 int code_table_size = static_cast<int>(module_->functions.size() + | 506 int code_table_size = static_cast<int>(module_->functions.size() + |
436 module_->num_exported_functions); | 507 module_->num_exported_functions); |
437 Handle<FixedArray> code_table = | 508 Handle<FixedArray> code_table = |
438 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); | 509 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED); |
439 | 510 |
440 // Initialize the code table with the illegal builtin. All call sites will | 511 // Check whether lazy compilation is enabled for this module. |
441 // be | 512 bool lazy_compile = |
| 513 FLAG_asm_wasm_lazy_compilation && module_->origin == wasm::kAsmJsOrigin; |
| 514 |
| 515 // If lazy compile: Initialize the code table with the lazy compile builtin. |
| 516 // Otherwise: Initialize with the illegal builtin. All call sites will be |
442 // patched at instantiation. | 517 // patched at instantiation. |
443 Handle<Code> illegal_builtin = isolate_->builtins()->Illegal(); | 518 Handle<Code> init_builtin = lazy_compile |
444 for (uint32_t i = 0; i < module_->functions.size(); ++i) { | 519 ? isolate_->builtins()->WasmCompileLazy() |
445 code_table->set(static_cast<int>(i), *illegal_builtin); | 520 : isolate_->builtins()->Illegal(); |
446 temp_instance.function_code[i] = illegal_builtin; | 521 for (int i = 0, e = static_cast<int>(module_->functions.size()); i < e; |
| 522 ++i) { |
| 523 code_table->set(i, *init_builtin); |
| 524 temp_instance.function_code[i] = init_builtin; |
447 } | 525 } |
448 | 526 |
449 isolate_->counters()->wasm_functions_per_module()->AddSample( | 527 isolate_->counters()->wasm_functions_per_module()->AddSample( |
450 static_cast<int>(module_->functions.size())); | 528 static_cast<int>(module_->functions.size())); |
451 CompilationHelper helper(isolate_, module_); | 529 if (!lazy_compile) { |
452 size_t funcs_to_compile = | 530 CompilationHelper helper(isolate_, module_); |
453 module_->functions.size() - module_->num_imported_functions; | 531 size_t funcs_to_compile = |
454 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0 && | 532 module_->functions.size() - module_->num_imported_functions; |
455 funcs_to_compile > 1) { | 533 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0 && |
456 // Avoid a race condition by collecting results into a second vector. | 534 funcs_to_compile > 1) { |
457 std::vector<Handle<Code>> results(temp_instance.function_code); | 535 // Avoid a race condition by collecting results into a second vector. |
458 helper.CompileInParallel(&module_env, results, thrower); | 536 std::vector<Handle<Code>> results(temp_instance.function_code); |
459 temp_instance.function_code.swap(results); | 537 helper.CompileInParallel(&module_env, results, thrower); |
460 } else { | 538 temp_instance.function_code.swap(results); |
461 helper.CompileSequentially(&module_env, temp_instance.function_code, | 539 } else { |
462 thrower); | 540 helper.CompileSequentially(&module_env, temp_instance.function_code, |
| 541 thrower); |
| 542 } |
| 543 if (thrower->error()) return {}; |
463 } | 544 } |
464 if (thrower->error()) return {}; | |
465 | 545 |
466 // At this point, compilation has completed. Update the code table. | 546 // At this point, compilation has completed. Update the code table. |
467 for (size_t i = FLAG_skip_compiling_wasm_funcs; | 547 for (size_t i = FLAG_skip_compiling_wasm_funcs; |
468 i < temp_instance.function_code.size(); ++i) { | 548 i < temp_instance.function_code.size(); ++i) { |
469 Code* code = *temp_instance.function_code[i]; | 549 Code* code = *temp_instance.function_code[i]; |
470 code_table->set(static_cast<int>(i), code); | 550 code_table->set(static_cast<int>(i), code); |
471 RecordStats(isolate_, code); | 551 RecordStats(isolate_, code); |
472 } | 552 } |
473 | 553 |
474 // Create heap objects for script, module bytes and asm.js offset table to | 554 // Create heap objects for script, module bytes and asm.js offset table to |
(...skipping 20 matching lines...) Expand all Loading... |
495 DCHECK(module_bytes->IsSeqOneByteString()); | 575 DCHECK(module_bytes->IsSeqOneByteString()); |
496 | 576 |
497 // Create the shared module data. | 577 // Create the shared module data. |
498 // TODO(clemensh): For the same module (same bytes / same hash), we should | 578 // TODO(clemensh): For the same module (same bytes / same hash), we should |
499 // only have one WasmSharedModuleData. Otherwise, we might only set | 579 // only have one WasmSharedModuleData. Otherwise, we might only set |
500 // breakpoints on a (potentially empty) subset of the instances. | 580 // breakpoints on a (potentially empty) subset of the instances. |
501 | 581 |
502 Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New( | 582 Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New( |
503 isolate_, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes), | 583 isolate_, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes), |
504 script, asm_js_offset_table); | 584 script, asm_js_offset_table); |
| 585 if (lazy_compile) WasmSharedModuleData::PrepareForLazyCompilation(shared); |
505 | 586 |
506 // Create the compiled module object, and populate with compiled functions | 587 // Create the compiled module object, and populate with compiled functions |
507 // and information needed at instantiation time. This object needs to be | 588 // and information needed at instantiation time. This object needs to be |
508 // serializable. Instantiation may occur off a deserialized version of this | 589 // serializable. Instantiation may occur off a deserialized version of this |
509 // object. | 590 // object. |
510 Handle<WasmCompiledModule> compiled_module = | 591 Handle<WasmCompiledModule> compiled_module = |
511 WasmCompiledModule::New(isolate_, shared); | 592 WasmCompiledModule::New(isolate_, shared); |
512 compiled_module->set_num_imported_functions( | 593 compiled_module->set_num_imported_functions( |
513 module_->num_imported_functions); | 594 module_->num_imported_functions); |
514 compiled_module->set_code_table(code_table); | 595 compiled_module->set_code_table(code_table); |
(...skipping 10 matching lines...) Expand all Loading... |
525 if (asm_js_script.is_null()) { | 606 if (asm_js_script.is_null()) { |
526 script->set_wasm_compiled_module(*compiled_module); | 607 script->set_wasm_compiled_module(*compiled_module); |
527 isolate_->debug()->OnAfterCompile(script); | 608 isolate_->debug()->OnAfterCompile(script); |
528 } | 609 } |
529 | 610 |
530 // Compile JS->WASM wrappers for exported functions. | 611 // Compile JS->WASM wrappers for exported functions. |
531 JSToWasmWrapperCache js_to_wasm_cache; | 612 JSToWasmWrapperCache js_to_wasm_cache; |
532 int func_index = 0; | 613 int func_index = 0; |
533 for (auto exp : module_->export_table) { | 614 for (auto exp : module_->export_table) { |
534 if (exp.kind != kExternalFunction) continue; | 615 if (exp.kind != kExternalFunction) continue; |
535 Handle<Code> wasm_code(Code::cast(code_table->get(exp.index)), isolate_); | 616 Handle<Code> wasm_code = EnsureExportedLazyDeoptData( |
| 617 isolate_, Handle<WasmInstanceObject>::null(), code_table, exp.index); |
536 Handle<Code> wrapper_code = | 618 Handle<Code> wrapper_code = |
537 js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(isolate_, module_, | 619 js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(isolate_, module_, |
538 wasm_code, exp.index); | 620 wasm_code, exp.index); |
539 int export_index = | 621 int export_index = |
540 static_cast<int>(module_->functions.size() + func_index); | 622 static_cast<int>(module_->functions.size() + func_index); |
541 code_table->set(export_index, *wrapper_code); | 623 code_table->set(export_index, *wrapper_code); |
542 RecordStats(isolate_, *wrapper_code); | 624 RecordStats(isolate_, *wrapper_code); |
543 func_index++; | 625 func_index++; |
544 } | 626 } |
545 | 627 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 handle(empty_function_tables->get(i), isolate)); | 670 handle(empty_function_tables->get(i), isolate)); |
589 } | 671 } |
590 compiled_module->set_ptr_to_function_tables(empty_function_tables); | 672 compiled_module->set_ptr_to_function_tables(empty_function_tables); |
591 } | 673 } |
592 | 674 |
593 FixedArray* functions = FixedArray::cast(fct_obj); | 675 FixedArray* functions = FixedArray::cast(fct_obj); |
594 for (int i = compiled_module->num_imported_functions(), | 676 for (int i = compiled_module->num_imported_functions(), |
595 end = functions->length(); | 677 end = functions->length(); |
596 i < end; ++i) { | 678 i < end; ++i) { |
597 Code* code = Code::cast(functions->get(i)); | 679 Code* code = Code::cast(functions->get(i)); |
| 680 // Skip lazy compile stubs. |
| 681 if (code->builtin_index() == Builtins::kWasmCompileLazy) continue; |
598 if (code->kind() != Code::WASM_FUNCTION) { | 682 if (code->kind() != Code::WASM_FUNCTION) { |
599 // From here on, there should only be wrappers for exported functions. | 683 // From here on, there should only be wrappers for exported functions. |
600 for (; i < end; ++i) { | 684 for (; i < end; ++i) { |
601 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, | 685 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, |
602 Code::cast(functions->get(i))->kind()); | 686 Code::cast(functions->get(i))->kind()); |
603 } | 687 } |
604 break; | 688 break; |
605 } | 689 } |
606 bool changed = | 690 bool changed = |
607 code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH); | 691 code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 Handle<WasmCompiledModule> compiled_module, int func_index) { | 817 Handle<WasmCompiledModule> compiled_module, int func_index) { |
734 WasmModule* module = compiled_module->module(); | 818 WasmModule* module = compiled_module->module(); |
735 if (func_index < 0 || | 819 if (func_index < 0 || |
736 static_cast<size_t>(func_index) > module->functions.size()) { | 820 static_cast<size_t>(func_index) > module->functions.size()) { |
737 return {0, 0}; | 821 return {0, 0}; |
738 } | 822 } |
739 WasmFunction& func = module->functions[func_index]; | 823 WasmFunction& func = module->functions[func_index]; |
740 return {static_cast<int>(func.code_start_offset), | 824 return {static_cast<int>(func.code_start_offset), |
741 static_cast<int>(func.code_end_offset - func.code_start_offset)}; | 825 static_cast<int>(func.code_end_offset - func.code_start_offset)}; |
742 } | 826 } |
| 827 |
743 } // namespace | 828 } // namespace |
744 | 829 |
745 Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store, | 830 Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store, |
746 size_t size, bool is_external, | 831 size_t size, bool is_external, |
747 bool enable_guard_regions) { | 832 bool enable_guard_regions) { |
748 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); | 833 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
749 JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, | 834 JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, |
750 static_cast<int>(size)); | 835 static_cast<int>(size)); |
751 buffer->set_is_neuterable(false); | 836 buffer->set_is_neuterable(false); |
752 buffer->set_has_guard_region(enable_guard_regions); | 837 buffer->set_has_guard_region(enable_guard_regions); |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 // Avoid creating too many handles in the outer scope. | 1106 // Avoid creating too many handles in the outer scope. |
1022 HandleScope scope(isolate_); | 1107 HandleScope scope(isolate_); |
1023 | 1108 |
1024 // Clone the code for WASM functions and exports. | 1109 // Clone the code for WASM functions and exports. |
1025 for (int i = 0; i < code_table->length(); ++i) { | 1110 for (int i = 0; i < code_table->length(); ++i) { |
1026 Handle<Code> orig_code(Code::cast(code_table->get(i)), isolate_); | 1111 Handle<Code> orig_code(Code::cast(code_table->get(i)), isolate_); |
1027 switch (orig_code->kind()) { | 1112 switch (orig_code->kind()) { |
1028 case Code::WASM_TO_JS_FUNCTION: | 1113 case Code::WASM_TO_JS_FUNCTION: |
1029 // Imports will be overwritten with newly compiled wrappers. | 1114 // Imports will be overwritten with newly compiled wrappers. |
1030 break; | 1115 break; |
| 1116 case Code::BUILTIN: |
| 1117 DCHECK_EQ(Builtins::kWasmCompileLazy, orig_code->builtin_index()); |
| 1118 // If this code object has deoptimization data, then we need a |
| 1119 // unique copy to attach updated deoptimization data. |
| 1120 if (orig_code->deoptimization_data()->length() > 0) { |
| 1121 Handle<Code> code = factory->CopyCode(orig_code); |
| 1122 Handle<FixedArray> deopt_data = |
| 1123 factory->NewFixedArray(2, TENURED); |
| 1124 deopt_data->set(1, Smi::FromInt(i)); |
| 1125 code->set_deoptimization_data(*deopt_data); |
| 1126 code_table->set(i, *code); |
| 1127 } |
| 1128 break; |
1031 case Code::JS_TO_WASM_FUNCTION: | 1129 case Code::JS_TO_WASM_FUNCTION: |
1032 case Code::WASM_FUNCTION: { | 1130 case Code::WASM_FUNCTION: { |
1033 Handle<Code> code = factory->CopyCode(orig_code); | 1131 Handle<Code> code = factory->CopyCode(orig_code); |
1034 code_table->set(i, *code); | 1132 code_table->set(i, *code); |
1035 break; | 1133 break; |
1036 } | 1134 } |
1037 default: | 1135 default: |
1038 UNREACHABLE(); | 1136 UNREACHABLE(); |
1039 } | 1137 } |
1040 } | 1138 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1183 } | 1281 } |
1184 compiled_module_->set_memory(memory_); | 1282 compiled_module_->set_memory(memory_); |
1185 } | 1283 } |
1186 | 1284 |
1187 //-------------------------------------------------------------------------- | 1285 //-------------------------------------------------------------------------- |
1188 // Set up the runtime support for the new instance. | 1286 // Set up the runtime support for the new instance. |
1189 //-------------------------------------------------------------------------- | 1287 //-------------------------------------------------------------------------- |
1190 Handle<WeakCell> weak_link = factory->NewWeakCell(instance); | 1288 Handle<WeakCell> weak_link = factory->NewWeakCell(instance); |
1191 | 1289 |
1192 for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs, | 1290 for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs, |
1193 num_functions = code_table->length(); | 1291 num_functions = static_cast<int>(module_->functions.size()); |
1194 i < num_functions; ++i) { | 1292 i < num_functions; ++i) { |
1195 Handle<Code> code = handle(Code::cast(code_table->get(i)), isolate_); | 1293 Handle<Code> code = handle(Code::cast(code_table->get(i)), isolate_); |
1196 if (code->kind() == Code::WASM_FUNCTION) { | 1294 if (code->kind() == Code::WASM_FUNCTION) { |
1197 Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED); | 1295 Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED); |
1198 deopt_data->set(0, *weak_link); | 1296 deopt_data->set(0, *weak_link); |
1199 deopt_data->set(1, Smi::FromInt(i)); | 1297 deopt_data->set(1, Smi::FromInt(i)); |
1200 code->set_deoptimization_data(*deopt_data); | 1298 code->set_deoptimization_data(*deopt_data); |
| 1299 continue; |
1201 } | 1300 } |
| 1301 DCHECK_EQ(Builtins::kWasmCompileLazy, code->builtin_index()); |
| 1302 if (code->deoptimization_data()->length() == 0) continue; |
| 1303 DCHECK_LE(2, code->deoptimization_data()->length()); |
| 1304 DCHECK_EQ(i, Smi::cast(code->deoptimization_data()->get(1))->value()); |
| 1305 code->deoptimization_data()->set(0, *weak_link); |
1202 } | 1306 } |
1203 | 1307 |
1204 //-------------------------------------------------------------------------- | 1308 //-------------------------------------------------------------------------- |
1205 // Set up the exports object for the new instance. | 1309 // Set up the exports object for the new instance. |
1206 //-------------------------------------------------------------------------- | 1310 //-------------------------------------------------------------------------- |
1207 ProcessExports(code_table, instance, compiled_module_); | 1311 ProcessExports(code_table, instance, compiled_module_); |
1208 | 1312 |
1209 //-------------------------------------------------------------------------- | 1313 //-------------------------------------------------------------------------- |
1210 // Add instance to Memory object | 1314 // Add instance to Memory object |
1211 //-------------------------------------------------------------------------- | 1315 //-------------------------------------------------------------------------- |
1212 DCHECK(wasm::IsWasmInstance(*instance)); | 1316 DCHECK(wasm::IsWasmInstance(*instance)); |
1213 if (instance->has_memory_object()) { | 1317 if (instance->has_memory_object()) { |
1214 instance->memory_object()->AddInstance(isolate_, instance); | 1318 instance->memory_object()->AddInstance(isolate_, instance); |
1215 } | 1319 } |
1216 | 1320 |
1217 //-------------------------------------------------------------------------- | 1321 //-------------------------------------------------------------------------- |
1218 // Initialize the indirect function tables. | 1322 // Initialize the indirect function tables. |
1219 //-------------------------------------------------------------------------- | 1323 //-------------------------------------------------------------------------- |
1220 if (function_table_count > 0) LoadTableSegments(code_table, instance); | 1324 if (function_table_count > 0) LoadTableSegments(code_table, instance); |
1221 | 1325 |
1222 // Patch all code with the relocations registered in code_specialization. | 1326 // Patch all code with the relocations registered in code_specialization. |
1223 { | 1327 code_specialization.RelocateDirectCalls(instance); |
1224 code_specialization.RelocateDirectCalls(instance); | 1328 code_specialization.ApplyToWholeInstance(*instance, SKIP_ICACHE_FLUSH); |
1225 code_specialization.ApplyToWholeInstance(*instance, SKIP_ICACHE_FLUSH); | |
1226 } | |
1227 | 1329 |
1228 FlushICache(isolate_, code_table); | 1330 FlushICache(isolate_, code_table); |
1229 | 1331 |
1230 //-------------------------------------------------------------------------- | 1332 //-------------------------------------------------------------------------- |
1231 // Unpack and notify signal handler of protected instructions. | 1333 // Unpack and notify signal handler of protected instructions. |
1232 //-------------------------------------------------------------------------- | 1334 //-------------------------------------------------------------------------- |
1233 if (FLAG_wasm_trap_handler) { | 1335 if (FLAG_wasm_trap_handler) { |
1234 for (int i = 0; i < code_table->length(); ++i) { | 1336 for (int i = 0; i < code_table->length(); ++i) { |
1235 Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i); | 1337 Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i); |
1236 | 1338 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1298 //-------------------------------------------------------------------------- | 1400 //-------------------------------------------------------------------------- |
1299 WasmSharedModuleData::SetBreakpointsOnNewInstance( | 1401 WasmSharedModuleData::SetBreakpointsOnNewInstance( |
1300 compiled_module_->shared(), instance); | 1402 compiled_module_->shared(), instance); |
1301 | 1403 |
1302 //-------------------------------------------------------------------------- | 1404 //-------------------------------------------------------------------------- |
1303 // Run the start function if one was specified. | 1405 // Run the start function if one was specified. |
1304 //-------------------------------------------------------------------------- | 1406 //-------------------------------------------------------------------------- |
1305 if (module_->start_function_index >= 0) { | 1407 if (module_->start_function_index >= 0) { |
1306 HandleScope scope(isolate_); | 1408 HandleScope scope(isolate_); |
1307 int start_index = module_->start_function_index; | 1409 int start_index = module_->start_function_index; |
1308 Handle<Code> startup_code(Code::cast(code_table->get(start_index)), | 1410 Handle<Code> startup_code = EnsureExportedLazyDeoptData( |
1309 isolate_); | 1411 isolate_, instance, code_table, start_index); |
1310 FunctionSig* sig = module_->functions[start_index].sig; | 1412 FunctionSig* sig = module_->functions[start_index].sig; |
1311 Handle<Code> wrapper_code = | 1413 Handle<Code> wrapper_code = |
1312 js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper( | 1414 js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper( |
1313 isolate_, module_, startup_code, start_index); | 1415 isolate_, module_, startup_code, start_index); |
1314 Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New( | 1416 Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New( |
1315 isolate_, instance, MaybeHandle<String>(), start_index, | 1417 isolate_, instance, MaybeHandle<String>(), start_index, |
1316 static_cast<int>(sig->parameter_count()), wrapper_code); | 1418 static_cast<int>(sig->parameter_count()), wrapper_code); |
1317 RecordStats(isolate_, *startup_code); | 1419 RecordStats(isolate_, *startup_code); |
1318 // Call the JS function. | 1420 // Call the JS function. |
1319 Handle<Object> undefined = factory->undefined_value(); | 1421 Handle<Object> undefined = factory->undefined_value(); |
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2006 table_instance.function_table->length())); | 2108 table_instance.function_table->length())); |
2007 for (int i = 0, e = static_cast<int>(table_init.entries.size()); i < e; | 2109 for (int i = 0, e = static_cast<int>(table_init.entries.size()); i < e; |
2008 ++i) { | 2110 ++i) { |
2009 uint32_t func_index = table_init.entries[i]; | 2111 uint32_t func_index = table_init.entries[i]; |
2010 WasmFunction* function = &module_->functions[func_index]; | 2112 WasmFunction* function = &module_->functions[func_index]; |
2011 int table_index = static_cast<int>(i + base); | 2113 int table_index = static_cast<int>(i + base); |
2012 int32_t sig_index = table.map.Find(function->sig); | 2114 int32_t sig_index = table.map.Find(function->sig); |
2013 DCHECK_GE(sig_index, 0); | 2115 DCHECK_GE(sig_index, 0); |
2014 table_instance.signature_table->set(table_index, | 2116 table_instance.signature_table->set(table_index, |
2015 Smi::FromInt(sig_index)); | 2117 Smi::FromInt(sig_index)); |
2016 table_instance.function_table->set(table_index, | 2118 Handle<Code> wasm_code = EnsureExportedLazyDeoptData( |
2017 code_table->get(func_index)); | 2119 isolate_, instance, code_table, func_index, |
| 2120 table_instance.function_table, table_index); |
| 2121 table_instance.function_table->set(table_index, *wasm_code); |
2018 | 2122 |
2019 if (!all_dispatch_tables.is_null()) { | 2123 if (!all_dispatch_tables.is_null()) { |
2020 Handle<Code> wasm_code(Code::cast(code_table->get(func_index)), | |
2021 isolate_); | |
2022 if (js_wrappers_[func_index].is_null()) { | 2124 if (js_wrappers_[func_index].is_null()) { |
2023 // No JSFunction entry yet exists for this function. Create one. | 2125 // No JSFunction entry yet exists for this function. Create one. |
2024 // TODO(titzer): We compile JS->WASM wrappers for functions are | 2126 // TODO(titzer): We compile JS->WASM wrappers for functions are |
2025 // not exported but are in an exported table. This should be done | 2127 // not exported but are in an exported table. This should be done |
2026 // at module compile time and cached instead. | 2128 // at module compile time and cached instead. |
2027 WasmInstance temp_instance(module_); | 2129 WasmInstance temp_instance(module_); |
2028 temp_instance.context = isolate_->native_context(); | 2130 temp_instance.context = isolate_->native_context(); |
2029 temp_instance.mem_size = 0; | 2131 temp_instance.mem_size = 0; |
2030 temp_instance.mem_start = nullptr; | 2132 temp_instance.mem_start = nullptr; |
2031 temp_instance.globals_start = nullptr; | 2133 temp_instance.globals_start = nullptr; |
(...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2721 Handle<String> module_property_name = | 2823 Handle<String> module_property_name = |
2722 isolate->factory()->InternalizeUtf8String("module"); | 2824 isolate->factory()->InternalizeUtf8String("module"); |
2723 Handle<String> instance_property_name = | 2825 Handle<String> instance_property_name = |
2724 isolate->factory()->InternalizeUtf8String("instance"); | 2826 isolate->factory()->InternalizeUtf8String("instance"); |
2725 JSObject::AddProperty(ret, module_property_name, module, NONE); | 2827 JSObject::AddProperty(ret, module_property_name, module, NONE); |
2726 JSObject::AddProperty(ret, instance_property_name, | 2828 JSObject::AddProperty(ret, instance_property_name, |
2727 instance_object.ToHandleChecked(), NONE); | 2829 instance_object.ToHandleChecked(), NONE); |
2728 | 2830 |
2729 ResolvePromise(isolate, promise, ret); | 2831 ResolvePromise(isolate, promise, ret); |
2730 } | 2832 } |
| 2833 |
| 2834 Handle<Code> wasm::CompileLazy(Isolate* isolate) { |
| 2835 HistogramTimerScope lazy_time_scope( |
| 2836 isolate->counters()->asm_wasm_lazy_compilation_time()); |
| 2837 |
| 2838 // Find the wasm frame which triggered the lazy compile, to get the wasm |
| 2839 // instance. |
| 2840 StackFrameIterator it(isolate); |
| 2841 // First frame: C entry stub. |
| 2842 DCHECK(!it.done()); |
| 2843 DCHECK_EQ(StackFrame::EXIT, it.frame()->type()); |
| 2844 it.Advance(); |
| 2845 // Second frame: WasmCompileLazy builtin. |
| 2846 DCHECK(!it.done()); |
| 2847 Handle<Code> lazy_compile_code(it.frame()->LookupCode(), isolate); |
| 2848 DCHECK_EQ(Builtins::kWasmCompileLazy, lazy_compile_code->builtin_index()); |
| 2849 Handle<WasmInstanceObject> instance; |
| 2850 Handle<FixedArray> exp_deopt_data; |
| 2851 int func_index = -1; |
| 2852 if (lazy_compile_code->deoptimization_data()->length() > 0) { |
| 2853 // Then it's an indirect call or via JS->WASM wrapper. |
| 2854 DCHECK_LE(2, lazy_compile_code->deoptimization_data()->length()); |
| 2855 exp_deopt_data = handle(lazy_compile_code->deoptimization_data(), isolate); |
| 2856 auto* weak_cell = WeakCell::cast(exp_deopt_data->get(0)); |
| 2857 instance = handle(WasmInstanceObject::cast(weak_cell->value()), isolate); |
| 2858 func_index = Smi::cast(exp_deopt_data->get(1))->value(); |
| 2859 } |
| 2860 it.Advance(); |
| 2861 // Third frame: The calling wasm code. |
| 2862 DCHECK(!it.done()); |
| 2863 DCHECK(it.frame()->is_js_to_wasm() || it.frame()->is_wasm_compiled()); |
| 2864 Handle<Code> caller_code = handle(it.frame()->LookupCode(), isolate); |
| 2865 if (it.frame()->is_js_to_wasm()) { |
| 2866 DCHECK(!instance.is_null()); |
| 2867 } else if (instance.is_null()) { |
| 2868 instance = handle(wasm::GetOwningWasmInstance(*caller_code), isolate); |
| 2869 } else { |
| 2870 DCHECK(*instance == wasm::GetOwningWasmInstance(*caller_code)); |
| 2871 } |
| 2872 int offset = |
| 2873 static_cast<int>(it.frame()->pc() - caller_code->instruction_start()); |
| 2874 // Only patch the caller code if this is *no* indirect call. |
| 2875 // exp_deopt_data will be null if the called function is not exported at all, |
| 2876 // and its length will be <= 2 if all entries in tables were already patched. |
| 2877 // Note that this check is conservative: If the first call to an exported |
| 2878 // function is direct, we will just patch the export tables, and only on the |
| 2879 // second call we will patch the caller. |
| 2880 bool patch_caller = caller_code->kind() == Code::JS_TO_WASM_FUNCTION || |
| 2881 exp_deopt_data.is_null() || exp_deopt_data->length() <= 2; |
| 2882 |
| 2883 MaybeHandle<Code> maybe_compiled_code = WasmCompiledModule::CompileLazy( |
| 2884 isolate, instance, caller_code, offset, func_index, patch_caller); |
| 2885 if (maybe_compiled_code.is_null()) { |
| 2886 DCHECK(isolate->has_pending_exception()); |
| 2887 return isolate->builtins()->Illegal(); |
| 2888 } |
| 2889 Handle<Code> compiled_code = maybe_compiled_code.ToHandleChecked(); |
| 2890 if (!exp_deopt_data.is_null() && exp_deopt_data->length() > 2) { |
| 2891 for (int idx = 2, end = exp_deopt_data->length(); idx < end; idx += 2) { |
| 2892 if (exp_deopt_data->get(idx)->IsUndefined(isolate)) break; |
| 2893 FixedArray* exp_table = FixedArray::cast(exp_deopt_data->get(idx)); |
| 2894 int exp_index = Smi::cast(exp_deopt_data->get(idx + 1))->value(); |
| 2895 DCHECK(exp_table->get(exp_index) == *lazy_compile_code); |
| 2896 exp_table->set(exp_index, *compiled_code); |
| 2897 } |
| 2898 // After processing, remove the list of exported entries, such that we don't |
| 2899 // do the patching redundantly. |
| 2900 Handle<FixedArray> new_deopt_data = |
| 2901 isolate->factory()->CopyFixedArrayUpTo(exp_deopt_data, 2, TENURED); |
| 2902 lazy_compile_code->set_deoptimization_data(*new_deopt_data); |
| 2903 } |
| 2904 |
| 2905 return compiled_code; |
| 2906 } |
OLD | NEW |