summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGThunks.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-07-16 14:51:15 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-07-16 14:51:15 +0200
commit4e6b3a206fa4ad8bb0b664f7674c9a70376d6e26 (patch)
tree7bb9ad7e31c24d1cf1707e03e6f1a80f6d033951 /Source/JavaScriptCore/dfg/DFGThunks.cpp
parent3977e3d2f72f7fe2c887c1ec0e0c342e1d169f42 (diff)
downloadqtwebkit-4e6b3a206fa4ad8bb0b664f7674c9a70376d6e26.tar.gz
Imported WebKit commit 953baa67aa07087b6ecd4199351ec554c724e27d (http://svn.webkit.org/repository/webkit/trunk@122676)
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGThunks.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGThunks.cpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp
index 08ca6eaa1..b056de79c 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.cpp
+++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp
@@ -28,6 +28,7 @@
#if ENABLE(DFG_JIT)
+#include "DFGCCallHelpers.h"
#include "DFGFPRInfo.h"
#include "DFGGPRInfo.h"
#include "DFGOSRExitCompiler.h"
@@ -82,6 +83,217 @@ MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData)
return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk"));
}
+inline void emitPointerValidation(CCallHelpers& jit, GPRReg pointerGPR)
+{
+#if !ASSERT_DISABLED
+ CCallHelpers::Jump isNonZero = jit.branchTestPtr(CCallHelpers::NonZero, pointerGPR);
+ jit.breakpoint();
+ isNonZero.link(&jit);
+ jit.push(pointerGPR);
+ jit.load8(pointerGPR, pointerGPR);
+ jit.pop(pointerGPR);
+#else
+ UNUSED_PARAM(jit);
+ UNUSED_PARAM(pointerGPR);
+#endif
+}
+
+MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData* globalData)
+{
+ CCallHelpers jit(globalData);
+
+ // We will jump to here if the JIT code thinks it's making a call, but the
+ // linking helper (C++ code) decided to throw an exception instead. We will
+ // have saved the callReturnIndex in the first arguments of JITStackFrame.
+ // Note that the return address will be on the stack at this point, so we
+ // need to remove it and drop it on the floor, since we don't care about it.
+ // Finally note that the call frame register points at the callee frame, so
+ // we need to pop it.
+ jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR);
+ jit.loadPtr(
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::CallerFrame),
+ GPRInfo::callFrameRegister);
+ jit.peek(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX);
+ jit.setupArgumentsWithExecState(GPRInfo::nonPreservedNonReturnGPR);
+ jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(lookupExceptionHandler)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0);
+ jit.call(GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::returnValueGPR2);
+ jit.jump(GPRInfo::returnValueGPR2);
+
+ LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID);
+ return FINALIZE_CODE(patchBuffer, ("DFG throw exception from call slow path thunk"));
+}
+
+static void slowPathFor(
+ CCallHelpers& jit, JSGlobalData* globalData, P_DFGOperation_E slowPathFunction)
+{
+ jit.preserveReturnAddressAfterCall(GPRInfo::nonArgGPR2);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR2);
+ jit.storePtr(
+ GPRInfo::nonArgGPR2,
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC));
+ jit.storePtr(GPRInfo::callFrameRegister, &globalData->topCallFrame);
+ jit.poke(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX);
+ jit.setupArgumentsExecState();
+ jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0);
+ jit.call(GPRInfo::nonArgGPR0);
+
+ // This slow call will return the address of one of the following:
+ // 1) Exception throwing thunk.
+ // 2) Host call return value returner thingy.
+ // 3) The function to call.
+ jit.loadPtr(
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC),
+ GPRInfo::nonPreservedNonReturnGPR);
+ jit.storePtr(
+ CCallHelpers::TrustedImmPtr(0),
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC));
+ emitPointerValidation(jit, GPRInfo::nonPreservedNonReturnGPR);
+ jit.restoreReturnAddressBeforeReturn(GPRInfo::nonPreservedNonReturnGPR);
+ emitPointerValidation(jit, GPRInfo::returnValueGPR);
+ jit.jump(GPRInfo::returnValueGPR);
+}
+
+static MacroAssemblerCodeRef linkForThunkGenerator(
+ JSGlobalData* globalData, CodeSpecializationKind kind)
+{
+ // The return address is on the stack or in the link register. We will hence
+ // save the return address to the call frame while we make a C++ function call
+ // to perform linking and lazy compilation if necessary. We expect the callee
+ // to be in nonArgGPR0/nonArgGPR1 (payload/tag), the call frame to have already
+ // been adjusted, nonPreservedNonReturnGPR holds the exception handler index,
+ // and all other registers to be available for use. We use JITStackFrame::args
+ // to save important information across calls.
+
+ CCallHelpers jit(globalData);
+
+ slowPathFor(jit, globalData, kind == CodeForCall ? operationLinkCall : operationLinkConstruct);
+
+ LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID);
+ return FINALIZE_CODE(
+ patchBuffer,
+ ("DFG link %s slow path thunk", kind == CodeForCall ? "call" : "construct"));
+}
+
+MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData* globalData)
+{
+ return linkForThunkGenerator(globalData, CodeForCall);
+}
+
+MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData* globalData)
+{
+ return linkForThunkGenerator(globalData, CodeForConstruct);
+}
+
+static MacroAssemblerCodeRef virtualForThunkGenerator(
+ JSGlobalData* globalData, CodeSpecializationKind kind)
+{
+ // The return address is on the stack, or in the link register. We will hence
+ // jump to the callee, or save the return address to the call frame while we
+ // make a C++ function call to the appropriate DFG operation.
+
+ CCallHelpers jit(globalData);
+
+ CCallHelpers::JumpList slowCase;
+
+ // FIXME: we should have a story for eliminating these checks. In many cases,
+ // the DFG knows that the value is definitely a cell, or definitely a function.
+
+#if USE(JSVALUE64)
+ slowCase.append(
+ jit.branchTestPtr(
+ CCallHelpers::NonZero, GPRInfo::nonArgGPR0, GPRInfo::tagMaskRegister));
+#else
+ slowCase.append(
+ jit.branch32(
+ CCallHelpers::NotEqual, GPRInfo::nonArgGPR1,
+ CCallHelpers::TrustedImm32(JSValue::CellTag)));
+#endif
+ slowCase.append(
+ jit.branchPtr(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::classInfoOffset()),
+ CCallHelpers::TrustedImmPtr(&JSFunction::s_info)));
+
+ // Now we know we have a JSFunction.
+
+ jit.loadPtr(
+ CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfExecutable()),
+ GPRInfo::nonArgGPR2);
+ slowCase.append(
+ jit.branch32(
+ CCallHelpers::LessThan,
+ CCallHelpers::Address(
+ GPRInfo::nonArgGPR2, ExecutableBase::offsetOfNumParametersFor(kind)),
+ CCallHelpers::TrustedImm32(0)));
+
+ // Now we know that we have a CodeBlock, and we're committed to making a fast
+ // call.
+
+ jit.loadPtr(
+ CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfScopeChain()),
+ GPRInfo::nonArgGPR1);
+#if USE(JSVALUE64)
+ jit.storePtr(
+ GPRInfo::nonArgGPR1,
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain));
+#else
+ jit.storePtr(
+ GPRInfo::nonArgGPR1,
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain +
+ OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ jit.store32(
+ CCallHelpers::TrustedImm32(JSValue::CellTag),
+ CCallHelpers::Address(
+ GPRInfo::callFrameRegister,
+ static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain +
+ OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+#endif
+
+ jit.loadPtr(
+ CCallHelpers::Address(GPRInfo::nonArgGPR2, ExecutableBase::offsetOfJITCodeWithArityCheckFor(kind)),
+ GPRInfo::regT0);
+
+ // Make a tail call. This will return back to DFG code.
+ emitPointerValidation(jit, GPRInfo::regT0);
+ jit.jump(GPRInfo::regT0);
+
+ slowCase.link(&jit);
+
+ // Here we don't know anything, so revert to the full slow path.
+
+ slowPathFor(jit, globalData, kind == CodeForCall ? operationVirtualCall : operationVirtualConstruct);
+
+ LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID);
+ return FINALIZE_CODE(
+ patchBuffer,
+ ("DFG virtual %s slow path thunk", kind == CodeForCall ? "call" : "construct"));
+}
+
+MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData* globalData)
+{
+ return virtualForThunkGenerator(globalData, CodeForCall);
+}
+
+MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData* globalData)
+{
+ return virtualForThunkGenerator(globalData, CodeForConstruct);
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)