mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[JAEGER] Remove VMFrame::scriptedReturn (bug 587833, r=dmandelin).
This commit is contained in:
parent
f3a2844e1b
commit
d1f08da7e5
@ -167,21 +167,25 @@ mjit::TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *sco
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::saveReturnAddress()
|
||||
{
|
||||
#ifndef JS_CPU_ARM
|
||||
masm.pop(Registers::ReturnReg);
|
||||
restoreFrameRegs(masm);
|
||||
masm.storePtr(Registers::ReturnReg, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
||||
#else
|
||||
restoreFrameRegs(masm);
|
||||
masm.storePtr(JSC::ARMRegisters::lr, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
||||
#endif
|
||||
}
|
||||
|
||||
CompileStatus
|
||||
mjit::Compiler::generatePrologue()
|
||||
{
|
||||
invokeLabel = masm.label();
|
||||
#ifdef JS_CPU_ARM
|
||||
/*
|
||||
* Unlike x86/x64, the return address is not automatically pushed onto the stack during a call
|
||||
* (blx). To compensate, we explicitly push it here.
|
||||
*
|
||||
* NOTE: The ABI requires that we maintain 8-byte stack alignment at function boundaries. The
|
||||
* trampoline always enters this function with an unaligned stack so we can re-align it.
|
||||
*/
|
||||
masm.push(JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
restoreFrameRegs(masm);
|
||||
|
||||
saveReturnAddress();
|
||||
|
||||
/*
|
||||
* If there is no function, then this can only be called via JaegerShot(),
|
||||
@ -190,10 +194,7 @@ mjit::Compiler::generatePrologue()
|
||||
if (fun) {
|
||||
Jump j = masm.jump();
|
||||
invokeLabel = masm.label();
|
||||
#ifdef JS_CPU_ARM
|
||||
masm.push(JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
restoreFrameRegs(masm);
|
||||
saveReturnAddress();
|
||||
|
||||
/* Set locals to undefined. */
|
||||
for (uint32 i = 0; i < script->nslots; i++) {
|
||||
@ -1572,6 +1573,16 @@ mjit::Compiler::jsop_getglobal(uint32 index)
|
||||
frame.push(address);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::restoreReturnAddress(Assembler &masm)
|
||||
{
|
||||
#ifndef JS_CPU_ARM
|
||||
masm.push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
||||
#else
|
||||
masm.move(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitReturn()
|
||||
{
|
||||
@ -1583,6 +1594,7 @@ mjit::Compiler::emitReturn()
|
||||
FrameAddress(offsetof(VMFrame, entryFp)),
|
||||
JSFrameReg);
|
||||
stubcc.linkExit(noInlineCalls, Uses(frame.frameDepth()));
|
||||
restoreReturnAddress(stubcc.masm);
|
||||
stubcc.masm.ret();
|
||||
|
||||
JS_ASSERT_IF(!fun, JSOp(*PC) == JSOP_STOP);
|
||||
@ -1643,13 +1655,12 @@ mjit::Compiler::emitReturn()
|
||||
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
|
||||
masm.loadPayload(rval, JSReturnReg_Data);
|
||||
masm.loadTypeTag(rval, JSReturnReg_Type);
|
||||
restoreReturnAddress(masm);
|
||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), Registers::ReturnReg);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
||||
#endif
|
||||
|
||||
masm.ret();
|
||||
}
|
||||
|
||||
@ -1836,20 +1847,12 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
}
|
||||
|
||||
/* Fast-path: return address contains scripted call. */
|
||||
|
||||
masm.addPtr(Imm32(sizeof(void*)), Registers::StackPointer);
|
||||
masm.call(Registers::ReturnReg);
|
||||
#if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)
|
||||
masm.callLabel = masm.label();
|
||||
#endif
|
||||
ADD_CALLSITE(false);
|
||||
|
||||
/*
|
||||
* The scripted call returns a register triplet, containing the jsval and
|
||||
* the current f.scriptedReturn.
|
||||
*/
|
||||
masm.push(Registers::ReturnReg);
|
||||
|
||||
/*
|
||||
* Functions invoked with |new| can return, for some reason, primitive
|
||||
* values. Just deal with this here.
|
||||
|
@ -225,6 +225,8 @@ class Compiler
|
||||
void addCallSite(uint32 id, bool stub);
|
||||
|
||||
/* Emitting helpers. */
|
||||
void saveReturnAddress();
|
||||
void restoreReturnAddress(Assembler &masm);
|
||||
void restoreFrameRegs(Assembler &masm);
|
||||
void emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
void iter(uintN flags);
|
||||
|
@ -169,7 +169,6 @@ top:
|
||||
static inline void
|
||||
FixVMFrame(VMFrame &f, JSStackFrame *fp)
|
||||
{
|
||||
f.fp->ncode = f.scriptedReturn;
|
||||
JS_ASSERT(f.fp == fp->down);
|
||||
f.fp = fp;
|
||||
}
|
||||
@ -500,7 +499,6 @@ CreateLightFrame(VMFrame &f, uint32 flags, uint32 argc)
|
||||
}
|
||||
|
||||
/* Initialize the frame. */
|
||||
newfp->ncode = NULL;
|
||||
newfp->setCallObj(NULL);
|
||||
newfp->setArgsObj(NULL);
|
||||
newfp->setScript(newscript);
|
||||
@ -634,7 +632,6 @@ js_InternalThrow(VMFrame &f)
|
||||
|
||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
||||
InlineReturn(f, JS_FALSE);
|
||||
f.scriptedReturn = cx->fp->ncode;
|
||||
}
|
||||
|
||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
||||
@ -768,7 +765,8 @@ RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
||||
fp->flags &= ~JSFRAME_RECORDING;
|
||||
|
||||
if (AtSafePoint(cx)) {
|
||||
if (!JaegerShot(cx)) {
|
||||
JSScript *script = fp->getScript();
|
||||
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
|
||||
if (!SwallowErrors(f, entryFrame))
|
||||
return false;
|
||||
|
||||
@ -846,9 +844,6 @@ RunTracer(VMFrame &f)
|
||||
if (!cx->jitEnabled)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT_IF(f.fp != f.entryFp,
|
||||
entryFrame->down->getScript()->isValidJitCode(f.scriptedReturn));
|
||||
|
||||
bool blacklist;
|
||||
uintN inlineCallCount = 0;
|
||||
tpa = MonitorTracePoint(f.cx, inlineCallCount, blacklist);
|
||||
@ -884,9 +879,12 @@ RunTracer(VMFrame &f)
|
||||
* The tracer could have dropped us off on any frame at any position.
|
||||
* Well, it could not have removed frames (recursion is disabled).
|
||||
*
|
||||
* Frames after the entryFrame cannot be entered via JaegerShot()
|
||||
* unless each is at a safe point. We can JaegerShot these frames
|
||||
* individually, but we must unwind to the entryFrame.
|
||||
* Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint()
|
||||
* unless each is at a safe point. We can JaegerShotAtSafePoint these
|
||||
* frames individually, but we must unwind to the entryFrame.
|
||||
*
|
||||
* Note carefully that JaegerShotAtSafePoint can resume methods at
|
||||
* arbitrary safe points whereas JaegerShot cannot.
|
||||
*
|
||||
* If we land on entryFrame without a safe point in sight, we'll end up
|
||||
* at the RETURN op. This is an edge case with two paths:
|
||||
@ -895,10 +893,8 @@ RunTracer(VMFrame &f)
|
||||
* move the return value down.
|
||||
* 2) The entryFrame is NOT the last inline frame. Pop the frame.
|
||||
*
|
||||
* In both cases, we hijack the stub to return to JaegerFromTracer. This
|
||||
* moves |oldFp->rval| into the scripted return registers, places the
|
||||
* new f.scriptedReturn in the machine return register, and returns to its
|
||||
* caller safely.
|
||||
* In both cases, we hijack the stub to return to InjectJaegerReturn. This
|
||||
* moves |oldFp->rval| into the scripted return registers.
|
||||
*/
|
||||
|
||||
restart:
|
||||
@ -936,8 +932,7 @@ RunTracer(VMFrame &f)
|
||||
if (!InlineReturn(f, JS_TRUE))
|
||||
THROWV(NULL);
|
||||
}
|
||||
entryFrame->ncode = f.fp->ncode;
|
||||
void *retPtr = JS_FUNC_TO_DATA_PTR(void *, JaegerFromTracer);
|
||||
void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn);
|
||||
*f.returnAddressLocation() = retPtr;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -49,6 +49,56 @@
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
|
||||
/*
|
||||
* Explanation of VMFrame activation and various helper thunks below.
|
||||
*
|
||||
* JaegerTrampoline - Executes a method JIT-compiled JSFunction. This function
|
||||
* creates a VMFrame on the machine stack and calls into JIT'd code. The JIT'd
|
||||
* code will eventually return to the VMFrame.
|
||||
*
|
||||
* - Called from C++ functions JaegerShot and JaegerBomb.
|
||||
* - Parameters: cx, fp, code, stackLimit, safePoint
|
||||
* - Notes: safePoint is used in combination with SafePointTrampoline,
|
||||
* explained further down.
|
||||
*
|
||||
* JaegerThrowpoline - Calls into an exception handler from JIT'd code, and if a
|
||||
* scripted exception handler is not found, unwinds the VMFrame and returns
|
||||
* to C++.
|
||||
*
|
||||
* - To start exception handling, we return from a stub call to the throwpoline.
|
||||
* - On entry to the throwpoline, the normal conditions of the jit-code ABI
|
||||
* are satisfied.
|
||||
* - To do the unwinding and find out where to continue executing, we call
|
||||
* js_InternalThrow.
|
||||
* - js_InternalThrow may return 0, which means the place to continue, if any,
|
||||
* is above this JaegerShot activation, so we just return, in the same way
|
||||
* the trampoline does.
|
||||
* - Otherwise, js_InternalThrow returns a jit-code address to continue
|
||||
* execution
|
||||
* at. Because the jit-code ABI conditions are satisfied, we can just jump
|
||||
* to that point.
|
||||
*
|
||||
*
|
||||
* SafePointTrampoline - Inline script calls link their return addresses through
|
||||
* JSStackFrame::ncode. This includes the return address that unwinds back
|
||||
* to JaegerTrampoline. However, the tracer integration code often wants to
|
||||
* enter a method JIT'd function at an arbitrary safe point. Safe points
|
||||
* do not have the return address linking code that the method prologue has.
|
||||
* SafePointTrampoline is a thunk which correctly links the initial return
|
||||
* address. It is used in JaegerBomb, and passed as the "script code"
|
||||
* parameter. Using the "safePoint" parameter to JaegerTrampoline, it correctly
|
||||
* jumps to the intended point in the method.
|
||||
*
|
||||
* - Used by JaegerTrampoline()
|
||||
*
|
||||
* InjectJaegerReturn - Implements the tail of InlineReturn. This is needed for
|
||||
* tracer integration, where a "return" opcode might not be a safe-point,
|
||||
* and thus the return path must be injected by hijacking the stub return
|
||||
* address.
|
||||
*
|
||||
* - Used by RunTracer()
|
||||
*/
|
||||
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
|
||||
static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
@ -150,27 +200,32 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
||||
"movq %rsi, %rbx" "\n"
|
||||
|
||||
/* Space for the rest of the VMFrame. */
|
||||
"subq $0x30, %rsp" "\n"
|
||||
"subq $0x28, %rsp" "\n"
|
||||
|
||||
/* Set cx->regs and set the active frame (requires saving rdx). */
|
||||
/*
|
||||
* This is actually part of the VMFrame, but we need to save |r8| for
|
||||
* SafePointTrampoline.
|
||||
*/
|
||||
"pushq %r8" "\n"
|
||||
|
||||
/* Set cx->regs and set the active frame. Save rdx and align frame in one. */
|
||||
"pushq %rdx" "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(SetVMFrameRegs) "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(PushActiveVMFrame) "\n"
|
||||
"popq %rdx" "\n"
|
||||
|
||||
/*
|
||||
* Jump into into the JIT'd code. The call implicitly fills in
|
||||
* the precious f.scriptedReturn member of VMFrame.
|
||||
*/
|
||||
"call *%rdx" "\n"
|
||||
"leaq -8(%rsp), %rdi" "\n"
|
||||
"call *0(%rsp)" "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
|
||||
"leaq -8(%rsp), %rdi" "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
|
||||
|
||||
"addq $0x50, %rsp" "\n"
|
||||
"addq $0x58, %rsp" "\n"
|
||||
"popq %rbx" "\n"
|
||||
"popq %r15" "\n"
|
||||
"popq %r14" "\n"
|
||||
@ -212,8 +267,17 @@ JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerFromTracer) "\n"
|
||||
SYMBOL_STRING(JaegerFromTracer) ":" "\n"
|
||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
||||
"popq %rax" "\n"
|
||||
"movq %rax, 0x60(%rbx)" "\n"
|
||||
"jmp *8(%rsp)" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
"movq 0x40(%rbx), %rcx" "\n" /* fp->rval type (as value) */
|
||||
"movq $0xFFFF800000000000, %r11" "\n" /* load type mask (JSVAL_TAG_MASK) */
|
||||
"andq %r11, %rcx" "\n" /* extract type */
|
||||
@ -224,6 +288,7 @@ SYMBOL_STRING(JaegerFromTracer) ":" "\n"
|
||||
|
||||
"movq 0x60(%rbx), %rax" "\n" /* fp->ncode */
|
||||
"movq 0x38(%rsp), %rbx" "\n" /* f.fp */
|
||||
"pushq %rax" "\n"
|
||||
"ret" "\n"
|
||||
);
|
||||
|
||||
@ -253,28 +318,26 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
||||
|
||||
/* Build the JIT frame. Push fields in order,
|
||||
* then align the stack to form esp == VMFrame. */
|
||||
"movl 12(%ebp), %ebx" "\n" /* fp */
|
||||
"movl 12(%ebp), %ebx" "\n" /* load fp */
|
||||
"pushl %ebx" "\n" /* entryFp */
|
||||
"pushl 20(%ebp)" "\n" /* inlineCallCount */
|
||||
"pushl 8(%ebp)" "\n"
|
||||
"pushl %ebx" "\n"
|
||||
"subl $0x18, %esp" "\n"
|
||||
"pushl 20(%ebp)" "\n" /* stackLimit */
|
||||
"pushl 8(%ebp)" "\n" /* cx */
|
||||
"pushl %ebx" "\n" /* fp */
|
||||
"subl $0x1C, %esp" "\n"
|
||||
|
||||
/* Jump into the JIT'd code. */
|
||||
"pushl 16(%ebp)" "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(SetVMFrameRegs) "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(PushActiveVMFrame) "\n"
|
||||
"popl %edx" "\n"
|
||||
|
||||
"call *%edx" "\n"
|
||||
"leal -4(%esp), %ecx" "\n"
|
||||
"call *16(%ebp)" "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
|
||||
"leal -4(%esp), %ecx" "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
|
||||
|
||||
"addl $0x28, %esp" "\n"
|
||||
"addl $0x2C, %esp" "\n"
|
||||
"popl %ebx" "\n"
|
||||
"popl %edi" "\n"
|
||||
"popl %esi" "\n"
|
||||
@ -317,15 +380,29 @@ JS_STATIC_ASSERT(offsetof(VMFrame, fp) == 0x1C);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerFromTracer) "\n"
|
||||
SYMBOL_STRING(JaegerFromTracer) ":" "\n"
|
||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
"movl 0x28(%ebx), %edx" "\n" /* fp->rval data */
|
||||
"movl 0x2C(%ebx), %ecx" "\n" /* fp->rval type */
|
||||
"movl 0x3C(%ebx), %eax" "\n" /* fp->ncode */
|
||||
"movl 0x1C(%esp), %ebx" "\n" /* f.fp */
|
||||
"pushl %eax" "\n"
|
||||
"ret" "\n"
|
||||
);
|
||||
|
||||
/*
|
||||
* Take the fifth parameter from JaegerShot() and jump to it. This makes it so
|
||||
* we can jump into arbitrary JIT code, which won't have the frame-fixup prologue.
|
||||
*/
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
||||
"popl %eax" "\n"
|
||||
"movl %eax, 0x3C(%ebx)" "\n"
|
||||
"jmp *24(%ebp)" "\n"
|
||||
);
|
||||
|
||||
# elif defined(JS_CPU_ARM)
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(VMFrame) == 80);
|
||||
@ -337,16 +414,30 @@ JS_STATIC_ASSERT(offsetof(VMFrame, fp) == (4*7));
|
||||
JS_STATIC_ASSERT(offsetof(VMFrame, oldRegs) == (4*4));
|
||||
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
|
||||
JS_STATIC_ASSERT(offsetof(VMFrame, scriptedReturn) == (4*0));
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 60);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) == 40);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerFromTracer) "\n"
|
||||
SYMBOL_STRING(JaegerFromTracer) ":" "\n"
|
||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
/* Restore frame regs. */
|
||||
"ldr r11, [sp, #32]" "\n"
|
||||
"ldr r1, [r11, #40]" "\n" /* fp->rval data */
|
||||
"ldr r2, [r11, #44]" "\n" /* fp->rval type */
|
||||
"ldr r0, [r11, #60]" "\n" /* fp->ncode */
|
||||
"ldr r11, [sp, #28]" "\n" /* load f.fp */
|
||||
"bx r0" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||
SYMBOL_STRING(SafePointTrampoline) ":"
|
||||
"str lr, [r11, #60]" "\n"
|
||||
/* This should load the fifth parameter from JaegerTrampoline and jump to it. */
|
||||
"" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerTrampoline) "\n"
|
||||
@ -399,11 +490,8 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
||||
" mov r0, sp" "\n"
|
||||
" bl " SYMBOL_STRING_RELOC(PushActiveVMFrame)"\n"
|
||||
|
||||
/* Call the compiled JavaScript function. We do this with an unaligned sp because the compiled
|
||||
* script explicitly pushes the return value into f->scriptedReturn. */
|
||||
" add sp, sp, #(4*1)" "\n"
|
||||
/* Call the compiled JavaScript function. */
|
||||
" blx r4" "\n"
|
||||
" sub sp, sp, #(4*1)" "\n"
|
||||
|
||||
/* Tidy up. */
|
||||
" mov r0, sp" "\n"
|
||||
@ -473,19 +561,29 @@ JS_STATIC_ASSERT(offsetof(VMFrame, fp) == 0x1C);
|
||||
|
||||
extern "C" {
|
||||
|
||||
__declspec(naked) void JaegerFromTracer()
|
||||
__declspec(naked) void InjectJaegerReturn()
|
||||
{
|
||||
__asm {
|
||||
mov edx, [ebx + 0x28];
|
||||
mov ecx, [ebx + 0x2C];
|
||||
mov eax, [ebx + 0x3C];
|
||||
mov ebx, [esp + 0x1C];
|
||||
push eax;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void SafePointTrampoline()
|
||||
{
|
||||
__asm {
|
||||
pop eax;
|
||||
mov eax, [ebx + 0x3C];
|
||||
jmp [ebp + 24];
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
||||
Value *stackLimit)
|
||||
Value *stackLimit, void *safePoint)
|
||||
{
|
||||
__asm {
|
||||
/* Prologue. */
|
||||
@ -503,23 +601,21 @@ extern "C" {
|
||||
push [ebp + 20];
|
||||
push [ebp + 8];
|
||||
push ebx;
|
||||
sub esp, 0x18;
|
||||
sub esp, 0x1C;
|
||||
|
||||
/* Jump into into the JIT'd code. */
|
||||
push [ebp+16];
|
||||
mov ecx, esp;
|
||||
call SetVMFrameRegs;
|
||||
mov ecx, esp;
|
||||
call PushActiveVMFrame;
|
||||
pop edx;
|
||||
|
||||
call edx;
|
||||
lea ecx, [esp-4];
|
||||
call [ebp + 16];
|
||||
mov ecx, esp;
|
||||
call PopActiveVMFrame;
|
||||
lea ecx, [esp-4];
|
||||
mov ecx, esp;
|
||||
call UnsetVMFrameRegs;
|
||||
|
||||
add esp, 0x28
|
||||
add esp, 0x2C;
|
||||
|
||||
pop ebx;
|
||||
pop edi;
|
||||
@ -618,39 +714,22 @@ ThreadData::Finish()
|
||||
}
|
||||
|
||||
extern "C" JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
||||
Value *stackLimit);
|
||||
Value *stackLimit, void *safePoint);
|
||||
extern "C" void SafePointTrampoline();
|
||||
|
||||
JSBool
|
||||
mjit::JaegerShot(JSContext *cx)
|
||||
static inline JSBool
|
||||
EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
||||
{
|
||||
JS_ASSERT(cx->regs);
|
||||
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE;);
|
||||
|
||||
void *code;
|
||||
jsbytecode *pc = cx->regs->pc;
|
||||
JSStackFrame *fp = cx->fp;
|
||||
JSScript *script = fp->getScript();
|
||||
|
||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
if (TRACE_RECORDER(cx))
|
||||
AbortRecording(cx, "attempt to enter method JIT while recording");
|
||||
#endif
|
||||
|
||||
if (pc == script->code)
|
||||
code = script->nmap[-1];
|
||||
else
|
||||
code = script->nmap[pc - script->code];
|
||||
|
||||
JS_ASSERT(code);
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
Profiler prof;
|
||||
JSScript *script = fp->getScript();
|
||||
|
||||
JaegerSpew(JSpew_Prof, "entering jaeger script: %s, line %d\n", script->filename,
|
||||
script->lineno);
|
||||
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
|
||||
safePoint ? "dropping" : "entering",
|
||||
script->filename, script->lineno);
|
||||
prof.start();
|
||||
#endif
|
||||
|
||||
@ -661,7 +740,7 @@ mjit::JaegerShot(JSContext *cx)
|
||||
Value *stackLimit = cx->stack().makeStackLimit(reinterpret_cast<Value*>(fp));
|
||||
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
||||
JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit);
|
||||
JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit, safePoint);
|
||||
|
||||
JS_ASSERT(checkFp == cx->fp);
|
||||
|
||||
@ -673,6 +752,37 @@ mjit::JaegerShot(JSContext *cx)
|
||||
return ok;
|
||||
}
|
||||
|
||||
JSBool
|
||||
mjit::JaegerShot(JSContext *cx)
|
||||
{
|
||||
JSScript *script = cx->fp->getScript();
|
||||
|
||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
if (TRACE_RECORDER(cx))
|
||||
AbortRecording(cx, "attempt to enter method JIT while recording");
|
||||
#endif
|
||||
|
||||
JS_ASSERT(cx->regs->pc == script->code);
|
||||
|
||||
void *code = script->nmap[-1];
|
||||
|
||||
return EnterMethodJIT(cx, cx->fp, code, NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js::mjit::JaegerShotAtSafePoint(JSContext *cx, void *safePoint)
|
||||
{
|
||||
#ifdef JS_TRACER
|
||||
JS_ASSERT(!TRACE_RECORDER(cx));
|
||||
#endif
|
||||
|
||||
void *code = JS_FUNC_TO_DATA_PTR(void *, SafePointTrampoline);
|
||||
|
||||
return EnterMethodJIT(cx, cx->fp, code, safePoint);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void Destroy(T &t)
|
||||
{
|
||||
@ -720,13 +830,6 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
script->mics = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
# if 0 /* def JS_TRACER */
|
||||
if (script->trees) {
|
||||
cx->free(script->trees);
|
||||
script->trees = NULL;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
|
@ -57,13 +57,11 @@ namespace js {
|
||||
|
||||
struct VMFrame
|
||||
{
|
||||
/* This must be the first entry on CPUs which push return addresses. */
|
||||
void *scriptedReturn;
|
||||
|
||||
union Arguments {
|
||||
struct {
|
||||
void *ptr;
|
||||
void *ptr2;
|
||||
void *ptr3;
|
||||
} x;
|
||||
} u;
|
||||
|
||||
@ -173,8 +171,11 @@ typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
|
||||
|
||||
namespace mjit {
|
||||
|
||||
JSBool
|
||||
JaegerShot(JSContext *cx);
|
||||
/* Execute a method that has been JIT compiled. */
|
||||
JSBool JaegerShot(JSContext *cx);
|
||||
|
||||
/* Drop into the middle of a method at an arbitrary point, and execute. */
|
||||
JSBool JaegerShotAtSafePoint(JSContext *cx, void *safePoint);
|
||||
|
||||
enum CompileStatus
|
||||
{
|
||||
@ -224,7 +225,7 @@ extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame);
|
||||
#else
|
||||
extern "C" void JaegerThrowpoline();
|
||||
#endif
|
||||
extern "C" void JaegerFromTracer();
|
||||
extern "C" void InjectJaegerReturn();
|
||||
|
||||
#endif /* jsjaeger_h__ */
|
||||
|
||||
|
@ -136,11 +136,6 @@ Recompiler::recompile()
|
||||
f != NULL;
|
||||
f = f->previous) {
|
||||
|
||||
if (script->isValidJitCode(f->scriptedReturn)) {
|
||||
if (!toPatch.append(findPatch(&f->scriptedReturn)))
|
||||
return false;
|
||||
}
|
||||
|
||||
void **machineReturn = f->returnAddressLocation();
|
||||
if (script->isValidJitCode(*machineReturn)) {
|
||||
if (!toPatch.append(findPatch(machineReturn)))
|
||||
|
@ -137,8 +137,14 @@ TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
|
||||
masm.loadPayload(rval, JSReturnReg_Data);
|
||||
masm.loadTypeTag(rval, JSReturnReg_Type);
|
||||
|
||||
#ifndef JS_CPU_ARM
|
||||
masm.push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
||||
#else
|
||||
masm.move(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
|
||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), Registers::ReturnReg);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
||||
|
Loading…
Reference in New Issue
Block a user