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

Side by Side Diff: src/wasm/wasm-objects.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-objects.h ('k') | no next file » | 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 "src/wasm/wasm-objects.h" 5 #include "src/wasm/wasm-objects.h"
6 #include "src/utils.h" 6 #include "src/utils.h"
7 7
8 #include "src/assembler-inl.h"
8 #include "src/base/iterator.h" 9 #include "src/base/iterator.h"
10 #include "src/compiler/wasm-compiler.h"
9 #include "src/debug/debug-interface.h" 11 #include "src/debug/debug-interface.h"
10 #include "src/objects-inl.h" 12 #include "src/objects-inl.h"
11 #include "src/wasm/module-decoder.h" 13 #include "src/wasm/module-decoder.h"
14 #include "src/wasm/wasm-code-specialization.h"
12 #include "src/wasm/wasm-module.h" 15 #include "src/wasm/wasm-module.h"
13 #include "src/wasm/wasm-text.h" 16 #include "src/wasm/wasm-text.h"
14 17
15 #define TRACE(...) \ 18 #define TRACE(...) \
16 do { \ 19 do { \
17 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ 20 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
18 } while (false) 21 } while (false)
19 22
20 #define TRACE_CHAIN(instance) \ 23 #define TRACE_CHAIN(instance) \
21 do { \ 24 do { \
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 module_start + func.code_end_offset, &locals); 210 module_start + func.code_end_offset, &locals);
208 DCHECK_LT(0, locals.encoded_size); 211 DCHECK_LT(0, locals.encoded_size);
209 for (uint32_t offset : iterator.offsets()) { 212 for (uint32_t offset : iterator.offsets()) {
210 if (offset > static_cast<uint32_t>(offset_in_func)) break; 213 if (offset > static_cast<uint32_t>(offset_in_func)) break;
211 if (offset == static_cast<uint32_t>(offset_in_func)) return true; 214 if (offset == static_cast<uint32_t>(offset_in_func)) return true;
212 } 215 }
213 return false; 216 return false;
214 } 217 }
215 #endif // DEBUG 218 #endif // DEBUG
216 219
220 int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
221 int offset) {
222 DCHECK(!iterator.done());
223 int byte_pos;
224 do {
225 byte_pos = iterator.source_position().ScriptOffset();
226 iterator.Advance();
227 } while (!iterator.done() && iterator.code_offset() <= offset);
228 return byte_pos;
229 }
230
231 int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
232 DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc));
233 decoder.Reset(pc + 1, pc + 6);
234 uint32_t call_idx = decoder.consume_u32v("call index");
235 DCHECK(decoder.ok());
236 DCHECK_GE(kMaxInt, call_idx);
237 return static_cast<int>(call_idx);
238 }
239
240 static void RecordLazyCodeStats(Isolate* isolate, Code* code) {
241 isolate->counters()->asm_wasm_lazily_compiled_functions()->Increment();
242 isolate->counters()->wasm_generated_code_size()->Increment(code->body_size());
243 isolate->counters()->wasm_reloc_size()->Increment(
244 code->relocation_info()->length());
245 }
246
247 class LazyCompilationOrchestrator {
248 bool CompileFunction(Isolate* isolate, Handle<WasmInstanceObject> instance,
249 int func_index) WARN_UNUSED_RESULT {
250 Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
251 isolate);
252 if (Code::cast(compiled_module->code_table()->get(func_index))->kind() ==
253 Code::WASM_FUNCTION) {
254 return true;
255 }
256 wasm::ModuleEnv module_env(compiled_module->module(), nullptr);
257 // TODO(clemensh): Remove this; it's not concurrency-safe.
258 std::vector<Handle<FixedArray>> fun_tables;
259 std::vector<Handle<FixedArray>> sig_tables;
260 size_t num_function_tables =
261 compiled_module->module()->function_tables.size();
262 for (size_t i = 0; i < num_function_tables; ++i) {
263 fun_tables.push_back(isolate->factory()->NewFixedArray(1));
264 sig_tables.push_back(isolate->factory()->NewFixedArray(1));
265 }
266 module_env.function_tables = &fun_tables;
267 module_env.signature_tables = &sig_tables;
268 uint8_t* module_start = compiled_module->module_bytes()->GetChars();
269 const WasmFunction* func = &module_env.module->functions[func_index];
270 wasm::FunctionBody body{func->sig, module_start,
271 module_start + func->code_start_offset,
272 module_start + func->code_end_offset};
273 wasm::WasmName name = Vector<const char>::cast(
274 compiled_module->GetRawFunctionName(func_index));
275 ErrorThrower thrower(isolate, "WasmLazyCompile");
276 compiler::WasmCompilationUnit unit(isolate, &module_env, body, name,
277 func_index);
278 unit.ExecuteCompilation();
279 Handle<Code> code = unit.FinishCompilation(&thrower);
280
281 Handle<FixedArray> deopt_data =
282 isolate->factory()->NewFixedArray(2, TENURED);
283 Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
284 deopt_data->set(0, *weak_instance);
285 deopt_data->set(1, Smi::FromInt(func_index));
286 code->set_deoptimization_data(*deopt_data);
287
288 if (thrower.error()) {
289 if (!isolate->has_pending_exception()) isolate->Throw(*thrower.Reify());
290 return false;
291 }
292
293 DCHECK_EQ(Builtins::kWasmCompileLazy,
294 Code::cast(compiled_module->code_table()->get(func_index))
295 ->builtin_index());
296 compiled_module->code_table()->set(func_index, *code);
297
298 // Now specialize the generated code for this instance.
299 Zone specialization_zone(isolate->allocator(), ZONE_NAME);
300 CodeSpecialization code_specialization(isolate, &specialization_zone);
301 if (module_env.module->globals_size) {
302 Address globals_start = reinterpret_cast<Address>(
303 instance->globals_buffer()->backing_store());
304 code_specialization.RelocateGlobals(nullptr, globals_start);
305 }
306 if (instance->has_memory_buffer()) {
307 Address mem_start =
308 reinterpret_cast<Address>(instance->memory_buffer()->backing_store());
309 int mem_size = instance->memory_buffer()->byte_length()->Number();
310 DCHECK_IMPLIES(mem_size == 0, mem_start == nullptr);
311 if (mem_size > 0) {
312 code_specialization.RelocateMemoryReferences(nullptr, 0, mem_start,
313 mem_size);
314 }
315 }
316 code_specialization.RelocateDirectCalls(instance);
317 if (module_env.used_indirect_tables) {
318 for (size_t i = 0; i < num_function_tables; ++i) {
319 Handle<Object> new_fun_table(
320 compiled_module->function_tables()->get(static_cast<int>(i)),
321 isolate);
322 code_specialization.RelocateObject(fun_tables[i], new_fun_table);
323 Handle<Object> new_sig_table(
324 compiled_module->signature_tables()->get(static_cast<int>(i)),
325 isolate);
326 code_specialization.RelocateObject(sig_tables[i], new_sig_table);
327 }
328 }
329 code_specialization.ApplyToWasmCode(*code, SKIP_ICACHE_FLUSH);
330 Assembler::FlushICache(isolate, code->instruction_start(),
331 code->instruction_size());
332 RecordLazyCodeStats(isolate, *code);
333 return true;
334 }
335
336 public:
337 MaybeHandle<Code> CompileLazy(Isolate* isolate,
338 Handle<WasmInstanceObject> instance,
339 Handle<Code> caller, int call_offset,
340 int exported_func_index, bool patch_caller) {
341 struct NonCompiledFunction {
342 int offset;
343 int func_index;
344 };
345 std::vector<NonCompiledFunction> non_compiled_functions;
346 int func_to_return_idx = exported_func_index;
347 wasm::Decoder decoder(nullptr, nullptr);
348 bool is_js_to_wasm = caller->kind() == Code::JS_TO_WASM_FUNCTION;
349 Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
350 isolate);
351
352 if (is_js_to_wasm) {
353 non_compiled_functions.push_back({0, exported_func_index});
354 } else if (patch_caller) {
355 DisallowHeapAllocation no_gc;
356 SeqOneByteString* module_bytes = compiled_module->module_bytes();
357 SourcePositionTableIterator source_pos_iterator(
358 caller->source_position_table());
359 DCHECK_EQ(2, caller->deoptimization_data()->length());
360 int caller_func_index =
361 Smi::cast(caller->deoptimization_data()->get(1))->value();
362 const byte* func_bytes =
363 module_bytes->GetChars() + compiled_module->module()
364 ->functions[caller_func_index]
365 .code_start_offset;
366 for (RelocIterator it(*caller, RelocInfo::kCodeTargetMask); !it.done();
367 it.next()) {
368 Code* callee =
369 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
370 if (callee->builtin_index() != Builtins::kWasmCompileLazy) continue;
371 size_t offset_l = it.rinfo()->pc() - caller->instruction_start();
372 DCHECK_GE(kMaxInt, offset_l);
373 int offset = static_cast<int>(offset_l);
374 int byte_pos =
375 AdvanceSourcePositionTableIterator(source_pos_iterator, offset);
376 int called_func_index =
377 ExtractDirectCallIndex(decoder, func_bytes + byte_pos);
378 non_compiled_functions.push_back({offset, called_func_index});
379 // Call offset one instruction after the call. Remember the last called
380 // function before that offset.
381 if (offset < call_offset) func_to_return_idx = called_func_index;
382 }
383 }
384
385 // TODO(clemensh): compile all functions in non_compiled_functions in
386 // background, wait for func_to_return_idx.
387 if (!CompileFunction(isolate, instance, func_to_return_idx)) {
388 return {};
389 }
390
391 if (is_js_to_wasm || patch_caller) {
392 DisallowHeapAllocation no_gc;
393 // Now patch the code object with all functions which are now compiled.
394 int idx = 0;
395 for (RelocIterator it(*caller, RelocInfo::kCodeTargetMask); !it.done();
396 it.next()) {
397 Code* callee =
398 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
399 if (callee->builtin_index() != Builtins::kWasmCompileLazy) continue;
400 DCHECK_GT(non_compiled_functions.size(), idx);
401 int called_func_index = non_compiled_functions[idx].func_index;
402 if (callee->deoptimization_data()->length() > 0) {
403 DCHECK_EQ(called_func_index,
404 Smi::cast(callee->deoptimization_data()->get(1))->value());
405 }
406 if (is_js_to_wasm) {
407 DCHECK_EQ(func_to_return_idx, called_func_index);
408 } else {
409 DCHECK_EQ(non_compiled_functions[idx].offset,
410 it.rinfo()->pc() - caller->instruction_start());
411 }
412 ++idx;
413 Handle<Code> callee_compiled(
414 Code::cast(compiled_module->code_table()->get(called_func_index)));
415 if (callee_compiled->builtin_index() == Builtins::kWasmCompileLazy) {
416 DCHECK_NE(func_to_return_idx, called_func_index);
417 continue;
418 }
419 DCHECK_EQ(Code::WASM_FUNCTION, callee_compiled->kind());
420 it.rinfo()->set_target_address(callee_compiled->instruction_start());
421 }
422 DCHECK_EQ(non_compiled_functions.size(), idx);
423 }
424
425 Code* ret =
426 Code::cast(compiled_module->code_table()->get(func_to_return_idx));
427 DCHECK_EQ(Code::WASM_FUNCTION, ret->kind());
428 return handle(ret, isolate);
429 }
430 };
431
217 } // namespace 432 } // namespace
218 433
219 Handle<WasmModuleObject> WasmModuleObject::New( 434 Handle<WasmModuleObject> WasmModuleObject::New(
220 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) { 435 Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
221 ModuleOrigin origin = compiled_module->module()->origin; 436 ModuleOrigin origin = compiled_module->module()->origin;
222 437
223 Handle<JSObject> module_object; 438 Handle<JSObject> module_object;
224 if (origin == ModuleOrigin::kWasmOrigin) { 439 if (origin == ModuleOrigin::kWasmOrigin) {
225 Handle<JSFunction> module_cons( 440 Handle<JSFunction> module_cons(
226 isolate->native_context()->wasm_module_constructor()); 441 isolate->native_context()->wasm_module_constructor());
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 Foreign::cast(get(kModuleWrapper))->foreign_address())); 755 Foreign::cast(get(kModuleWrapper))->foreign_address()));
541 } 756 }
542 757
543 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes, 758 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
544 SeqOneByteString); 759 SeqOneByteString);
545 DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script); 760 DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
546 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table, 761 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
547 kAsmJsOffsetTable, ByteArray); 762 kAsmJsOffsetTable, ByteArray);
548 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos, 763 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
549 kBreakPointInfos, FixedArray); 764 kBreakPointInfos, FixedArray);
765 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, lazy_compilation_orchestrator,
766 kLazyCompilationOrchestrator, Foreign);
550 767
551 Handle<WasmSharedModuleData> WasmSharedModuleData::New( 768 Handle<WasmSharedModuleData> WasmSharedModuleData::New(
552 Isolate* isolate, Handle<Foreign> module_wrapper, 769 Isolate* isolate, Handle<Foreign> module_wrapper,
553 Handle<SeqOneByteString> module_bytes, Handle<Script> script, 770 Handle<SeqOneByteString> module_bytes, Handle<Script> script,
554 Handle<ByteArray> asm_js_offset_table) { 771 Handle<ByteArray> asm_js_offset_table) {
555 Handle<FixedArray> arr = 772 Handle<FixedArray> arr =
556 isolate->factory()->NewFixedArray(kFieldCount, TENURED); 773 isolate->factory()->NewFixedArray(kFieldCount, TENURED);
557 774
558 arr->set(kModuleWrapper, *module_wrapper); 775 arr->set(kModuleWrapper, *module_wrapper);
559 if (!module_bytes.is_null()) { 776 if (!module_bytes.is_null()) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 946
730 // Find the function for this breakpoint, and set the breakpoint. 947 // Find the function for this breakpoint, and set the breakpoint.
731 int func_index = compiled_module->GetContainingFunction(position); 948 int func_index = compiled_module->GetContainingFunction(position);
732 DCHECK_LE(0, func_index); 949 DCHECK_LE(0, func_index);
733 WasmFunction& func = compiled_module->module()->functions[func_index]; 950 WasmFunction& func = compiled_module->module()->functions[func_index];
734 int offset_in_func = position - func.code_start_offset; 951 int offset_in_func = position - func.code_start_offset;
735 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func); 952 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
736 } 953 }
737 } 954 }
738 955
956 void WasmSharedModuleData::PrepareForLazyCompilation(
957 Handle<WasmSharedModuleData> shared) {
958 if (shared->has_lazy_compilation_orchestrator()) return;
959 Isolate* isolate = shared->GetIsolate();
960 LazyCompilationOrchestrator* orch = new LazyCompilationOrchestrator();
961 Handle<Managed<LazyCompilationOrchestrator>> orch_handle =
962 Managed<LazyCompilationOrchestrator>::New(isolate, orch);
963 shared->set(WasmSharedModuleData::kLazyCompilationOrchestrator, *orch_handle);
964 }
965
739 Handle<WasmCompiledModule> WasmCompiledModule::New( 966 Handle<WasmCompiledModule> WasmCompiledModule::New(
740 Isolate* isolate, Handle<WasmSharedModuleData> shared) { 967 Isolate* isolate, Handle<WasmSharedModuleData> shared) {
741 Handle<FixedArray> ret = 968 Handle<FixedArray> ret =
742 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); 969 isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
743 // WasmCompiledModule::cast would fail since fields are not set yet. 970 // WasmCompiledModule::cast would fail since fields are not set yet.
744 Handle<WasmCompiledModule> compiled_module( 971 Handle<WasmCompiledModule> compiled_module(
745 reinterpret_cast<WasmCompiledModule*>(*ret), isolate); 972 reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
746 compiled_module->InitId(); 973 compiled_module->InitId();
747 compiled_module->set_num_imported_functions(0); 974 compiled_module->set_num_imported_functions(0);
748 compiled_module->set_shared(shared); 975 compiled_module->set_shared(shared);
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
1155 if (maybe_breakpoint_info->IsUndefined(isolate)) return {}; 1382 if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1156 Handle<BreakPointInfo> breakpoint_info = 1383 Handle<BreakPointInfo> breakpoint_info =
1157 Handle<BreakPointInfo>::cast(maybe_breakpoint_info); 1384 Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1158 if (breakpoint_info->source_position() != position) return {}; 1385 if (breakpoint_info->source_position() != position) return {};
1159 1386
1160 Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(), 1387 Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
1161 isolate); 1388 isolate);
1162 return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects); 1389 return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
1163 } 1390 }
1164 1391
1392 MaybeHandle<Code> WasmCompiledModule::CompileLazy(
1393 Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller,
1394 int offset, int func_index, bool patch_caller) {
1395 isolate->set_context(*instance->compiled_module()->native_context());
1396 Object* orch_obj =
1397 instance->compiled_module()->shared()->lazy_compilation_orchestrator();
1398 LazyCompilationOrchestrator* orch =
1399 Managed<LazyCompilationOrchestrator>::cast(orch_obj)->get();
1400 return orch->CompileLazy(isolate, instance, caller, offset, func_index,
1401 patch_caller);
1402 }
1403
1165 Handle<WasmInstanceWrapper> WasmInstanceWrapper::New( 1404 Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
1166 Isolate* isolate, Handle<WasmInstanceObject> instance) { 1405 Isolate* isolate, Handle<WasmInstanceObject> instance) {
1167 Handle<FixedArray> array = 1406 Handle<FixedArray> array =
1168 isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED); 1407 isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED);
1169 Handle<WasmInstanceWrapper> instance_wrapper( 1408 Handle<WasmInstanceWrapper> instance_wrapper(
1170 reinterpret_cast<WasmInstanceWrapper*>(*array), isolate); 1409 reinterpret_cast<WasmInstanceWrapper*>(*array), isolate);
1171 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance); 1410 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance);
1172 instance_wrapper->set(kWrapperInstanceObject, *cell); 1411 instance_wrapper->set(kWrapperInstanceObject, *cell);
1173 return instance_wrapper; 1412 return instance_wrapper;
1174 } 1413 }
1175 1414
1176 bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) { 1415 bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
1177 if (!obj->IsFixedArray()) return false; 1416 if (!obj->IsFixedArray()) return false;
1178 Handle<FixedArray> array = handle(FixedArray::cast(obj)); 1417 Handle<FixedArray> array = handle(FixedArray::cast(obj));
1179 if (array->length() != kWrapperPropertyCount) return false; 1418 if (array->length() != kWrapperPropertyCount) return false;
1180 if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false; 1419 if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false;
1181 Isolate* isolate = array->GetIsolate(); 1420 Isolate* isolate = array->GetIsolate();
1182 if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) && 1421 if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) &&
1183 !array->get(kNextInstanceWrapper)->IsFixedArray()) 1422 !array->get(kNextInstanceWrapper)->IsFixedArray())
1184 return false; 1423 return false;
1185 if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) && 1424 if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) &&
1186 !array->get(kPreviousInstanceWrapper)->IsFixedArray()) 1425 !array->get(kPreviousInstanceWrapper)->IsFixedArray())
1187 return false; 1426 return false;
1188 return true; 1427 return true;
1189 } 1428 }
OLDNEW
« no previous file with comments | « src/wasm/wasm-objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698