Added: trunk/JSTests/wasm/function-tests/trap-after-cross-instance-call.js (0 => 214950)
--- trunk/JSTests/wasm/function-tests/trap-after-cross-instance-call.js (rev 0)
+++ trunk/JSTests/wasm/function-tests/trap-after-cross-instance-call.js 2017-04-05 17:19:16 UTC (rev 214950)
@@ -0,0 +1,64 @@
+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+const pageSize = 64 * 1024;
+const numPages = 10;
+
+const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("a", "b", {initial: numPages})
+ .Function("foo", "bar", { params: [], ret: "void" })
+ .End()
+ .Function().End()
+ .Export().Function("foo").End()
+ .Code()
+ .Function("foo", {params: ["i32"], ret: "i32"})
+ .Call(0)
+ .GetLocal(0)
+ .I32Load(2, 0)
+ .Return()
+ .End()
+ .End();
+
+const bin = builder.WebAssembly().get();
+const module = new WebAssembly.Module(bin);
+
+let importObject = {a: {b: new WebAssembly.Memory({initial: numPages})}};
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("a", "b", {initial: numPages})
+ .End()
+ .Function().End()
+ .Export().Function("bar").End()
+ .Code()
+ .Function("bar", { params: [], ret: "void" })
+ .Return()
+ .End()
+ .End();
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+
+ importObject.foo = new WebAssembly.Instance(module, {a: {b: new WebAssembly.Memory({initial: numPages})}}).exports
+}
+
+let foo1 = new WebAssembly.Instance(module, importObject).exports.foo;
+importObject.foo = { bar() { } };
+let foo2 = new WebAssembly.Instance(module, importObject).exports.foo;
+
+
+function wasmFrameCountFromError(e) {
+ let stackFrames = e.stack.split("\n").filter((s) => s.indexOf("<wasm>@[wasm code]") !== -1);
+ return stackFrames.length;
+}
+
+for (let i = 0; i < 1000; i++) {
+ const e1 = assert.throws(() => foo1(numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access");
+ assert.eq(wasmFrameCountFromError(e1), 2);
+ const e2 = assert.throws(() => foo1(numPages * pageSize + 1), WebAssembly.RuntimeError, "Out of bounds memory access");
+ assert.eq(wasmFrameCountFromError(e2), 2);
+}
Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (214949 => 214950)
--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2017-04-05 17:15:55 UTC (rev 214949)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2017-04-05 17:19:16 UTC (rev 214950)
@@ -243,7 +243,7 @@
HashMap<ValueKey, Value*> m_constantPool;
InsertionSet m_constantInsertionValues;
GPRReg m_memoryBaseGPR;
- GPRReg m_memorySizeGPR;
+ GPRReg m_memorySizeGPR { InvalidGPRReg };
GPRReg m_wasmContextGPR;
Value* m_instanceValue; // FIXME: make this lazy https://bugs.webkit.org/show_bug.cgi?id=169792
};
@@ -313,16 +313,21 @@
// FIXME we don't really need to pin registers here if there's no memory. It makes wasm -> wasm thunks simpler for now. https://bugs.webkit.org/show_bug.cgi?id=166623
const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
+
m_memoryBaseGPR = pinnedRegs.baseMemoryPointer;
+ m_proc.pinRegister(m_memoryBaseGPR);
+
m_wasmContextGPR = pinnedRegs.wasmContextPointer;
- m_proc.pinRegister(m_memoryBaseGPR);
if (!useFastTLSForContext())
m_proc.pinRegister(m_wasmContextGPR);
- ASSERT(!pinnedRegs.sizeRegisters[0].sizeOffset);
- m_memorySizeGPR = pinnedRegs.sizeRegisters[0].sizeRegister;
- for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
- m_proc.pinRegister(regInfo.sizeRegister);
+ if (mode != MemoryMode::Signaling) {
+ ASSERT(!pinnedRegs.sizeRegisters[0].sizeOffset);
+ m_memorySizeGPR = pinnedRegs.sizeRegisters[0].sizeRegister;
+ for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
+ m_proc.pinRegister(regInfo.sizeRegister);
+ }
+
if (info.memory) {
m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -903,6 +908,7 @@
[=] (PatchpointValue* patchpoint) {
patchpoint->effects.writesPinned = true;
patchpoint->effects.readsPinned = true;
+ // We need to clobber all potential pinned registers since we might be leaving the instance.
patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -928,6 +934,7 @@
patchpoint->effects.writesPinned = true;
patchpoint->effects.readsPinned = true;
patchpoint->append(jumpDestination, ValueRep::SomeRegister);
+ // We need to clobber all potential pinned registers since we might be leaving the instance.
patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex, returnType] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -1032,6 +1039,7 @@
[=] (PatchpointValue* patchpoint) {
patchpoint->effects.writesPinned = true;
patchpoint->effects.readsPinned = true;
+ // We need to clobber all potential pinned registers since we might be leaving the instance.
patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
patchpoint->append(calleeCode, ValueRep::SomeRegister);
@@ -1088,7 +1096,7 @@
dataLogLn();
}
-static void createJSToWasmWrapper(CompilationContext& compilationContext, WasmInternalFunction& function, const Signature& signature, const ModuleInformation& info)
+static void createJSToWasmWrapper(CompilationContext& compilationContext, WasmInternalFunction& function, const Signature& signature, const ModuleInformation& info, MemoryMode mode)
{
CCallHelpers& jit = *compilationContext.jsEntrypointJIT;
@@ -1104,7 +1112,7 @@
});
const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
- RegisterSet toSave = pinnedRegs.toSave();
+ RegisterSet toSave = pinnedRegs.toSave(mode);
#if !ASSERT_DISABLED
unsigned toSaveSize = toSave.numberOfSetGPRs();
@@ -1230,13 +1238,17 @@
jit.loadWasmContext(baseMemory);
jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
}
- const auto& sizeRegs = pinnedRegs.sizeRegisters;
- ASSERT(sizeRegs.size() >= 1);
- ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
- jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister);
+
+ if (mode != MemoryMode::Signaling) {
+ const auto& sizeRegs = pinnedRegs.sizeRegisters;
+ ASSERT(sizeRegs.size() >= 1);
+ ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
+ jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister);
+ for (unsigned i = 1; i < sizeRegs.size(); ++i)
+ jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
+ }
+
jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory);
- for (unsigned i = 1; i < sizeRegs.size(); ++i)
- jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
}
compilationContext.jsEntrypointToWasmEntrypointCall = jit.call();
@@ -1311,7 +1323,7 @@
result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
}
- createJSToWasmWrapper(compilationContext, *result, signature, info);
+ createJSToWasmWrapper(compilationContext, *result, signature, info, mode);
return WTFMove(result);
}
Modified: trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h (214949 => 214950)
--- trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h 2017-04-05 17:15:55 UTC (rev 214949)
+++ trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h 2017-04-05 17:19:16 UTC (rev 214950)
@@ -48,14 +48,16 @@
static const PinnedRegisterInfo& get();
PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg);
- RegisterSet toSave() const
+ RegisterSet toSave(MemoryMode mode = MemoryMode::BoundsChecking) const
{
RegisterSet result;
result.set(baseMemoryPointer);
if (wasmContextPointer != InvalidGPRReg)
result.set(wasmContextPointer);
- for (const auto& info : sizeRegisters)
- result.set(info.sizeRegister);
+ if (mode != MemoryMode::Signaling) {
+ for (const auto& info : sizeRegisters)
+ result.set(info.sizeRegister);
+ }
return result;
}
};