[wasm] Fix importing wasm-lazy-compile stubs

If two modules use lazy compilation, and one imports a function of
another, we are unwrapping the js-to-wasm wrapper of the export. This
was failing so far, because during unwrapping we did not find the wasm
code.
This CL fixes this by also recognizing WasmCompileLazy stubs as "wasm
code".

R=ahaas@chromium.org

Bug: chromium:779569, v8:5991
Change-Id: If2260c3721e3746a7635b9d0182fd520df2fb773
Reviewed-on: https://chromium-review.googlesource.com/771672
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49405}
This commit is contained in:
Clemens Hammacher 2017-11-16 11:40:42 +01:00 committed by Commit Bot
parent f139f17e59
commit 77b0baa649
3 changed files with 60 additions and 8 deletions

View File

@ -615,8 +615,10 @@ Handle<Code> CompileLazy(Isolate* isolate) {
Handle<WasmInstanceObject> instance;
Handle<FixedArray> exp_deopt_data;
int func_index = -1;
// If the lazy compile stub has deopt data, use that to determine the
// instance and function index. Otherwise this must be a wasm->wasm call
// within one instance, so extract the information from the caller.
if (lazy_compile_code->deoptimization_data()->length() > 0) {
// Then it's an indirect call or via JS->wasm wrapper.
DCHECK_LE(2, lazy_compile_code->deoptimization_data()->length());
exp_deopt_data = handle(lazy_compile_code->deoptimization_data(), isolate);
auto* weak_cell = WeakCell::cast(exp_deopt_data->get(0));

View File

@ -679,20 +679,21 @@ Handle<Code> WasmExportedFunction::GetWasmCode() {
Handle<Code> export_wrapper_code = handle(this->code());
DCHECK_EQ(export_wrapper_code->kind(), Code::JS_TO_WASM_FUNCTION);
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
auto IsWasmFunctionCode = [](Code* code) {
return code->kind() == Code::WASM_FUNCTION ||
code->kind() == Code::WASM_TO_JS_FUNCTION ||
code->kind() == Code::WASM_INTERPRETER_ENTRY ||
code->builtin_index() == Builtins::kWasmCompileLazy;
};
for (RelocIterator it(*export_wrapper_code, mask);; it.next()) {
DCHECK(!it.done());
Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (target->kind() != Code::WASM_FUNCTION &&
target->kind() != Code::WASM_TO_JS_FUNCTION &&
target->kind() != Code::WASM_INTERPRETER_ENTRY)
continue;
if (!IsWasmFunctionCode(target)) continue;
// There should only be this one call to wasm code.
#ifdef DEBUG
for (it.next(); !it.done(); it.next()) {
Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
DCHECK(code->kind() != Code::WASM_FUNCTION &&
code->kind() != Code::WASM_TO_JS_FUNCTION &&
code->kind() != Code::WASM_INTERPRETER_ENTRY);
DCHECK(!IsWasmFunctionCode(code));
}
#endif
return handle(target);

View File

@ -0,0 +1,49 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --wasm-lazy-compilation
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
(function importFromOtherInstance() {
print(arguments.callee.name);
const builder1 = new WasmModuleBuilder();
builder1.addFunction('func', kSig_v_v).addBody([]).exportFunc();
const instance1 = builder1.instantiate();
const builder2 = new WasmModuleBuilder();
builder2.addImport('mod', 'fn', kSig_v_v);
builder2.instantiate({mod: {fn: instance1.exports.func}});
})();
(function testWasmToWasmWithDifferentMemory() {
print(arguments.callee.name);
const builder1 = new WasmModuleBuilder();
builder1.addMemory(1, 1, true);
builder1.addFunction('store', kSig_v_i)
.addBody([
kExprI32Const, 0, // i32.const 1
kExprGetLocal, 0, // get_local 0
kExprI32StoreMem, 0, 0, // i32.store offset=0 align=0
])
.exportFunc();
const instance1 = builder1.instantiate();
const mem1 = new Int32Array(instance1.exports.memory.buffer);
const builder2 = new WasmModuleBuilder();
builder2.addMemory(1, 1, true);
builder2.addImport('mod', 'store', kSig_v_i);
builder2.addFunction('call_store', kSig_v_i)
.addBody([kExprGetLocal, 0, kExprCallFunction, 0])
.exportFunc();
const instance2 = builder2.instantiate({mod: {store: instance1.exports.store}});
const mem2 = new Int32Array(instance2.exports.memory.buffer);
assertEquals(0, mem1[0]);
assertEquals(0, mem2[0]);
instance2.exports.call_store(3);
assertEquals(3, mem1[0]);
assertEquals(0, mem2[0]);
})();