https://bugs.webkit.org/show_bug.cgi?id=165429
Reviewed by Keith Miller.
JSTests:
* wasm/function-tests/trap-load.js: Added.
(assert):
(wasmFrameCountFromError):
(i.catch):
(assert.continuation):
* wasm/function-tests/trap-store.js: Added.
(import.Builder.from.string_appeared_here.assert):
(i.catch):
(assert.continuation):
(assert):
* wasm/js-api/test_memory_constructor.js:
(assert):
Source/JavaScriptCore:
This patch teaches the stack walking runtime about wasm.
To do this, I taught StackVisitor that a callee is not
always an object.
To be able to unwind callee save registers properly, I've given
JSWebAssemblyCallee a list of RegisterAtOffsetList for the callee
saves that B3 saved in the prologue. Also, because we have two
B3Compilations per wasm function, one for wasm entrypoint, and
one for the JS entrypoint, I needed to create a callee for each
because they each might spill callee save registers.
I also fixed a bug inside the Wasm::Memory constructor where we
were trying to mmap the same number of bytes even after the first
mmap failed. We should start by trying to mmap the maximum bytes,
and if that fails, fall back to the specified initial bytes. However,
the code was just mmapping the maximum twice. I've fixed that and
also added a RELEASE_ASSERT_NOT_REACHED() for when the second mmap
fails along with a FIXME to throw an OOM error.
There was a second bug I fixed where JSModuleRecord was calling
visitWeak on its CallLinkInfos inside ::visitChldren(). It needs
to do this after marking. I changed JSModuleRecord to do what
CodeBlock does and call visitWeak on its CallLinkInfos inside
an UnconditionalFinalizer.
* API/JSContextRef.cpp:
(BacktraceFunctor::operator()):
* inspector/ScriptCallStackFactory.cpp:
(Inspector::createScriptCallStackFromException):
* interpreter/CallFrame.cpp:
(JSC::CallFrame::vmEntryGlobalObject):
* interpreter/CallFrame.h:
(JSC::ExecState::callee):
* interpreter/Interpreter.cpp:
(JSC::GetStackTraceFunctor::operator()):
(JSC::UnwindFunctor::operator()):
(JSC::UnwindFunctor::copyCalleeSavesToVMEntryFrameCalleeSavesBuffer):
* interpreter/Interpreter.h:
* interpreter/ShadowChicken.cpp:
(JSC::ShadowChicken::update):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::StackVisitor):
(JSC::StackVisitor::readFrame):
(JSC::StackVisitor::readNonInlinedFrame):
(JSC::StackVisitor::readInlinedFrame):
(JSC::StackVisitor::Frame::isWasmFrame):
(JSC::StackVisitor::Frame::codeType):
(JSC::StackVisitor::Frame::calleeSaveRegisters):
(JSC::StackVisitor::Frame::functionName):
(JSC::StackVisitor::Frame::sourceURL):
(JSC::StackVisitor::Frame::toString):
(JSC::StackVisitor::Frame::hasLineAndColumnInfo):
(JSC::StackVisitor::Frame::setToEnd):
* interpreter/StackVisitor.h:
(JSC::StackVisitor::Frame::callee):
(JSC::StackVisitor::Frame::isNativeFrame):
(JSC::StackVisitor::Frame::isJSFrame): Deleted.
* jsc.cpp:
(callWasmFunction):
(functionTestWasmModuleFunctions):
* runtime/Error.cpp:
(JSC::addErrorInfoAndGetBytecodeOffset):
* runtime/JSCell.cpp:
(JSC::JSCell::isAnyWasmCallee):
* runtime/JSCell.h:
* runtime/JSFunction.cpp:
(JSC::RetrieveArgumentsFunctor::operator()):
(JSC::RetrieveCallerFunctionFunctor::operator()):
* runtime/StackFrame.cpp:
(JSC::StackFrame::sourceID):
(JSC::StackFrame::sourceURL):
(JSC::StackFrame::functionName):
(JSC::StackFrame::computeLineAndColumn):
(JSC::StackFrame::toString):
* runtime/StackFrame.h:
(JSC::StackFrame::StackFrame):
(JSC::StackFrame::hasLineAndColumnInfo):
(JSC::StackFrame::hasBytecodeOffset):
(JSC::StackFrame::bytecodeOffset):
(JSC::StackFrame::isNative): Deleted.
* runtime/VM.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile):
* wasm/WasmCallingConvention.h:
(JSC::Wasm::CallingConvention::setupFrameInPrologue):
* wasm/WasmFormat.h:
* wasm/WasmMemory.cpp:
(JSC::Wasm::Memory::Memory):
* wasm/WasmMemory.h:
(JSC::Wasm::Memory::isValid):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::run):
(JSC::Wasm::Plan::initializeCallees):
* wasm/WasmPlan.h:
(JSC::Wasm::Plan::jsToWasmEntryPointForFunction): Deleted.
* wasm/js/JSWebAssemblyCallee.cpp:
(JSC::JSWebAssemblyCallee::finishCreation):
* wasm/js/JSWebAssemblyCallee.h:
(JSC::JSWebAssemblyCallee::create):
(JSC::JSWebAssemblyCallee::entrypoint):
(JSC::JSWebAssemblyCallee::calleeSaveRegisters):
(JSC::JSWebAssemblyCallee::jsToWasmEntryPoint): Deleted.
* wasm/js/JSWebAssemblyModule.cpp:
(JSC::JSWebAssemblyModule::JSWebAssemblyModule):
(JSC::JSWebAssemblyModule::visitChildren):
(JSC::JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally):
* wasm/js/JSWebAssemblyModule.h:
(JSC::JSWebAssemblyModule::jsEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyModule::wasmEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyModule::setJSEntrypointCallee):
(JSC::JSWebAssemblyModule::setWasmEntrypointCallee):
(JSC::JSWebAssemblyModule::allocationSize):
(JSC::JSWebAssemblyModule::calleeFromFunctionIndexSpace): Deleted.
* wasm/js/JSWebAssemblyRuntimeError.h:
* wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::call):
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyMemoryConstructor.cpp:
(JSC::constructJSWebAssemblyMemory):
* wasm/js/WebAssemblyModuleConstructor.cpp:
(JSC::constructJSWebAssemblyModule):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
Source/WebCore:
* bindings/js/JSDOMBinding.cpp:
(WebCore::GetCallerGlobalObjectFunctor::operator()):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209696
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-12-11 Saam Barati <sbarati@apple.com>
+
+ We should be able to throw exceptions from Wasm code and when Wasm frames are on the stack
+ https://bugs.webkit.org/show_bug.cgi?id=165429
+
+ Reviewed by Keith Miller.
+
+ * wasm/function-tests/trap-load.js: Added.
+ (assert):
+ (wasmFrameCountFromError):
+ (i.catch):
+ (assert.continuation):
+ * wasm/function-tests/trap-store.js: Added.
+ (import.Builder.from.string_appeared_here.assert):
+ (i.catch):
+ (assert.continuation):
+ (assert):
+ * wasm/js-api/test_memory_constructor.js:
+ (assert):
+
2016-12-10 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r209653, r209654, r209663, and
--- /dev/null
+import Builder from '../Builder.js'
+
+const pageSize = 64 * 1024;
+const numPages = 10;
+
+const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("a", "b", {initial: numPages})
+ .End()
+ .Function().End()
+ .Export().Function("foo").End()
+ .Code()
+ .Function("foo", {params: ["i32"], ret: "i32"})
+ .GetLocal(0)
+ .I32Load(2, 0)
+ .Return()
+ .End()
+ .End();
+
+const bin = builder.WebAssembly().get();
+const module = new WebAssembly.Module(bin);
+const foo = new WebAssembly.Instance(module, {a: {b: new WebAssembly.Memory({initial: numPages})}}).exports.foo;
+
+function assert(b) {
+ if (!b)
+ throw new Error("Bad")
+}
+
+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++) {
+ let threw = false;
+ try {
+ foo(numPages * pageSize + 1);
+ } catch(e) {
+ assert(e instanceof WebAssembly.RuntimeError);
+ assert(e.message === "Out of bounds memory access");
+ threw = true;
+ assert(wasmFrameCountFromError(e) === 2);
+ }
+ assert(threw);
+}
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("imp", "mem", {initial: numPages})
+ .Function("imp", "func", { params: ["i32"] })
+ .End()
+ .Function().End()
+ .Export().Function("foo").End()
+ .Code()
+ .Function("foo", {params: ["i32", "i32"]})
+ .GetLocal(0)
+ .I32Const(0)
+ .I32Eq()
+ .If("void", b =>
+ b.GetLocal(1)
+ .GetLocal(1)
+ .I32Load(2, 0)
+ .Br(0)
+ .Else()
+ .GetLocal(0)
+ .Call(0)
+ .Br(0)
+ )
+ .End()
+ .End();
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const imp = {
+ imp: {
+ mem: new WebAssembly.Memory({initial: numPages}),
+ func: continuation
+ }
+ };
+ const foo = new WebAssembly.Instance(module, imp).exports.foo;
+ const address = numPages*pageSize + 1;
+ function continuation(x) {
+ foo(x - 1, address);
+ }
+
+ for (let i = 0; i < 10000; i++) {
+ let threw = false;
+ try {
+ foo(25, address);
+ } catch(e) {
+ assert(e instanceof WebAssembly.RuntimeError);
+ assert(e.message === "Out of bounds memory access");
+ // There are 25 total calls, and each call does:
+ // JS entry, wasm entry, js call stub.
+ // The last call that traps just has JS entry and wasm entry.
+ assert(wasmFrameCountFromError(e) === 25 * 3 + 2);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
--- /dev/null
+import Builder from '../Builder.js'
+
+function assert(b) {
+ if (!b)
+ throw new Error("Bad")
+}
+
+const pageSize = 64 * 1024;
+const numPages = 10;
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("a", "b", {initial: numPages})
+ .End()
+ .Function().End()
+ .Export().Function("foo").End()
+ .Code()
+ .Function("foo", {params: ["i32", "i32"]})
+ .GetLocal(1)
+ .GetLocal(0)
+ .I32Store(2, 0)
+ .End()
+ .End();
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const foo = new WebAssembly.Instance(module, {a: {b: new WebAssembly.Memory({initial: numPages})}}).exports.foo;
+
+ for (let i = 0; i < 10000; i++) {
+ let threw = false;
+ try {
+ foo(i, numPages * pageSize + 1);
+ } catch(e) {
+ assert(e instanceof WebAssembly.RuntimeError);
+ assert(e.message === "Out of bounds memory access");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Memory("imp", "mem", {initial: numPages})
+ .Function("imp", "func", { params: ["i32"] })
+ .End()
+ .Function().End()
+ .Export().Function("foo").End()
+ .Code()
+ .Function("foo", {params: ["i32", "i32"]})
+ .GetLocal(0)
+ .I32Const(0)
+ .I32Eq()
+ .If("void", b =>
+ b.GetLocal(1)
+ .GetLocal(0)
+ .I32Store(2, 0)
+ .Br(0)
+ .Else()
+ .GetLocal(0)
+ .Call(0)
+ .Br(0)
+ )
+ .End()
+ .End();
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const imp = {
+ imp: {
+ mem: new WebAssembly.Memory({initial: numPages}),
+ func: continuation
+ }
+ };
+ const foo = new WebAssembly.Instance(module, imp).exports.foo;
+ const address = numPages*pageSize + 1;
+ function continuation(x) {
+ foo(x - 1, address);
+ }
+
+ for (let i = 0; i < 10000; i++) {
+ let threw = false;
+ try {
+ foo(25, address);
+ } catch(e) {
+ assert(e instanceof WebAssembly.RuntimeError);
+ assert(e.message === "Out of bounds memory access");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
testInvalidSize({initial: v}, "initial");
}
- // These should not throw.
- new WebAssembly.Memory({initial: maxPageCount});
- new WebAssembly.Memory({initial: maxPageCount, maximum: maxPageCount});
+ try {
+ new WebAssembly.Memory({initial: maxPageCount});
+ new WebAssembly.Memory({initial: maxPageCount, maximum: maxPageCount});
+ } catch(e) {
+ // These might throw, since we're asking for a lot of memory.
+ }
testInvalidInitial(2**31);
testInvalidInitial(maxPageCount + 1);
if (m_remainingCapacityForFrameCapture) {
// If callee is unknown, but we've not added any frame yet, we should
// still add the frame, because something called us, and gave us arguments.
- JSObject* callee = visitor->callee();
+ JSCell* callee = visitor->callee();
if (!callee && visitor->index())
return StackVisitor::Done;
builder.append(visitor->functionName());
builder.appendLiteral("() at ");
builder.append(visitor->sourceURL());
- if (visitor->isJSFrame()) {
+ if (visitor->hasLineAndColumnInfo()) {
builder.append(':');
unsigned lineNumber;
unsigned unusedColumn;
+2016-12-11 Saam Barati <sbarati@apple.com>
+
+ We should be able to throw exceptions from Wasm code and when Wasm frames are on the stack
+ https://bugs.webkit.org/show_bug.cgi?id=165429
+
+ Reviewed by Keith Miller.
+
+ This patch teaches the stack walking runtime about wasm.
+ To do this, I taught StackVisitor that a callee is not
+ always an object.
+
+ To be able to unwind callee save registers properly, I've given
+ JSWebAssemblyCallee a list of RegisterAtOffsetList for the callee
+ saves that B3 saved in the prologue. Also, because we have two
+ B3Compilations per wasm function, one for wasm entrypoint, and
+ one for the JS entrypoint, I needed to create a callee for each
+ because they each might spill callee save registers.
+
+ I also fixed a bug inside the Wasm::Memory constructor where we
+ were trying to mmap the same number of bytes even after the first
+ mmap failed. We should start by trying to mmap the maximum bytes,
+ and if that fails, fall back to the specified initial bytes. However,
+ the code was just mmapping the maximum twice. I've fixed that and
+ also added a RELEASE_ASSERT_NOT_REACHED() for when the second mmap
+ fails along with a FIXME to throw an OOM error.
+
+ There was a second bug I fixed where JSModuleRecord was calling
+ visitWeak on its CallLinkInfos inside ::visitChldren(). It needs
+ to do this after marking. I changed JSModuleRecord to do what
+ CodeBlock does and call visitWeak on its CallLinkInfos inside
+ an UnconditionalFinalizer.
+
+ * API/JSContextRef.cpp:
+ (BacktraceFunctor::operator()):
+ * inspector/ScriptCallStackFactory.cpp:
+ (Inspector::createScriptCallStackFromException):
+ * interpreter/CallFrame.cpp:
+ (JSC::CallFrame::vmEntryGlobalObject):
+ * interpreter/CallFrame.h:
+ (JSC::ExecState::callee):
+ * interpreter/Interpreter.cpp:
+ (JSC::GetStackTraceFunctor::operator()):
+ (JSC::UnwindFunctor::operator()):
+ (JSC::UnwindFunctor::copyCalleeSavesToVMEntryFrameCalleeSavesBuffer):
+ * interpreter/Interpreter.h:
+ * interpreter/ShadowChicken.cpp:
+ (JSC::ShadowChicken::update):
+ * interpreter/StackVisitor.cpp:
+ (JSC::StackVisitor::StackVisitor):
+ (JSC::StackVisitor::readFrame):
+ (JSC::StackVisitor::readNonInlinedFrame):
+ (JSC::StackVisitor::readInlinedFrame):
+ (JSC::StackVisitor::Frame::isWasmFrame):
+ (JSC::StackVisitor::Frame::codeType):
+ (JSC::StackVisitor::Frame::calleeSaveRegisters):
+ (JSC::StackVisitor::Frame::functionName):
+ (JSC::StackVisitor::Frame::sourceURL):
+ (JSC::StackVisitor::Frame::toString):
+ (JSC::StackVisitor::Frame::hasLineAndColumnInfo):
+ (JSC::StackVisitor::Frame::setToEnd):
+ * interpreter/StackVisitor.h:
+ (JSC::StackVisitor::Frame::callee):
+ (JSC::StackVisitor::Frame::isNativeFrame):
+ (JSC::StackVisitor::Frame::isJSFrame): Deleted.
+ * jsc.cpp:
+ (callWasmFunction):
+ (functionTestWasmModuleFunctions):
+ * runtime/Error.cpp:
+ (JSC::addErrorInfoAndGetBytecodeOffset):
+ * runtime/JSCell.cpp:
+ (JSC::JSCell::isAnyWasmCallee):
+ * runtime/JSCell.h:
+ * runtime/JSFunction.cpp:
+ (JSC::RetrieveArgumentsFunctor::operator()):
+ (JSC::RetrieveCallerFunctionFunctor::operator()):
+ * runtime/StackFrame.cpp:
+ (JSC::StackFrame::sourceID):
+ (JSC::StackFrame::sourceURL):
+ (JSC::StackFrame::functionName):
+ (JSC::StackFrame::computeLineAndColumn):
+ (JSC::StackFrame::toString):
+ * runtime/StackFrame.h:
+ (JSC::StackFrame::StackFrame):
+ (JSC::StackFrame::hasLineAndColumnInfo):
+ (JSC::StackFrame::hasBytecodeOffset):
+ (JSC::StackFrame::bytecodeOffset):
+ (JSC::StackFrame::isNative): Deleted.
+ * runtime/VM.h:
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+ (JSC::Wasm::createJSToWasmWrapper):
+ (JSC::Wasm::parseAndCompile):
+ * wasm/WasmCallingConvention.h:
+ (JSC::Wasm::CallingConvention::setupFrameInPrologue):
+ * wasm/WasmFormat.h:
+ * wasm/WasmMemory.cpp:
+ (JSC::Wasm::Memory::Memory):
+ * wasm/WasmMemory.h:
+ (JSC::Wasm::Memory::isValid):
+ * wasm/WasmPlan.cpp:
+ (JSC::Wasm::Plan::run):
+ (JSC::Wasm::Plan::initializeCallees):
+ * wasm/WasmPlan.h:
+ (JSC::Wasm::Plan::jsToWasmEntryPointForFunction): Deleted.
+ * wasm/js/JSWebAssemblyCallee.cpp:
+ (JSC::JSWebAssemblyCallee::finishCreation):
+ * wasm/js/JSWebAssemblyCallee.h:
+ (JSC::JSWebAssemblyCallee::create):
+ (JSC::JSWebAssemblyCallee::entrypoint):
+ (JSC::JSWebAssemblyCallee::calleeSaveRegisters):
+ (JSC::JSWebAssemblyCallee::jsToWasmEntryPoint): Deleted.
+ * wasm/js/JSWebAssemblyModule.cpp:
+ (JSC::JSWebAssemblyModule::JSWebAssemblyModule):
+ (JSC::JSWebAssemblyModule::visitChildren):
+ (JSC::JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally):
+ * wasm/js/JSWebAssemblyModule.h:
+ (JSC::JSWebAssemblyModule::jsEntrypointCalleeFromFunctionIndexSpace):
+ (JSC::JSWebAssemblyModule::wasmEntrypointCalleeFromFunctionIndexSpace):
+ (JSC::JSWebAssemblyModule::setJSEntrypointCallee):
+ (JSC::JSWebAssemblyModule::setWasmEntrypointCallee):
+ (JSC::JSWebAssemblyModule::allocationSize):
+ (JSC::JSWebAssemblyModule::calleeFromFunctionIndexSpace): Deleted.
+ * wasm/js/JSWebAssemblyRuntimeError.h:
+ * wasm/js/WebAssemblyFunction.cpp:
+ (JSC::WebAssemblyFunction::call):
+ * wasm/js/WebAssemblyInstanceConstructor.cpp:
+ (JSC::constructJSWebAssemblyInstance):
+ * wasm/js/WebAssemblyMemoryConstructor.cpp:
+ (JSC::constructJSWebAssemblyMemory):
+ * wasm/js/WebAssemblyModuleConstructor.cpp:
+ (JSC::constructJSWebAssemblyModule):
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::link):
+
2016-12-11 Filip Pizlo <fpizlo@apple.com>
Re-enable concurrent GC.
extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL);
frames.append(ScriptCallFrame(String(), exceptionSourceURL, noSourceID, lineNumber, columnNumber));
} else {
- if (stackTrace[0].isNative() || stackTrace[0].sourceURL().isEmpty()) {
+ if (!stackTrace[0].hasLineAndColumnInfo() || stackTrace[0].sourceURL().isEmpty()) {
const ScriptCallFrame& firstCallFrame = frames.first();
extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL);
frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, stackTrace[0].sourceID(), lineNumber, columnNumber);
JSGlobalObject* CallFrame::vmEntryGlobalObject()
{
- if (this == lexicalGlobalObject()->globalExec())
- return lexicalGlobalObject();
+ if (callee()->isObject()) {
+ if (this == lexicalGlobalObject()->globalExec())
+ return lexicalGlobalObject();
+ }
+ // If we're not an object, we're wasm, and therefore we're executing code and the below is safe.
// For any ExecState that's not a globalExec, the
// dynamic global object must be set since code is running
public:
static const int headerSizeInRegisters = CallFrameSlot::argumentCount + 1;
- JSCell* callee() const { return this[CallFrameSlot::callee].unboxedCell(); }
JSValue calleeAsValue() const { return this[CallFrameSlot::callee].jsValue(); }
JSObject* jsCallee() const { return this[CallFrameSlot::callee].object(); }
+ JSCell* callee() const { return this[CallFrameSlot::callee].unboxedCell(); }
SUPPRESS_ASAN JSValue unsafeCallee() const { return this[CallFrameSlot::callee].asanUnsafeJSValue(); }
CodeBlock* codeBlock() const { return this[CallFrameSlot::codeBlock].Register::codeBlock(); }
CodeBlock** addressOfCodeBlock() const { return bitwise_cast<CodeBlock**>(this + CallFrameSlot::codeBlock); }
#include "Register.h"
#include "ScopedArguments.h"
#include "StackAlignment.h"
+#include "StackFrame.h"
#include "StackVisitor.h"
#include "StrictEvalActivation.h"
#include "StrongInlines.h"
}
if (m_remainingCapacityForFrameCapture) {
- if (visitor->isJSFrame()
+ if (!visitor->isWasmFrame()
+ && !!visitor->codeBlock()
&& !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
- StackFrame s = {
- Strong<JSObject>(m_vm, visitor->callee()),
- Strong<CodeBlock>(m_vm, visitor->codeBlock()),
- visitor->bytecodeOffset()
- };
- m_results.append(s);
+ m_results.append(
+ StackFrame(m_vm, visitor->callee(), visitor->codeBlock(), visitor->bytecodeOffset()));
} else {
- StackFrame s = {
- Strong<JSObject>(m_vm, visitor->callee()),
- Strong<CodeBlock>(),
- 0 // unused value because codeBlock is null.
- };
- m_results.append(s);
+ m_results.append(
+ StackFrame(m_vm, visitor->callee()));
}
m_remainingCapacityForFrameCapture--;
m_handler = nullptr;
if (!m_isTermination) {
- if (m_codeBlock)
+ if (m_codeBlock) {
m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler);
+ if (m_handler)
+ return StackVisitor::Done;
+ }
}
- if (m_handler)
- return StackVisitor::Done;
-
notifyDebuggerOfUnwinding(m_callFrame);
- bool shouldStopUnwinding = visitor->callerIsVMEntryFrame();
- if (shouldStopUnwinding) {
- copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(visitor);
+ copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(visitor);
+ bool shouldStopUnwinding = visitor->callerIsVMEntryFrame();
+ if (shouldStopUnwinding)
return StackVisitor::Done;
- }
-
- copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(visitor);
return StackVisitor::Continue;
}
void copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(StackVisitor& visitor) const
{
#if ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
-
- if (!visitor->isJSFrame())
- return;
-
-#if ENABLE(DFG_JIT)
- if (visitor->inlineCallFrame())
- return;
-#endif
- RegisterAtOffsetList* currentCalleeSaves = m_codeBlock ? m_codeBlock->calleeSaveRegisters() : nullptr;
+ RegisterAtOffsetList* currentCalleeSaves = visitor->calleeSaveRegisters();
if (!currentCalleeSaves)
return;
#include "JSObject.h"
#include "Opcode.h"
#include "StackAlignment.h"
-#include "StackFrame.h"
#include <wtf/HashMap.h>
#if !ENABLE(JIT)
class ModuleProgramExecutable;
class Register;
class JSScope;
+ class StackFrame;
struct CallFrameClosure;
struct HandlerInfo;
struct Instruction;
exec, [&] (StackVisitor& visitor) -> StackVisitor::Status {
if (visitor->isInlinedFrame())
return StackVisitor::Continue;
+ if (visitor->isWasmFrame()) {
+ // FIXME: Make shadow chicken work with Wasm.
+ // https://bugs.webkit.org/show_bug.cgi?id=165441
+ return StackVisitor::Continue;
+ }
+
bool isTailDeleted = false;
- stackRightNow.append(Frame(visitor->callee(), visitor->callFrame(), isTailDeleted));
+ // FIXME: Make shadow chicken work with Wasm.
+ // https://bugs.webkit.org/show_bug.cgi?id=165441
+ stackRightNow.append(Frame(jsCast<JSObject*>(visitor->callee()), visitor->callFrame(), isTailDeleted));
return StackVisitor::Continue;
});
stackRightNow.reverse();
return StackVisitor::Continue;
}
+ if (visitor->isWasmFrame()) {
+ // FIXME: Make shadow chicken work with Wasm.
+ return StackVisitor::Continue;
+ }
+
CallFrame* callFrame = visitor->callFrame();
if (verbose)
dataLog(" Examining ", RawPointer(callFrame), "\n");
if (scope)
RELEASE_ASSERT(scope->inherits(JSScope::info()));
}
- toPush.append(Frame(visitor->callee(), callFrame, isTailDeleted, callFrame->thisValue(), scope, codeBlock, callFrame->callSiteIndex()));
+ toPush.append(Frame(jsCast<JSObject*>(visitor->callee()), callFrame, isTailDeleted, callFrame->thisValue(), scope, codeBlock, callFrame->callSiteIndex()));
if (indexInLog < logCursorIndex
// This condition protects us from the case where advanceIndexInLogTo didn't find
#include "InlineCallFrame.h"
#include "Interpreter.h"
#include "JSCInlines.h"
+#include "JSWebAssemblyCallee.h"
#include <wtf/text/StringBuilder.h>
namespace JSC {
StackVisitor::StackVisitor(CallFrame* startFrame)
{
m_frame.m_index = 0;
+ m_frame.m_isWasmFrame = false;
CallFrame* topFrame;
if (startFrame) {
m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
return;
}
+ if (callFrame->callee()->isAnyWasmCallee()) {
+ readNonInlinedFrame(callFrame);
+ return;
+ }
+
#if !ENABLE(DFG_JIT)
readNonInlinedFrame(callFrame);
m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
- m_frame.m_callee = callFrame->jsCallee();
- m_frame.m_codeBlock = callFrame->codeBlock();
- m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
- : codeOrigin ? codeOrigin->bytecodeIndex
- : callFrame->bytecodeOffset();
+ m_frame.m_isWasmFrame = false;
+
+ JSCell* callee = callFrame->callee();
+ m_frame.m_callee = callee;
+
+ if (callee->isAnyWasmCallee()) {
+ m_frame.m_isWasmFrame = true;
+ m_frame.m_codeBlock = nullptr;
+ m_frame.m_bytecodeOffset = 0;
+ } else {
+ m_frame.m_codeBlock = callFrame->codeBlock();
+ m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
+ : codeOrigin ? codeOrigin->bytecodeIndex
+ : callFrame->bytecodeOffset();
+
+ }
+
#if ENABLE(DFG_JIT)
m_frame.m_inlineCallFrame = 0;
#endif
void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
{
ASSERT(codeOrigin);
+ m_frame.m_isWasmFrame = false;
int frameOffset = inlinedFrameOffset(codeOrigin);
bool isInlined = !!frameOffset;
}
#endif // ENABLE(DFG_JIT)
+bool StackVisitor::Frame::isWasmFrame() const
+{
+ return m_isWasmFrame;
+}
+
StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
{
- if (!isJSFrame())
+ if (isWasmFrame())
+ return CodeType::Wasm;
+
+ if (!codeBlock())
return CodeType::Native;
switch (codeBlock()->codeType()) {
return CodeType::Global;
}
+RegisterAtOffsetList* StackVisitor::Frame::calleeSaveRegisters()
+{
+ if (isInlinedFrame())
+ return nullptr;
+
+#if ENABLE(WEBASSEMBLY)
+ if (isWasmFrame()) {
+ if (JSCell* callee = this->callee()) {
+ if (JSWebAssemblyCallee* wasmCallee = jsDynamicCast<JSWebAssemblyCallee*>(callee))
+ return wasmCallee->calleeSaveRegisters();
+ // Other wasm callees (e.g, stubs) don't use callee save registers, so nothing needs
+ // to be restored for them.
+ }
+
+ return nullptr;
+ }
+#endif
+
+ if (CodeBlock* codeBlock = this->codeBlock())
+ return codeBlock->calleeSaveRegisters();
+
+ return nullptr;
+}
+
String StackVisitor::Frame::functionName() const
{
String traceLine;
- JSObject* callee = this->callee();
+ JSCell* callee = this->callee();
switch (codeType()) {
+ case CodeType::Wasm:
+ traceLine = ASCIILiteral("wasm code");
+ break;
case CodeType::Eval:
traceLine = ASCIILiteral("eval code");
break;
break;
case CodeType::Native:
if (callee)
- traceLine = getCalculatedDisplayName(callFrame()->vm(), callee).impl();
+ traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(callee)).impl();
break;
case CodeType::Function:
- traceLine = getCalculatedDisplayName(callFrame()->vm(), callee).impl();
+ traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(callee)).impl();
break;
case CodeType::Global:
traceLine = ASCIILiteral("global code");
case CodeType::Native:
traceLine = ASCIILiteral("[native code]");
break;
+ case CodeType::Wasm:
+ traceLine = ASCIILiteral("[wasm code]");
+ break;
}
return traceLine.isNull() ? emptyString() : traceLine;
}
if (!functionName.isEmpty())
traceBuild.append('@');
traceBuild.append(sourceURL);
- if (isJSFrame()) {
+ if (hasLineAndColumnInfo()) {
unsigned line = 0;
unsigned column = 0;
computeLineAndColumn(line, column);
return arguments;
}
+bool StackVisitor::Frame::hasLineAndColumnInfo() const
+{
+ return !!codeBlock();
+}
+
void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column) const
{
CodeBlock* codeBlock = this->codeBlock();
#if ENABLE(DFG_JIT)
m_inlineCallFrame = 0;
#endif
+ m_isWasmFrame = false;
}
void StackVisitor::Frame::dump(PrintStream& out, Indenter indent) const
class JSObject;
class ClonedArguments;
class Register;
+class RegisterAtOffsetList;
typedef ExecState CallFrame;
Eval,
Function,
Module,
- Native
+ Native,
+ Wasm
};
size_t index() const { return m_index; }
size_t argumentCountIncludingThis() const { return m_argumentCountIncludingThis; }
bool callerIsVMEntryFrame() const { return m_callerIsVMEntryFrame; }
CallFrame* callerFrame() const { return m_callerFrame; }
- JSObject* callee() const { return m_callee; }
+ JSCell* callee() const { return m_callee; }
CodeBlock* codeBlock() const { return m_codeBlock; }
unsigned bytecodeOffset() const { return m_bytecodeOffset; }
InlineCallFrame* inlineCallFrame() const {
#endif
}
- bool isJSFrame() const { return !!codeBlock(); }
+ bool isNativeFrame() const { return !codeBlock() && !isWasmFrame(); }
bool isInlinedFrame() const { return !!inlineCallFrame(); }
+ bool isWasmFrame() const;
JS_EXPORT_PRIVATE String functionName() const;
JS_EXPORT_PRIVATE String sourceURL() const;
intptr_t sourceID();
CodeType codeType() const;
+ bool hasLineAndColumnInfo() const;
JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column) const;
+ RegisterAtOffsetList* calleeSaveRegisters();
+
ClonedArguments* createArguments();
VMEntryFrame* vmEntryFrame() const { return m_VMEntryFrame; }
CallFrame* callFrame() const { return m_callFrame; }
void retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const;
void setToEnd();
- size_t m_index;
- size_t m_argumentCountIncludingThis;
+#if ENABLE(DFG_JIT)
+ InlineCallFrame* m_inlineCallFrame;
+#endif
+ CallFrame* m_callFrame;
VMEntryFrame* m_VMEntryFrame;
VMEntryFrame* m_CallerVMEntryFrame;
CallFrame* m_callerFrame;
- JSObject* m_callee;
+ JSCell* m_callee;
CodeBlock* m_codeBlock;
+ size_t m_index;
+ size_t m_argumentCountIncludingThis;
unsigned m_bytecodeOffset;
- bool m_callerIsVMEntryFrame;
-#if ENABLE(DFG_JIT)
- InlineCallFrame* m_inlineCallFrame;
-#endif
- CallFrame* m_callFrame;
+ bool m_callerIsVMEntryFrame : 1;
+ bool m_isWasmFrame : 1;
friend class StackVisitor;
};
ProtoCallFrame protoCallFrame;
protoCallFrame.init(nullptr, globalObject->globalExec()->jsCallee(), firstArgument, argCount, remainingArgs);
- return JSValue::decode(vmEntryToWasm(wasmCallee->jsToWasmEntryPoint(), vm, &protoCallFrame));
+ return JSValue::decode(vmEntryToWasm(wasmCallee->entrypoint(), vm, &protoCallFrame));
}
// testWasmModule(JSArrayBufferView source, number functionCount, ...[[WasmValue, [WasmValue]]]) where the ith copy of [[result, [args]]] is a list
CRASH();
MarkedArgumentBuffer callees;
+ MarkedArgumentBuffer keepAlive;
{
unsigned lastIndex = UINT_MAX;
plan.initializeCallees(exec->lexicalGlobalObject(),
- [&] (unsigned calleeIndex, JSWebAssemblyCallee* callee) {
+ [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
RELEASE_ASSERT(!calleeIndex || (calleeIndex - 1 == lastIndex));
- callees.append(callee);
+ callees.append(jsEntrypointCallee);
+ keepAlive.append(wasmEntrypointCallee);
lastIndex = calleeIndex;
});
}
if (!!moduleInformation->memory) {
memory = std::make_unique<Wasm::Memory>(moduleInformation->memory.initial(), moduleInformation->memory.maximum());
+ RELEASE_ASSERT(memory->isValid());
memoryBytes = memory->memory();
memorySize = memory->size();
}
for (unsigned argIndex = 0; argIndex < arguments->length(); ++argIndex)
boxedArgs.append(box(exec, vm, arguments->getIndexQuickly(argIndex)));
- JSValue callResult = callWasmFunction(&vm, exec->lexicalGlobalObject(), jsCast<JSWebAssemblyCallee*>(callees.at(i)), boxedArgs);
+ JSValue callResult;
+ {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ callResult = callWasmFunction(&vm, exec->lexicalGlobalObject(), jsCast<JSWebAssemblyCallee*>(callees.at(i)), boxedArgs);
+ RETURN_IF_EXCEPTION(scope, { });
+ }
JSValue expected = box(exec, vm, result);
if (callResult != expected) {
dataLog("Arguments: ");
ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
- StackFrame* firstNonNativeFrame = nullptr;
+ StackFrame* firstFrameWithLineAndColumnInfo = nullptr;
for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
- firstNonNativeFrame = &stackTrace.at(i);
- if (!firstNonNativeFrame->isNative())
+ firstFrameWithLineAndColumnInfo = &stackTrace.at(i);
+ if (firstFrameWithLineAndColumnInfo->hasLineAndColumnInfo())
break;
}
vm.topCallFrame->iterate(functor);
callFrame = functor.foundCallFrame();
unsigned stackIndex = functor.index();
- *bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
+ *bytecodeOffset = 0;
+ if (stackTrace.at(stackIndex).hasBytecodeOffset())
+ *bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset();
}
unsigned line;
unsigned column;
- firstNonNativeFrame->computeLineAndColumn(line, column);
+ firstFrameWithLineAndColumnInfo->computeLineAndColumn(line, column);
obj->putDirect(vm, vm.propertyNames->line, jsNumber(line));
obj->putDirect(vm, vm.propertyNames->column, jsNumber(column));
- String frameSourceURL = firstNonNativeFrame->sourceURL();
+ String frameSourceURL = firstFrameWithLineAndColumnInfo->sourceURL();
if (!frameSourceURL.isEmpty())
obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, frameSourceURL));
#include "JSCell.h"
#include "ArrayBufferView.h"
+#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSString.h"
#include "JSObject.h"
+#include "JSWebAssemblyCallee.h"
#include "NumberObject.h"
-#include "JSCInlines.h"
+#include "WebAssemblyToJSCallee.h"
#include <wtf/MathExtras.h>
namespace JSC {
RELEASE_ASSERT_NOT_REACHED();
}
+bool JSCell::isAnyWasmCallee() const
+{
+#if ENABLE(WEBASSEMBLY)
+ return inherits(JSWebAssemblyCallee::info()) || inherits(WebAssemblyToJSCallee::info());
+#else
+ return false;
+#endif
+
+}
+
} // namespace JSC
bool isString() const;
bool isSymbol() const;
bool isObject() const;
+ bool isAnyWasmCallee() const;
bool isGetterSetter() const;
bool isCustomGetterSetter() const;
bool isProxy() const;
StackVisitor::Status operator()(StackVisitor& visitor) const
{
- JSObject* callee = visitor->callee();
+ JSCell* callee = visitor->callee();
if (callee != m_targetCallee)
return StackVisitor::Continue;
StackVisitor::Status operator()(StackVisitor& visitor) const
{
- JSObject* callee = visitor->callee();
+ JSCell* callee = visitor->callee();
if (callee && callee->inherits(JSBoundFunction::info()))
return StackVisitor::Continue;
intptr_t StackFrame::sourceID() const
{
- if (!codeBlock)
+ if (!m_codeBlock)
return noSourceID;
- return codeBlock->ownerScriptExecutable()->sourceID();
+ return m_codeBlock->ownerScriptExecutable()->sourceID();
}
String StackFrame::sourceURL() const
{
- if (!codeBlock)
+ if (!m_codeBlock) {
+ if (m_callee && m_callee->isAnyWasmCallee())
+ return ASCIILiteral("[wasm code]");
return ASCIILiteral("[native code]");
+ }
- String sourceURL = codeBlock->ownerScriptExecutable()->sourceURL();
+ String sourceURL = m_codeBlock->ownerScriptExecutable()->sourceURL();
if (!sourceURL.isNull())
return sourceURL;
return emptyString();
String StackFrame::functionName(VM& vm) const
{
- if (codeBlock) {
- switch (codeBlock->codeType()) {
+ if (m_codeBlock) {
+ switch (m_codeBlock->codeType()) {
case EvalCode:
return ASCIILiteral("eval code");
case ModuleCode:
}
}
String name;
- if (callee)
- name = getCalculatedDisplayName(vm, callee.get()).impl();
+ if (m_callee) {
+ if (m_callee->isObject())
+ name = getCalculatedDisplayName(vm, jsCast<JSObject*>(m_callee.get())).impl();
+ else if (m_callee->isAnyWasmCallee())
+ return ASCIILiteral("<wasm>");
+ }
return name.isNull() ? emptyString() : name;
}
void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column) const
{
- if (!codeBlock) {
+ if (!m_codeBlock) {
line = 0;
column = 0;
return;
int divot = 0;
int unusedStartOffset = 0;
int unusedEndOffset = 0;
- codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, unusedStartOffset, unusedEndOffset, line, column);
+ m_codeBlock->expressionRangeForBytecodeOffset(m_bytecodeOffset, divot, unusedStartOffset, unusedEndOffset, line, column);
- ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
+ ScriptExecutable* executable = m_codeBlock->ownerScriptExecutable();
if (executable->hasOverrideLineNumber())
line = executable->overrideLineNumber();
}
if (!functionName.isEmpty())
traceBuild.append('@');
traceBuild.append(sourceURL);
- if (codeBlock) {
+ if (hasLineAndColumnInfo()) {
unsigned line;
unsigned column;
computeLineAndColumn(line, column);
class CodeBlock;
class JSObject;
-struct StackFrame {
- Strong<JSObject> callee;
- Strong<CodeBlock> codeBlock;
- unsigned bytecodeOffset;
-
- bool isNative() const { return !codeBlock; }
+class StackFrame {
+public:
+ StackFrame(VM& vm, JSCell* callee)
+ : m_callee(vm, callee)
+ { }
+
+ StackFrame(VM& vm, JSCell* callee, CodeBlock* codeBlock, unsigned bytecodeOffset)
+ : m_callee(vm, callee)
+ , m_codeBlock(vm, codeBlock)
+ , m_bytecodeOffset(bytecodeOffset)
+ { }
+
+ bool hasLineAndColumnInfo() const { return !!m_codeBlock; }
void computeLineAndColumn(unsigned& line, unsigned& column) const;
String functionName(VM&) const;
intptr_t sourceID() const;
String sourceURL() const;
String toString(VM&) const;
+
+ bool hasBytecodeOffset() const { return m_bytecodeOffset != UINT_MAX; }
+ unsigned bytecodeOffset()
+ {
+ ASSERT(m_bytecodeOffset != UINT_MAX);
+ return m_bytecodeOffset;
+ }
+
+
+private:
+ Strong<JSCell> m_callee { };
+ Strong<CodeBlock> m_codeBlock { };
+ unsigned m_bytecodeOffset { UINT_MAX };
+
};
} // namespace JSC
class ScriptExecutable;
class SourceProvider;
class SourceProviderCache;
-struct StackFrame;
+class StackFrame;
class Structure;
#if ENABLE(REGEXP_TRACING)
class RegExp;
#include "B3VariableValue.h"
#include "B3WasmAddressValue.h"
#include "B3WasmBoundsCheckValue.h"
+#include "ExceptionScope.h"
+#include "FrameTracers.h"
+#include "JITExceptions.h"
+#include "JSCInlines.h"
#include "JSWebAssemblyInstance.h"
#include "JSWebAssemblyModule.h"
+#include "JSWebAssemblyRuntimeError.h"
#include "VirtualRegister.h"
#include "WasmCallingConvention.h"
#include "WasmFunctionParser.h"
m_proc.pinRegister(info.sizeRegister);
m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
- // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351
- jit.breakpoint();
+ jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
+
+ jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ CCallHelpers::Call call = jit.call();
+ jit.jumpToExceptionHandler();
+
+ jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+ void (*throwMemoryException)(ExecState*) = [] (ExecState* exec) {
+ VM* vm = &exec->vm();
+ NativeCallFrameTracer tracer(vm, exec);
+
+ {
+ auto throwScope = DECLARE_THROW_SCOPE(*vm);
+ JSGlobalObject* globalObject = vm->topJSWebAssemblyInstance->globalObject();
+
+ JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(
+ exec, globalObject->WebAssemblyRuntimeErrorStructure(), "Out of bounds memory access");
+ throwException(exec, throwScope, error);
+ }
+
+ genericUnwind(vm, exec);
+ ASSERT(!!vm->callFrameForCatch);
+ };
+
+ linkBuffer.link(call, throwMemoryException);
+ });
});
+
+ B3::PatchpointValue* foo = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
+ foo->setGenerator(
+ [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
+ });
}
- wasmCallingConvention().setupFrameInPrologue(compilation, m_proc, Origin(), m_currentBlock);
+ wasmCallingConvention().setupFrameInPrologue(&compilation->wasmCalleeMoveLocation, m_proc, Origin(), m_currentBlock);
m_functionIndexSpaceValue = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), functionIndexSpace.buffer.get());
}
dataLogLn("\n");
}
-static std::unique_ptr<Compilation> createJSToWasmWrapper(VM& vm, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
+static std::unique_ptr<Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFunction& function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
{
Procedure proc;
BasicBlock* block = proc.addBlock();
- // Check argument count is sane.
- Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, Origin());
- Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, Origin(), CallFrameSlot::argumentCount * sizeof(Register));
- Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
- block->appendNew<Value>(proc, Add, Origin(), framePointer, offSetOfArgumentCount));
+ Origin origin;
+
+ jscCallingConvention().setupFrameInPrologue(&function.jsToWasmCalleeMoveLocation, proc, origin, block);
+
+ Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin);
+ Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, origin, CallFrameSlot::argumentCount * sizeof(Register));
+ Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, origin,
+ block->appendNew<Value>(proc, Add, origin, framePointer, offSetOfArgumentCount));
+
+ Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->arguments.size());
- Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, Origin(), signature->arguments.size());
+ CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, origin,
+ block->appendNew<Value>(proc, Above, origin, expectedArgumentCount, argumentCount));
- CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, Origin(),
- block->appendNew<Value>(proc, Above, Origin(), expectedArgumentCount, argumentCount));
argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
jit.breakpoint();
});
block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topWasmMemorySize));
sizes.reserveCapacity(memory.pinnedRegisters().sizeRegisters.size());
for (auto info : memory.pinnedRegisters().sizeRegisters) {
- sizes.append(block->appendNew<Value>(proc, Sub, Origin(), size,
- block->appendNew<Const32Value>(proc, Origin(), info.sizeOffset)));
+ sizes.append(block->appendNew<Value>(proc, Sub, origin, size,
+ block->appendNew<Const32Value>(proc, origin, info.sizeOffset)));
}
}
// Get our arguments.
Vector<Value*> arguments;
- jscCallingConvention().loadArguments(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {
+ jscCallingConvention().loadArguments(signature->arguments, proc, block, origin, [&] (Value* argument, unsigned) {
arguments.append(argument);
});
// Move the arguments into place.
- Value* result = wasmCallingConvention().setupCall(proc, block, Origin(), arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
+ Value* result = wasmCallingConvention().setupCall(proc, block, origin, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
if (!!memory) {
ASSERT(sizes.size() == memory.pinnedRegisters().sizeRegisters.size());
patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory.pinnedRegisters().baseMemoryPointer)));
// Return the result, if needed.
switch (signature->returnType) {
case Wasm::Void:
- block->appendNewControlValue(proc, B3::Return, Origin());
+ block->appendNewControlValue(proc, B3::Return, origin);
break;
case Wasm::F32:
case Wasm::F64:
- result = block->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+ result = block->appendNew<Value>(proc, BitwiseCast, origin, result);
FALLTHROUGH;
case Wasm::I32:
case Wasm::I64:
- block->appendNewControlValue(proc, B3::Return, Origin(), result);
+ block->appendNewControlValue(proc, B3::Return, origin, result);
break;
case Wasm::Func:
case Wasm::Anyfunc:
RELEASE_ASSERT_NOT_REACHED();
}
- return std::make_unique<Compilation>(vm, proc);
+ auto jsEntrypoint = std::make_unique<Compilation>(vm, proc);
+ function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters();
+ return jsEntrypoint;
}
std::unique_ptr<WasmInternalFunction> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
if (verbose)
dataLog("Post SSA: ", procedure);
- result->code = std::make_unique<Compilation>(vm, procedure, optLevel);
- result->jsToWasmEntryPoint = createJSToWasmWrapper(vm, signature, result->code->code(), info.memory);
+ result->wasmEntrypoint.compilation = std::make_unique<Compilation>(vm, procedure, optLevel);
+ result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+ result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory);
return result;
}
}
public:
- void setupFrameInPrologue(WasmInternalFunction* compilation, B3::Procedure& proc, B3::Origin origin, B3::BasicBlock* block) const
+ void setupFrameInPrologue(CodeLocationDataLabelPtr* calleeMoveLocation, B3::Procedure& proc, B3::Origin origin, B3::BasicBlock* block) const
{
static_assert(CallFrameSlot::callee * sizeof(Register) < headerSize, "We rely on this here for now.");
static_assert(CallFrameSlot::codeBlock * sizeof(Register) < headerSize, "We rely on this here for now.");
GPRReg result = params[0].gpr();
MacroAssembler::DataLabelPtr moveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), result);
jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
- compilation->calleeMoveLocation = linkBuffer.locationOf(moveLocation);
+ *calleeMoveLocation = linkBuffer.locationOf(moveLocation);
});
});
#include "CodeLocation.h"
#include "Identifier.h"
#include "MacroAssemblerCodeRef.h"
+#include "RegisterAtOffsetList.h"
#include "WasmMemoryInformation.h"
#include "WasmOps.h"
#include "WasmPageCount.h"
size_t functionIndex;
};
+struct Entrypoint {
+ std::unique_ptr<B3::Compilation> compilation;
+ RegisterAtOffsetList calleeSaveRegisters;
+};
+
struct WasmInternalFunction {
- CodeLocationDataLabelPtr calleeMoveLocation;
- std::unique_ptr<B3::Compilation> code;
- std::unique_ptr<B3::Compilation> jsToWasmEntryPoint;
+ CodeLocationDataLabelPtr wasmCalleeMoveLocation;
+ CodeLocationDataLabelPtr jsToWasmCalleeMoveLocation;
+
+ Entrypoint wasmEntrypoint;
+ Entrypoint jsToWasmEntrypoint;
};
typedef MacroAssemblerCodeRef WasmToJSStub;
, m_maximum(maximum)
// FIXME: If we add signal based bounds checking then we need extra space for overflow on load.
// see: https://bugs.webkit.org/show_bug.cgi?id=162693
- , m_mappedCapacity(PageCount::max().bytes())
{
RELEASE_ASSERT(!maximum || maximum >= initial); // This should be guaranteed by our caller.
+ m_mappedCapacity = m_capacity;
// FIXME: It would be nice if we had a VM tag for wasm memory. https://bugs.webkit.org/show_bug.cgi?id=163600
void* result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (result == MAP_FAILED) {
// Try again with a different number.
- m_mappedCapacity = m_capacity;
+ m_mappedCapacity = m_size;
result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (result == MAP_FAILED)
return;
munmap(m_memory, m_mappedCapacity);
}
+ bool isValid() const { return !!m_memory; }
+
void* memory() const { return m_memory; }
uint32_t size() const { return m_size; }
unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation));
- m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->code->code().executableAddress();
+ m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
}
// Patch the call sites for each WebAssembly function.
m_failed = false;
}
-void Plan::initializeCallees(JSGlobalObject* globalObject, std::function<void(unsigned, JSWebAssemblyCallee*)> callback)
+void Plan::initializeCallees(JSGlobalObject* globalObject, std::function<void(unsigned, JSWebAssemblyCallee*, JSWebAssemblyCallee*)> callback)
{
ASSERT(!failed());
for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
WasmInternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
- CodeLocationDataLabelPtr calleeMoveLocation = function->calleeMoveLocation;
- JSWebAssemblyCallee* callee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->code), WTFMove(function->jsToWasmEntryPoint));
- MacroAssembler::repatchPointer(calleeMoveLocation, callee);
+ JSWebAssemblyCallee* jsEntrypointCallee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->jsToWasmEntrypoint));
+ MacroAssembler::repatchPointer(function->jsToWasmCalleeMoveLocation, jsEntrypointCallee);
- if (verbose)
- dataLogLn("Made Wasm callee: ", RawPointer(callee));
+ JSWebAssemblyCallee* wasmEntrypointCallee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->wasmEntrypoint));
+ MacroAssembler::repatchPointer(function->wasmCalleeMoveLocation, wasmEntrypointCallee);
- callback(internalFunctionIndex, callee);
+ callback(internalFunctionIndex, jsEntrypointCallee, wasmEntrypointCallee);
}
}
JS_EXPORT_PRIVATE void run();
- JS_EXPORT_PRIVATE void initializeCallees(JSGlobalObject*, std::function<void(unsigned, JSWebAssemblyCallee*)>);
+ JS_EXPORT_PRIVATE void initializeCallees(JSGlobalObject*, std::function<void(unsigned, JSWebAssemblyCallee*, JSWebAssemblyCallee*)>);
bool WARN_UNUSED_RETURN failed() const { return m_failed; }
const String& errorMessage() const
return m_wasmInternalFunctions.size();
}
- B3::Compilation* jsToWasmEntryPointForFunction(size_t i) const
- {
- ASSERT(i > m_wasmToJSStubs.size());
- return m_wasmInternalFunctions.at(i - m_wasmToJSStubs.size())->jsToWasmEntryPoint.get();
- }
-
std::unique_ptr<ModuleInformation>&& takeModuleInformation()
{
RELEASE_ASSERT(!failed());
: Base(vm, vm.webAssemblyCalleeStructure.get())
{ }
-void JSWebAssemblyCallee::finishCreation(VM& vm, std::unique_ptr<B3::Compilation>&& code, std::unique_ptr<B3::Compilation>&& jsToWasmEntryPoint)
+void JSWebAssemblyCallee::finishCreation(VM& vm, Wasm::Entrypoint&& entrypoint)
{
Base::finishCreation(vm);
- m_code = WTFMove(code);
- m_jsToWasmEntryPoint = WTFMove(jsToWasmEntryPoint);
+ m_entrypoint = WTFMove(entrypoint);
}
void JSWebAssemblyCallee::destroy(JSCell* cell)
#if ENABLE(WEBASSEMBLY)
-#include "JSCallee.h"
+#include "JSCell.h"
+#include "RegisterAtOffsetList.h"
+#include "Structure.h"
#include "WasmFormat.h"
namespace JSC {
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- static JSWebAssemblyCallee* create(VM& vm, std::unique_ptr<B3::Compilation>&& code, std::unique_ptr<B3::Compilation>&& jsToWasmEntryPoint)
+ static JSWebAssemblyCallee* create(VM& vm, Wasm::Entrypoint&& entrypoint)
{
JSWebAssemblyCallee* callee = new (NotNull, allocateCell<JSWebAssemblyCallee>(vm.heap)) JSWebAssemblyCallee(vm);
- callee->finishCreation(vm, std::forward<std::unique_ptr<B3::Compilation>>(code), std::forward<std::unique_ptr<B3::Compilation>>(jsToWasmEntryPoint));
+ callee->finishCreation(vm, WTFMove(entrypoint));
return callee;
}
static const bool needsDestruction = true;
static void destroy(JSCell*);
- void* jsToWasmEntryPoint() { return m_jsToWasmEntryPoint->code().executableAddress(); }
+ void* entrypoint() { return m_entrypoint.compilation->code().executableAddress(); }
+
+ RegisterAtOffsetList* calleeSaveRegisters() { return &m_entrypoint.calleeSaveRegisters; }
private:
- void finishCreation(VM&, std::unique_ptr<B3::Compilation>&&, std::unique_ptr<B3::Compilation>&&);
+ void finishCreation(VM&, Wasm::Entrypoint&&);
JSWebAssemblyCallee(VM&);
- std::unique_ptr<B3::Compilation> m_code;
- std::unique_ptr<B3::Compilation> m_jsToWasmEntryPoint;
+ Wasm::Entrypoint m_entrypoint;
};
} // namespace JSC
, m_functionIndexSpace(WTFMove(functionIndexSpace))
, m_calleeCount(calleeCount)
{
- memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>));
+ memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>) * 2);
}
void JSWebAssemblyModule::finishCreation(VM& vm, SymbolTable* exportSymbolTable)
void JSWebAssemblyModule::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- auto* thisObject = jsCast<JSWebAssemblyModule*>(cell);
+ JSWebAssemblyModule* thisObject = jsCast<JSWebAssemblyModule*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_exportSymbolTable);
- for (auto iter = thisObject->m_callLinkInfos.begin(); !!iter; ++iter)
- (*iter)->visitWeak(*thisObject->vm());
- for (unsigned i = 0; i < thisObject->m_calleeCount; i++) {
+ for (unsigned i = 0; i < thisObject->m_calleeCount * 2; i++) {
WriteBarrier<JSWebAssemblyCallee>* callee = &thisObject->callees()[i];
visitor.append(callee);
}
+
+ visitor.addUnconditionalFinalizer(&thisObject->m_unconditionalFinalizer);
+}
+
+void JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally()
+{
+ JSWebAssemblyModule* thisObject = bitwise_cast<JSWebAssemblyModule*>(
+ bitwise_cast<char*>(this) - OBJECT_OFFSETOF(JSWebAssemblyModule, m_unconditionalFinalizer));
+ for (auto iter = thisObject->m_callLinkInfos.begin(); !!iter; ++iter)
+ (*iter)->visitWeak(*thisObject->vm());
}
} // namespace JSC
#include "JSDestructibleObject.h"
#include "JSObject.h"
+#include "JSWebAssemblyCallee.h"
+#include "UnconditionalFinalizer.h"
#include "WasmFormat.h"
#include <wtf/Bag.h>
#include <wtf/Vector.h>
namespace JSC {
-class JSWebAssemblyCallee;
class SymbolTable;
class JSWebAssemblyModule : public JSDestructibleObject {
Wasm::Signature* signatureForFunctionIndexSpace(unsigned functionIndexSpace) const { ASSERT(functionIndexSpace < m_functionIndexSpace.size); return m_functionIndexSpace.buffer.get()[functionIndexSpace].signature; }
unsigned importCount() const { return m_wasmToJSStubs.size(); }
- JSWebAssemblyCallee* calleeFromFunctionIndexSpace(unsigned functionIndexSpace)
+ JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
{
RELEASE_ASSERT(functionIndexSpace >= importCount());
unsigned calleeIndex = functionIndexSpace - importCount();
return callees()[calleeIndex].get();
}
+ JSWebAssemblyCallee* wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
+ {
+ RELEASE_ASSERT(functionIndexSpace >= importCount());
+ unsigned calleeIndex = functionIndexSpace - importCount();
+ RELEASE_ASSERT(calleeIndex < m_calleeCount);
+ return callees()[calleeIndex + m_calleeCount].get();
+ }
+
+ void setJSEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
+ {
+ RELEASE_ASSERT(calleeIndex < m_calleeCount);
+ callees()[calleeIndex].set(vm, this, callee);
+ }
+
+ void setWasmEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
+ {
+ RELEASE_ASSERT(calleeIndex < m_calleeCount);
+ callees()[calleeIndex + m_calleeCount].set(vm, this, callee);
+ }
+
WriteBarrier<JSWebAssemblyCallee>* callees()
{
return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
static size_t allocationSize(unsigned numCallees)
{
- return offsetOfCallees() + sizeof(WriteBarrier<JSWebAssemblyCallee>) * numCallees;
+ return offsetOfCallees() + sizeof(WriteBarrier<JSWebAssemblyCallee>) * numCallees * 2;
}
+ class UnconditionalFinalizer : public JSC::UnconditionalFinalizer {
+ void finalizeUnconditionally() override;
+ };
+
+ UnconditionalFinalizer m_unconditionalFinalizer;
std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
Bag<CallLinkInfo> m_callLinkInfos;
WriteBarrier<SymbolTable> m_exportSymbolTable;
public:
typedef ErrorInstance Base;
- static JSWebAssemblyRuntimeError* create(ExecState*, Structure*, const String&, bool);
+ static JSWebAssemblyRuntimeError* create(ExecState*, Structure*, const String&, bool useCurrentFrame = true);
static JSWebAssemblyRuntimeError* create(ExecState* exec, Structure* structure, JSValue message, bool useCurrentFrame)
{
return create(exec, structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), useCurrentFrame);
JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
vm.topJSWebAssemblyInstance = instance();
- EncodedJSValue rawResult = vmEntryToWasm(webAssemblyCallee()->jsToWasmEntryPoint(), &vm, protoCallFrame);
+ ASSERT(instance());
+ EncodedJSValue rawResult = vmEntryToWasm(webAssemblyCallee()->entrypoint(), &vm, protoCallFrame);
vm.topJSWebAssemblyInstance = prevJSWebAssemblyInstance;
// FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
RELEASE_ASSERT(!moduleInformation.memory.isImport());
// We create a memory when it's a memory definition.
std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(moduleInformation.memory.initial(), moduleInformation.memory.maximum());
+ if (!memory->isValid())
+ return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
instance->setMemory(vm,
JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
}
}
std::unique_ptr<Wasm::Memory> memory = std::make_unique<Wasm::Memory>(initialPageCount, maximumPageCount);
+ if (!memory->isValid())
+ return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
return JSValue::encode(JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
}
unsigned calleeCount = plan.internalFunctionCount();
JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmToJSStubs(), plan.takeFunctionIndexSpace(), exportSymbolTable, calleeCount);
plan.initializeCallees(state->jsCallee()->globalObject(),
- [&] (unsigned calleeIndex, JSWebAssemblyCallee* callee) {
- result->callees()[calleeIndex].set(vm, result, callee);
+ [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
+ result->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);
+ result->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee);
});
return JSValue::encode(result);
}
// a. Let func be an Exported Function Exotic Object created from c.
// b. Append func to funcs.
// c. Return func.
- JSWebAssemblyCallee* wasmCallee = module->calleeFromFunctionIndexSpace(exp.functionIndex);
+ JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
Wasm::Signature* signature = module->signatureForFunctionIndexSpace(exp.functionIndex);
WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, wasmCallee, signature);
exportedValue = function;
// FIXME can start call imports / tables? This assumes not. https://github.com/WebAssembly/design/issues/896
if (!m_startFunction.get()) {
// The start function wasn't added above. It must be a purely internal function.
- JSWebAssemblyCallee* wasmCallee = module->calleeFromFunctionIndexSpace(startFunctionIndexSpace);
+ JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, wasmCallee, signature);
m_startFunction.set(vm, this, function);
}
+2016-12-11 Saam Barati <sbarati@apple.com>
+
+ We should be able to throw exceptions from Wasm code and when Wasm frames are on the stack
+ https://bugs.webkit.org/show_bug.cgi?id=165429
+
+ Reviewed by Keith Miller.
+
+ * bindings/js/JSDOMBinding.cpp:
+ (WebCore::GetCallerGlobalObjectFunctor::operator()):
+
2016-12-11 Darin Adler <darin@apple.com>
Remove uses of Dictionary in WebRTC IDL files
m_globalObject = codeBlock->globalObject();
else {
ASSERT(visitor->callee());
- m_globalObject = visitor->callee()->globalObject();
+ // FIXME: Callee is not an object if the caller is Web Assembly.
+ // Figure out what to do here. We can probably get the global object
+ // from the top-most Wasm Instance. https://bugs.webkit.org/show_bug.cgi?id=165721
+ if (visitor->callee()->isObject())
+ m_globalObject = jsCast<JSObject*>(visitor->callee())->globalObject();
}
return StackVisitor::Done;
}