Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Side by Side Diff: src/wasm/wasm-module.cc

Issue 2731523005: [wasm] Lazy compilation for asm.js (Closed)
Patch Set: [wasm] Lazy compilation for asm.js Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-module.h ('k') | src/wasm/wasm-objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/wasm/wasm-module.h ('k') | src/wasm/wasm-objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698