зеркало из https://github.com/mozilla/pjs.git
Improved JM call path, bug 587707. r=lw,dvander
This commit is contained in:
Родитель
5bf8ef0fc2
Коммит
f6d77b2ef3
|
@ -434,7 +434,7 @@ void
|
|||
FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
|
||||
{
|
||||
JS_ASSERT(prev);
|
||||
JS_ASSERT(curpc == prev->savedpc_);
|
||||
JS_ASSERT(curpc == curfp->pc(cx, fp));
|
||||
JS_ASSERT(fp == curseg->getInitialFrame());
|
||||
|
||||
/*
|
||||
|
@ -2035,16 +2035,10 @@ void
|
|||
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
|
||||
{
|
||||
JS_ASSERT(regs != &newregs);
|
||||
if (hasActiveSegment()) {
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
if (hasActiveSegment())
|
||||
currentSegment->suspend(regs);
|
||||
}
|
||||
newseg->setPreviousInContext(currentSegment);
|
||||
currentSegment = newseg;
|
||||
#ifdef DEBUG
|
||||
newregs.fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
setCurrentRegs(&newregs);
|
||||
newseg->joinContext(this, newregs.fp);
|
||||
}
|
||||
|
@ -2054,7 +2048,6 @@ JSContext::popSegmentAndFrame()
|
|||
{
|
||||
JS_ASSERT(currentSegment->maybeContext() == this);
|
||||
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
currentSegment->leaveContext();
|
||||
currentSegment = currentSegment->getPreviousInContext();
|
||||
if (currentSegment) {
|
||||
|
@ -2063,9 +2056,6 @@ JSContext::popSegmentAndFrame()
|
|||
} else {
|
||||
setCurrentRegs(currentSegment->getSuspendedRegs());
|
||||
currentSegment->resume();
|
||||
#ifdef DEBUG
|
||||
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(regs->fp->prev() == NULL);
|
||||
|
@ -2078,8 +2068,6 @@ JSContext::saveActiveSegment()
|
|||
{
|
||||
JS_ASSERT(hasActiveSegment());
|
||||
currentSegment->save(regs);
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
setCurrentRegs(NULL);
|
||||
}
|
||||
|
||||
|
@ -2089,9 +2077,6 @@ JSContext::restoreSegment()
|
|||
js::StackSegment *ccs = currentSegment;
|
||||
setCurrentRegs(ccs->getSuspendedRegs());
|
||||
ccs->restore();
|
||||
#ifdef DEBUG
|
||||
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
|
||||
JSGenerator *
|
||||
|
|
|
@ -883,6 +883,7 @@ JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
|||
*/
|
||||
class FrameRegsIter
|
||||
{
|
||||
JSContext *cx;
|
||||
StackSegment *curseg;
|
||||
JSStackFrame *curfp;
|
||||
Value *cursp;
|
||||
|
@ -2090,6 +2091,9 @@ struct JSContext
|
|||
/* Undoes calls to suspendActiveSegment. */
|
||||
void restoreSegment();
|
||||
|
||||
/* Get the frame whose prev() is fp, which may be in any segment. */
|
||||
inline JSStackFrame *computeNextFrame(JSStackFrame *fp);
|
||||
|
||||
/*
|
||||
* Perform a linear search of all frames in all segments in the given context
|
||||
* for the given frame, returning the segment, if found, and null otherwise.
|
||||
|
|
|
@ -71,6 +71,21 @@ JSContext::ensureGeneratorStackSpace()
|
|||
return ok;
|
||||
}
|
||||
|
||||
JSStackFrame *
|
||||
JSContext::computeNextFrame(JSStackFrame *fp)
|
||||
{
|
||||
JSStackFrame *next = NULL;
|
||||
for (js::StackSegment *ss = currentSegment; ; ss = ss->getPreviousInContext()) {
|
||||
JSStackFrame *end = ss->getInitialFrame()->prev();
|
||||
for (JSStackFrame *f = ss->getCurrentFrame(); f != end; next = f, f = f->prev()) {
|
||||
if (f == fp)
|
||||
return next;
|
||||
}
|
||||
if (end != ss->getPreviousInContext()->getCurrentFrame())
|
||||
next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs *
|
||||
|
@ -309,16 +324,10 @@ StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
|
|||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
||||
|
||||
JSStackFrame *fp = fg->regs_.fp;
|
||||
JSStackFrame *prev = cx->maybefp();
|
||||
fp->prev_ = prev;
|
||||
fp->setPrev(cx->regs);
|
||||
if (JS_UNLIKELY(!currentSegment->inContext())) {
|
||||
cx->pushSegmentAndFrame(currentSegment, fg->regs_);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
JS_ASSERT(prev->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
#endif
|
||||
prev->savedpc_ = cx->regs->pc;
|
||||
fg->prevRegs_ = cx->regs;
|
||||
cx->setCurrentRegs(&fg->regs_);
|
||||
}
|
||||
|
@ -339,10 +348,8 @@ StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
|
|||
} else {
|
||||
JS_ASSERT(&fg.regs_ == cx->regs);
|
||||
JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
|
||||
JS_ASSERT(fp->prevpc() == fg.prevRegs_->pc);
|
||||
cx->setCurrentRegs(fg.prevRegs_);
|
||||
#ifdef DEBUG
|
||||
cx->fp()->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,11 +391,8 @@ StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
|
|||
JS_ASSERT(isCurrentAndActive(cx));
|
||||
JS_ASSERT(cx->regs == regs && script == fp->script());
|
||||
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
fp->prev_ = regs->fp;
|
||||
#ifdef DEBUG
|
||||
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
fp->setPrev(regs);
|
||||
|
||||
regs->fp = fp;
|
||||
regs->pc = script->code;
|
||||
regs->sp = fp->slots() + script->nfixed;
|
||||
|
@ -400,17 +404,13 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp)
|
|||
JS_ASSERT(isCurrentAndActive(cx));
|
||||
JS_ASSERT(cx->hasActiveSegment());
|
||||
JS_ASSERT(cx->regs->fp->prev_ == prev);
|
||||
JS_ASSERT(cx->regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
JS_ASSERT(!cx->regs->fp->hasImacropc());
|
||||
JS_ASSERT(prev->base() <= newsp && newsp <= cx->regs->fp->formalArgsEnd());
|
||||
|
||||
JSFrameRegs *regs = cx->regs;
|
||||
regs->pc = prev->pc(cx, regs->fp);
|
||||
regs->fp = prev;
|
||||
regs->pc = prev->savedpc_;
|
||||
regs->sp = newsp;
|
||||
#ifdef DEBUG
|
||||
prev->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE Value *
|
||||
|
@ -442,6 +442,7 @@ StackSpace::getStackLimit(JSContext *cx)
|
|||
|
||||
JS_REQUIRES_STACK inline
|
||||
FrameRegsIter::FrameRegsIter(JSContext *cx)
|
||||
: cx(cx)
|
||||
{
|
||||
curseg = cx->getCurrentSegment();
|
||||
if (JS_UNLIKELY(!curseg || !curseg->isActive())) {
|
||||
|
@ -463,7 +464,7 @@ FrameRegsIter::operator++()
|
|||
if (!prev)
|
||||
return *this;
|
||||
|
||||
curpc = prev->savedpc_;
|
||||
curpc = curfp->pc(cx, fp);
|
||||
|
||||
if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
|
||||
incSlow(fp, prev);
|
||||
|
|
|
@ -274,6 +274,7 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
|||
} else {
|
||||
JS_ASSERT(!argsobj.getPrivate());
|
||||
}
|
||||
fp->clearArgsObj();
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
@ -1157,6 +1158,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
}
|
||||
|
||||
callobj.setPrivate(NULL);
|
||||
fp->clearCallObj();
|
||||
}
|
||||
|
||||
JSBool JS_FASTCALL
|
||||
|
|
|
@ -93,6 +93,10 @@
|
|||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
#if defined(JS_METHODJIT) && defined(JS_MONOIC)
|
||||
#include "methodjit/MonoIC.h"
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
|
@ -100,10 +104,61 @@ using namespace js::gc;
|
|||
#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
|
||||
|
||||
#ifdef DEBUG
|
||||
jsbytecode *const JSStackFrame::sInvalidpc = (jsbytecode *)0xbeef;
|
||||
JSObject *const JSStackFrame::sInvalidScopeChain = (JSObject *)0xbeef;
|
||||
#endif
|
||||
|
||||
jsbytecode *
|
||||
JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
|
||||
{
|
||||
JS_ASSERT_IF(next, next->prev_ == this);
|
||||
JS_ASSERT(cx->containingSegment(this) != NULL);
|
||||
|
||||
JSFrameRegs *regs;
|
||||
if (cx->regs) {
|
||||
regs = cx->regs;
|
||||
} else {
|
||||
StackSegment *segment = cx->getCurrentSegment();
|
||||
regs = segment->getSuspendedRegs();
|
||||
}
|
||||
|
||||
if (this == regs->fp)
|
||||
return regs->pc;
|
||||
|
||||
if (!next)
|
||||
next = cx->computeNextFrame(this);
|
||||
|
||||
if (next->flags_ & JSFRAME_HAS_PREVPC)
|
||||
return next->prevpc_;
|
||||
|
||||
#if defined(JS_METHODJIT) && defined(JS_MONOIC)
|
||||
JSScript *script = this->script();
|
||||
size_t low = 0;
|
||||
size_t high = script->jit->nCallICs;
|
||||
while (high > low + 1) {
|
||||
/* Could overflow here on a script with 2 billion calls. Oh well. */
|
||||
size_t mid = (high + low) / 2;
|
||||
void *entry = script->callICs[mid].funGuard.executableAddress();
|
||||
|
||||
/*
|
||||
* Use >= here as the return address of the call is likely to be
|
||||
* the start address of the next (possibly IC'ed) operation.
|
||||
*/
|
||||
if (entry >= next->ncode_)
|
||||
high = mid;
|
||||
else
|
||||
low = mid;
|
||||
}
|
||||
|
||||
js::mjit::ic::CallICInfo &callIC = script->callICs[low];
|
||||
|
||||
JS_ASSERT((uint8*)callIC.funGuard.executableAddress() + callIC.joinPointOffset == next->ncode_);
|
||||
return callIC.pc;
|
||||
#else
|
||||
JS_NOT_REACHED("Unknown PC for frame");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't determine in advance which local variables can live on the stack and
|
||||
* be freed when their dynamic scope ends, and which will be closed over and
|
||||
|
@ -670,7 +725,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
JSObject *initialVarObj;
|
||||
if (prev) {
|
||||
JS_ASSERT(chain == &prev->scopeChain());
|
||||
frame.fp()->initEvalFrame(script, prev, flags);
|
||||
frame.fp()->initEvalFrame(script, prev, prev->pc(cx), flags);
|
||||
|
||||
/*
|
||||
* We want to call |prev->varobj()|, but this requires knowing the
|
||||
|
|
|
@ -91,10 +91,22 @@ enum JSFrameFlags
|
|||
|
||||
/* Lazy frame initialization */
|
||||
JSFRAME_HAS_IMACRO_PC = 0x8000, /* frame has imacpc value available */
|
||||
JSFRAME_HAS_CALL_OBJ = 0x10000, /* frame has a callobj in JSStackFrame::exec */
|
||||
JSFRAME_HAS_CALL_OBJ = 0x10000, /* frame has a callobj reachable from scopeChain_ */
|
||||
JSFRAME_HAS_ARGS_OBJ = 0x20000, /* frame has an argsobj in JSStackFrame::args */
|
||||
JSFRAME_HAS_HOOK_DATA = 0x40000, /* frame has hookData_ set */
|
||||
JSFRAME_HAS_ANNOTATION = 0x80000 /* frame has annotation_ set */
|
||||
JSFRAME_HAS_ANNOTATION = 0x80000, /* frame has annotation_ set */
|
||||
|
||||
/*
|
||||
* Whether the prevpc_ value is valid. If not set, the ncode_ value is
|
||||
* valid and prevpc_ can be recovered using it.
|
||||
*/
|
||||
JSFRAME_HAS_PREVPC = 0x100000,
|
||||
|
||||
/*
|
||||
* For use by compiled functions, at function exit indicates whether rval_
|
||||
* has been assigned to. Otherwise the return value is carried in registers.
|
||||
*/
|
||||
JSFRAME_RVAL_ASSIGNED = 0x200000
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -116,16 +128,16 @@ struct JSStackFrame
|
|||
} args;
|
||||
JSObject *scopeChain_; /* current scope chain */
|
||||
JSStackFrame *prev_; /* previous cx->regs->fp */
|
||||
jsbytecode *savedpc_; /* only valid if cx->fp != this */
|
||||
void *ncode_; /* return address for method JIT */
|
||||
|
||||
/* Lazily initialized */
|
||||
js::Value rval_; /* (TODO bug 595073) return value of the frame */
|
||||
js::Value rval_; /* return value of the frame */
|
||||
jsbytecode *prevpc_; /* pc of previous frame*/
|
||||
jsbytecode *imacropc_; /* pc of macro caller */
|
||||
void *hookData_; /* closure returned by call hook */
|
||||
void *annotation_; /* perhaps remove with bug 546848 */
|
||||
|
||||
/* TODO: remove */
|
||||
void *ncode_; /* bug 535912 */
|
||||
JSObject *blockChain_; /* bug 540675 */
|
||||
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
|
@ -195,7 +207,8 @@ struct JSStackFrame
|
|||
inline void initCallFrameLatePrologue();
|
||||
|
||||
/* Used for eval. */
|
||||
inline void initEvalFrame(JSScript *script, JSStackFrame *prev, uint32 flags);
|
||||
inline void initEvalFrame(JSScript *script, JSStackFrame *prev,
|
||||
jsbytecode *prevpc, uint32 flags);
|
||||
inline void initGlobalFrame(JSScript *script, JSObject &chain, uint32 flags);
|
||||
|
||||
/* Used when activating generators. */
|
||||
|
@ -222,8 +235,26 @@ struct JSStackFrame
|
|||
return prev_;
|
||||
}
|
||||
|
||||
void repointGeneratorFrameDown(JSStackFrame *prev) {
|
||||
void setPrev(JSStackFrame *prev, jsbytecode *prevpc) {
|
||||
JS_ASSERT(flags_ & JSFRAME_HAS_PREVPC);
|
||||
prev_ = prev;
|
||||
if (prev) {
|
||||
prevpc_ = prevpc;
|
||||
JS_ASSERT_IF(!prev->isDummyFrame() && !prev->hasImacropc(),
|
||||
uint32(prevpc - prev->script()->code) < prev->script()->length);
|
||||
}
|
||||
}
|
||||
|
||||
void setPrev(JSFrameRegs *regs) {
|
||||
JS_ASSERT(flags_ & JSFRAME_HAS_PREVPC);
|
||||
if (regs) {
|
||||
prev_ = regs->fp;
|
||||
prevpc_ = regs->pc;
|
||||
JS_ASSERT_IF(!prev_->isDummyFrame() && !prev_->hasImacropc(),
|
||||
uint32(prevpc_ - prev_->script()->code) < prev_->script()->length);
|
||||
} else {
|
||||
prev_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -249,7 +280,16 @@ struct JSStackFrame
|
|||
* the bytecode being executed for the frame.
|
||||
*/
|
||||
|
||||
jsbytecode *pc(JSContext *cx) const;
|
||||
/*
|
||||
* Get the frame's current bytecode, assuming |this| is in |cx|.
|
||||
* next is frame whose prev == this, NULL if not known or if this == cx->fp().
|
||||
*/
|
||||
jsbytecode *pc(JSContext *cx, JSStackFrame *next = NULL);
|
||||
|
||||
jsbytecode *prevpc() {
|
||||
JS_ASSERT((prev_ != NULL) && (flags_ & JSFRAME_HAS_PREVPC));
|
||||
return prevpc_;
|
||||
}
|
||||
|
||||
JSScript *script() const {
|
||||
JS_ASSERT(isScriptFrame());
|
||||
|
@ -367,7 +407,8 @@ struct JSStackFrame
|
|||
return hasArgsObj() ? &argsObj() : NULL;
|
||||
}
|
||||
|
||||
void setArgsObj(JSObject &obj);
|
||||
inline void setArgsObj(JSObject &obj);
|
||||
inline void clearArgsObj();
|
||||
|
||||
/*
|
||||
* This value
|
||||
|
@ -469,6 +510,7 @@ struct JSStackFrame
|
|||
inline JSObject *maybeCallObj() const;
|
||||
inline void setScopeChainNoCallObj(JSObject &obj);
|
||||
inline void setScopeChainAndCallObj(JSObject &obj);
|
||||
inline void clearCallObj();
|
||||
|
||||
/* Block chain */
|
||||
|
||||
|
@ -570,12 +612,21 @@ struct JSStackFrame
|
|||
return &rval_;
|
||||
}
|
||||
|
||||
void setAssignedReturnValue(const js::Value &v) {
|
||||
flags_ |= JSFRAME_RVAL_ASSIGNED;
|
||||
setReturnValue(v);
|
||||
}
|
||||
|
||||
/* Native-code return address */
|
||||
|
||||
void *nativeReturnAddress() const {
|
||||
return ncode_;
|
||||
}
|
||||
|
||||
void setNativeReturnAddress(void *addr) {
|
||||
ncode_ = addr;
|
||||
}
|
||||
|
||||
void **addressOfNativeReturnAddress() {
|
||||
return &ncode_;
|
||||
}
|
||||
|
@ -717,10 +768,6 @@ struct JSStackFrame
|
|||
return offsetof(JSStackFrame, prev_);
|
||||
}
|
||||
|
||||
static size_t offsetOfSavedpc() {
|
||||
return offsetof(JSStackFrame, savedpc_);
|
||||
}
|
||||
|
||||
static size_t offsetOfReturnValue() {
|
||||
return offsetof(JSStackFrame, rval_);
|
||||
}
|
||||
|
@ -763,9 +810,6 @@ struct JSStackFrame
|
|||
void methodjitStaticAsserts();
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Magic value to represent invalid JSStackFrame::savedpc entry. */
|
||||
static jsbytecode *const sInvalidpc;
|
||||
|
||||
/* Poison scopeChain value set before a frame is flushed. */
|
||||
static JSObject *const sInvalidScopeChain;
|
||||
#endif
|
||||
|
|
|
@ -50,11 +50,11 @@ JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
|
|||
JS_ASSERT(fun == callee.getFunctionPrivate());
|
||||
|
||||
/* Initialize stack frame members. */
|
||||
flags_ = JSFRAME_FUNCTION | flagsArg;
|
||||
flags_ = JSFRAME_FUNCTION | JSFRAME_HAS_PREVPC | flagsArg;
|
||||
exec.fun = fun;
|
||||
args.nactual = nactual; /* only need to write if over/under-flow */
|
||||
scopeChain_ = callee.getParent();
|
||||
/* savedpc_, prev_ initialized by push*Frame */
|
||||
/* prevpc_, prev_ initialized by push*Frame */
|
||||
JS_ASSERT(!hasImacropc());
|
||||
JS_ASSERT(!hasHookData());
|
||||
rval_.setUndefined();
|
||||
|
@ -74,9 +74,6 @@ JSStackFrame::initCallFrameCallerHalf(JSContext *cx, JSObject &scopeChain,
|
|||
JSFRAME_UNDERFLOW_ARGS)) == 0);
|
||||
JSFrameRegs *regs = cx->regs;
|
||||
|
||||
/* Save caller pc. */
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
|
||||
/* Initialize the caller half of the stack frame members. */
|
||||
flags_ = JSFRAME_FUNCTION | flagsArg;
|
||||
args.nactual = nactual; /* only need to write if over/under-flow */
|
||||
|
@ -99,9 +96,6 @@ JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, void *ncode)
|
|||
/* Initialize state that gets set early in a jitted function's prologue. */
|
||||
exec.fun = fun;
|
||||
ncode_ = ncode;
|
||||
#ifdef DEBUG
|
||||
savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -118,41 +112,43 @@ JSStackFrame::initCallFrameLatePrologue()
|
|||
}
|
||||
|
||||
inline void
|
||||
JSStackFrame::initEvalFrame(JSScript *script, JSStackFrame *downFrame, uint32 flagsArg)
|
||||
JSStackFrame::initEvalFrame(JSScript *script, JSStackFrame *prev,
|
||||
jsbytecode *prevpc, uint32 flagsArg)
|
||||
{
|
||||
JS_ASSERT(flagsArg & JSFRAME_EVAL);
|
||||
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
|
||||
JS_ASSERT(downFrame->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
|
||||
JS_ASSERT(prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
|
||||
|
||||
/* Copy (callee, thisv). */
|
||||
js::Value *dstvp = (js::Value *)this - 2;
|
||||
js::Value *srcvp = downFrame->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)
|
||||
? (js::Value *)downFrame - 2
|
||||
: downFrame->formalArgs() - 2;
|
||||
js::Value *srcvp = prev->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)
|
||||
? (js::Value *)prev - 2
|
||||
: prev->formalArgs() - 2;
|
||||
dstvp[0] = srcvp[0];
|
||||
dstvp[1] = srcvp[1];
|
||||
JS_ASSERT_IF(downFrame->flags_ & JSFRAME_FUNCTION,
|
||||
JS_ASSERT_IF(prev->flags_ & JSFRAME_FUNCTION,
|
||||
dstvp[0].toObject().isFunction());
|
||||
|
||||
/* Initialize stack frame members. */
|
||||
flags_ = flagsArg | (downFrame->flags_ & (JSFRAME_FUNCTION |
|
||||
flags_ = flagsArg | JSFRAME_HAS_PREVPC |
|
||||
(prev->flags_ & (JSFRAME_FUNCTION |
|
||||
JSFRAME_GLOBAL |
|
||||
JSFRAME_HAS_CALL_OBJ));
|
||||
if (isFunctionFrame()) {
|
||||
exec = downFrame->exec;
|
||||
exec = prev->exec;
|
||||
args.script = script;
|
||||
} else {
|
||||
exec.script = script;
|
||||
}
|
||||
scopeChain_ = &downFrame->scopeChain();
|
||||
JS_ASSERT_IF(isFunctionFrame(), &callObj() == &downFrame->callObj());
|
||||
/* savedpc initialized by pushExecuteFrame */
|
||||
prev_ = downFrame;
|
||||
scopeChain_ = &prev->scopeChain();
|
||||
JS_ASSERT_IF(isFunctionFrame(), &callObj() == &prev->callObj());
|
||||
|
||||
setPrev(prev, prevpc);
|
||||
JS_ASSERT(!hasImacropc());
|
||||
JS_ASSERT(!hasHookData());
|
||||
rval_.setUndefined();
|
||||
blockChain_ = NULL;
|
||||
setAnnotation(downFrame->annotation());
|
||||
setAnnotation(prev->annotation());
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -166,11 +162,11 @@ JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg
|
|||
vp[1].setUndefined(); /* Set after frame pushed using thisObject */
|
||||
|
||||
/* Initialize stack frame members. */
|
||||
flags_ = flagsArg | JSFRAME_GLOBAL;
|
||||
flags_ = flagsArg | JSFRAME_GLOBAL | JSFRAME_HAS_PREVPC;
|
||||
exec.script = script;
|
||||
args.script = (JSScript *)0xbad;
|
||||
scopeChain_ = &chain;
|
||||
/* savedpc initialized by pushExecuteFrame */
|
||||
|
||||
prev_ = NULL;
|
||||
JS_ASSERT(!hasImacropc());
|
||||
JS_ASSERT(!hasHookData());
|
||||
|
@ -183,8 +179,8 @@ inline void
|
|||
JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
|
||||
{
|
||||
js::PodZero(this);
|
||||
flags_ = JSFRAME_DUMMY;
|
||||
prev_ = cx->maybefp();
|
||||
flags_ = JSFRAME_DUMMY | JSFRAME_HAS_PREVPC;
|
||||
setPrev(cx->regs);
|
||||
chain.isGlobal();
|
||||
setScopeChainNoCallObj(chain);
|
||||
}
|
||||
|
@ -288,13 +284,6 @@ JSStackFrame::varobj(JSContext *cx) const
|
|||
return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj();
|
||||
}
|
||||
|
||||
inline jsbytecode *
|
||||
JSStackFrame::pc(JSContext *cx) const
|
||||
{
|
||||
JS_ASSERT(cx->regs && cx->containingSegment(this) != NULL);
|
||||
return (cx->regs->fp == this) ? cx->regs->pc : savedpc_;
|
||||
}
|
||||
|
||||
inline uintN
|
||||
JSStackFrame::numActualArgs() const
|
||||
{
|
||||
|
@ -336,6 +325,14 @@ JSStackFrame::setArgsObj(JSObject &obj)
|
|||
flags_ |= JSFRAME_HAS_ARGS_OBJ;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSStackFrame::clearArgsObj()
|
||||
{
|
||||
JS_ASSERT(hasArgsObj());
|
||||
args.nactual = args.obj->getArgsInitialLength();
|
||||
flags_ ^= JSFRAME_HAS_ARGS_OBJ;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSStackFrame::setScopeChainNoCallObj(JSObject &obj)
|
||||
{
|
||||
|
@ -360,6 +357,13 @@ JSStackFrame::setScopeChainAndCallObj(JSObject &obj)
|
|||
flags_ |= JSFRAME_HAS_CALL_OBJ;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSStackFrame::clearCallObj()
|
||||
{
|
||||
JS_ASSERT(hasCallObj());
|
||||
flags_ ^= JSFRAME_HAS_CALL_OBJ;
|
||||
}
|
||||
|
||||
inline JSObject &
|
||||
JSStackFrame::callObj() const
|
||||
{
|
||||
|
|
|
@ -1271,7 +1271,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
|
||||
/* Copy frame onto the stack. */
|
||||
stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
|
||||
stackfp->repointGeneratorFrameDown(cx->maybefp());
|
||||
stackfp->setPrev(cx->regs);
|
||||
stackfp->unsetFloatingGenerator();
|
||||
RebaseRegsFromTo(&gen->regs, genfp, stackfp);
|
||||
MUST_FLOW_THROUGH("restore");
|
||||
|
|
|
@ -310,7 +310,10 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
|
||||
/* regs->sp = sp */
|
||||
storePtr(ClobberInCall,
|
||||
FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, sp)));
|
||||
FrameAddress(offsetof(VMFrame, regs.sp)));
|
||||
|
||||
/* regs->fp = fp */
|
||||
storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
}
|
||||
|
||||
void setupVMFrame() {
|
||||
|
@ -332,23 +335,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
return MacroAssembler::call(reg);
|
||||
}
|
||||
|
||||
void restoreReturnAddress()
|
||||
{
|
||||
#ifndef JS_CPU_ARM
|
||||
/* X86 and X64's "ret" instruction expects a return address on the stack. */
|
||||
push(Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||
#else
|
||||
/* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
|
||||
* always emits a return to LR. */
|
||||
load32(Address(JSFrameReg, JSStackFrame::offsetOfncode()), JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void saveReturnAddress(RegisterID reg)
|
||||
{
|
||||
storePtr(reg, Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||
}
|
||||
|
||||
void finalize(uint8 *ncode) {
|
||||
JSC::JITCode jc(ncode, size());
|
||||
JSC::CodeBlock cb(jc);
|
||||
|
@ -367,6 +353,13 @@ static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = BaseAssembler::J
|
|||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = BaseAssembler::JSReturnReg_Data;
|
||||
static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = BaseAssembler::JSParamReg_Argc;
|
||||
|
||||
struct FrameFlagsAddress : JSC::MacroAssembler::Address
|
||||
{
|
||||
FrameFlagsAddress()
|
||||
: Address(JSFrameReg, JSStackFrame::offsetOfFlags())
|
||||
{}
|
||||
};
|
||||
|
||||
} /* namespace mjit */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -111,6 +111,11 @@ BytecodeAnalyzer::analyze(uint32 index)
|
|||
case JSOP_TRAP:
|
||||
return false;
|
||||
|
||||
case JSOP_SETRVAL:
|
||||
case JSOP_POPV:
|
||||
usesRval = true;
|
||||
break;
|
||||
|
||||
case JSOP_DEFAULT:
|
||||
case JSOP_GOTO:
|
||||
offs = (pc + JSOP_GOTO_LENGTH) - script->code;
|
||||
|
|
|
@ -65,10 +65,14 @@ namespace js
|
|||
OpcodeStatus *ops;
|
||||
Vector<jsbytecode *, 16, ContextAllocPolicy> doList;
|
||||
|
||||
/* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
|
||||
bool usesRval;
|
||||
|
||||
public:
|
||||
BytecodeAnalyzer(JSContext *cx, JSScript *script)
|
||||
: cx(cx), script(script), ops(NULL),
|
||||
doList(ContextAllocPolicy(cx))
|
||||
doList(ContextAllocPolicy(cx)),
|
||||
usesRval(false)
|
||||
{
|
||||
}
|
||||
~BytecodeAnalyzer();
|
||||
|
@ -78,6 +82,8 @@ namespace js
|
|||
|
||||
public:
|
||||
|
||||
bool usesReturnValue() const { return usesRval; }
|
||||
|
||||
inline const OpcodeStatus & operator [](uint32 offs) const {
|
||||
JS_ASSERT(offs < script->length);
|
||||
return ops[offs];
|
||||
|
|
|
@ -83,6 +83,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObj
|
|||
#if defined JS_POLYIC
|
||||
pics(ContextAllocPolicy(cx)),
|
||||
#endif
|
||||
callPatches(ContextAllocPolicy(cx)),
|
||||
callSites(ContextAllocPolicy(cx)),
|
||||
doubleList(ContextAllocPolicy(cx)),
|
||||
escapingList(ContextAllocPolicy(cx)),
|
||||
|
@ -178,27 +179,11 @@ mjit::TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *sco
|
|||
return status;
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::RegisterID
|
||||
mjit::Compiler::takeHWReturnAddress(Assembler &masm)
|
||||
{
|
||||
#ifndef JS_CPU_ARM
|
||||
JS_STATIC_ASSERT(JSParamReg_Argc != Registers::ReturnReg);
|
||||
masm.pop(Registers::ReturnReg);
|
||||
return Registers::ReturnReg;
|
||||
#else
|
||||
return JSC::ARMRegisters::lr;
|
||||
#endif
|
||||
}
|
||||
|
||||
CompileStatus
|
||||
mjit::Compiler::generatePrologue()
|
||||
{
|
||||
invokeLabel = masm.label();
|
||||
|
||||
RegisterID retAddr = takeHWReturnAddress(masm);
|
||||
restoreFrameRegs(masm);
|
||||
masm.saveReturnAddress(retAddr);
|
||||
|
||||
/*
|
||||
* If there is no function, then this can only be called via JaegerShot(),
|
||||
* which expects an existing frame to be initialized like the interpreter.
|
||||
|
@ -211,17 +196,11 @@ mjit::Compiler::generatePrologue()
|
|||
* either argc >= nargs or the arity check has corrected the frame.
|
||||
*/
|
||||
invokeLabel = masm.label();
|
||||
RegisterID retAddr = takeHWReturnAddress(masm);
|
||||
masm.saveReturnAddress(retAddr);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||
#endif
|
||||
|
||||
Label fastPath = masm.label();
|
||||
|
||||
/* Store these early on so slow paths can access them. */
|
||||
/* Store this early on so slow paths can access it. */
|
||||
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
|
||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
|
||||
{
|
||||
/*
|
||||
|
@ -231,11 +210,6 @@ mjit::Compiler::generatePrologue()
|
|||
* This loops back to entry point #2.
|
||||
*/
|
||||
arityLabel = stubcc.masm.label();
|
||||
RegisterID retAddr = takeHWReturnAddress(stubcc.masm);
|
||||
stubcc.masm.saveReturnAddress(retAddr);
|
||||
#ifdef DEBUG
|
||||
stubcc.masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||
#endif
|
||||
Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
|
||||
Imm32(fun->nargs));
|
||||
stubcc.crossJump(argMatch, fastPath);
|
||||
|
@ -440,10 +414,10 @@ mjit::Compiler::finishThisUp()
|
|||
script->callICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
|
||||
|
||||
/* Compute the hot call offset. */
|
||||
uint32 offset = fullCode.locationOf(callICs[i].hotCall) -
|
||||
uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
|
||||
fullCode.locationOf(callICs[i].funGuard);
|
||||
script->callICs[i].hotCallOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].hotCallOffset == offset);
|
||||
script->callICs[i].hotJumpOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].hotJumpOffset == offset);
|
||||
|
||||
/* Compute the join point offset. */
|
||||
offset = fullCode.locationOf(callICs[i].joinPoint) -
|
||||
|
@ -483,6 +457,24 @@ mjit::Compiler::finishThisUp()
|
|||
}
|
||||
#endif /* JS_MONOIC */
|
||||
|
||||
for (size_t i = 0; i < callPatches.length(); i++) {
|
||||
void *joinPoint = fullCode.locationOf(callPatches[i].joinPoint).executableAddress();
|
||||
|
||||
/* Patch the write of ncode in the hot path. */
|
||||
JSC::CodeLocationDataLabelPtr fastNcode =
|
||||
fullCode.locationOf(callPatches[i].fastNcodePatch);
|
||||
JSC::RepatchBuffer fastRepatch((uint8*)fastNcode.executableAddress() - 32, 64, false);
|
||||
fastRepatch.repatch(fastNcode, joinPoint);
|
||||
|
||||
/* Patch the write of ncode in the slow path. */
|
||||
if (callPatches[i].hasSlowNcode) {
|
||||
JSC::CodeLocationDataLabelPtr slowNcode =
|
||||
stubCode.locationOf(callPatches[i].slowNcodePatch);
|
||||
JSC::RepatchBuffer slowRepatch((uint8*)slowNcode.executableAddress() - 32, 64, false);
|
||||
slowRepatch.repatch(slowNcode, joinPoint);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined JS_POLYIC
|
||||
script->jit->nPICs = pics.length();
|
||||
if (pics.length()) {
|
||||
|
@ -666,6 +658,12 @@ mjit::Compiler::generateMethod()
|
|||
BEGIN_CASE(JSOP_POPV)
|
||||
BEGIN_CASE(JSOP_SETRVAL)
|
||||
{
|
||||
RegisterID reg = frame.allocReg();
|
||||
masm.load32(FrameFlagsAddress(), reg);
|
||||
masm.or32(Imm32(JSFRAME_RVAL_ASSIGNED), reg);
|
||||
masm.store32(reg, FrameFlagsAddress());
|
||||
frame.freeReg(reg);
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
|
||||
frame.pop();
|
||||
|
@ -673,12 +671,7 @@ mjit::Compiler::generateMethod()
|
|||
END_CASE(JSOP_POPV)
|
||||
|
||||
BEGIN_CASE(JSOP_RETURN)
|
||||
{
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
|
||||
frame.pop();
|
||||
emitReturn();
|
||||
}
|
||||
emitReturn(frame.peek(-1));
|
||||
END_CASE(JSOP_RETURN)
|
||||
|
||||
BEGIN_CASE(JSOP_GOTO)
|
||||
|
@ -1490,7 +1483,7 @@ mjit::Compiler::generateMethod()
|
|||
END_CASE(JSOP_DEFLOCALFUN)
|
||||
|
||||
BEGIN_CASE(JSOP_RETRVAL)
|
||||
emitReturn();
|
||||
emitReturn(NULL);
|
||||
END_CASE(JSOP_RETRVAL)
|
||||
|
||||
BEGIN_CASE(JSOP_GETGNAME)
|
||||
|
@ -1550,7 +1543,7 @@ mjit::Compiler::generateMethod()
|
|||
|
||||
BEGIN_CASE(JSOP_STOP)
|
||||
/* Safe point! */
|
||||
emitReturn();
|
||||
emitReturn(NULL);
|
||||
goto done;
|
||||
END_CASE(JSOP_STOP)
|
||||
|
||||
|
@ -1805,21 +1798,39 @@ mjit::Compiler::jsop_getglobal(uint32 index)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitReturn()
|
||||
mjit::Compiler::emitFinalReturn(Assembler &masm)
|
||||
{
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg);
|
||||
masm.jump(Registers::ReturnReg);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::loadReturnValue(Assembler &masm)
|
||||
{
|
||||
/*
|
||||
* if (!f.inlineCallCount)
|
||||
* return;
|
||||
* Load a return value from POPV or SETRVAL into the return registers,
|
||||
* otherwise return undefined.
|
||||
*/
|
||||
Jump noInlineCalls = masm.branchPtr(Assembler::Equal,
|
||||
FrameAddress(offsetof(VMFrame, entryFp)),
|
||||
JSFrameReg);
|
||||
stubcc.linkExit(noInlineCalls, Uses(frame.frameDepth()));
|
||||
stubcc.masm.restoreReturnAddress();
|
||||
stubcc.masm.ret();
|
||||
masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data);
|
||||
if (analysis.usesReturnValue()) {
|
||||
Jump rvalClear = masm.branchTest32(Assembler::Zero,
|
||||
FrameFlagsAddress(),
|
||||
Imm32(JSFRAME_RVAL_ASSIGNED));
|
||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm.loadValueAsComponents(rvalAddress,
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
rvalClear.linkTo(masm.label(), &masm);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT_IF(!fun, JSOp(*PC) == JSOP_STOP);
|
||||
|
||||
/* Only the top of the stack can be returned. */
|
||||
JS_ASSERT_IF(fe, fe == frame.peek(-1));
|
||||
|
||||
/*
|
||||
* If there's a function object, deal with the fact that it can escape.
|
||||
* Note that after we've placed the call object, all tracked state can
|
||||
|
@ -1832,42 +1843,44 @@ mjit::Compiler::emitReturn()
|
|||
if (fun) {
|
||||
if (fun->isHeavyweight()) {
|
||||
/* There will always be a call object. */
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::PutCallObject);
|
||||
prepareStubCall(Uses(fe ? 1 : 0));
|
||||
stubCall(stubs::PutActivationObjects);
|
||||
|
||||
if (fe) {
|
||||
masm.loadValueAsComponents(frame.addressOf(fe),
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
emitFinalReturn(masm);
|
||||
frame.discardFrame();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */
|
||||
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
||||
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
||||
stubcc.linkExit(putObjs, Uses(frame.frameDepth()));
|
||||
frame.discardFrame();
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::PutActivationObjects);
|
||||
stubcc.rejoin(Changes(0));
|
||||
|
||||
if (fe) {
|
||||
stubcc.masm.loadValueAsComponents(frame.addressOf(fe),
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
} else {
|
||||
loadReturnValue(stubcc.masm);
|
||||
}
|
||||
|
||||
emitFinalReturn(stubcc.masm);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* r = fp->prev
|
||||
* f.fp = r
|
||||
*/
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
|
||||
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
if (fe)
|
||||
frame.storeTo(fe, JSReturnReg_Data, JSReturnReg_Type, Registers::ReturnReg);
|
||||
else
|
||||
loadReturnValue(masm);
|
||||
|
||||
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data);
|
||||
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type);
|
||||
|
||||
Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm.loadValueAsComponents(rval, JSReturnReg_Type, JSReturnReg_Data);
|
||||
masm.restoreReturnAddress();
|
||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||
#endif
|
||||
masm.ret();
|
||||
emitFinalReturn(masm);
|
||||
frame.discardFrame();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1955,6 +1968,9 @@ mjit::Compiler::emitPrimitiveTestForNew(uint32 argc)
|
|||
void
|
||||
mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
||||
{
|
||||
CallPatchInfo callPatch;
|
||||
callPatch.hasSlowNcode = false;
|
||||
|
||||
RegisterID r0 = Registers::ReturnReg;
|
||||
VoidPtrStubUInt32 stub = callingNew ? stubs::UncachedNew : stubs::UncachedCall;
|
||||
|
||||
|
@ -1966,12 +1982,21 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
|||
|
||||
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
|
||||
|
||||
masm.call(r0);
|
||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
||||
callPatch.fastNcodePatch =
|
||||
masm.storePtrWithPatch(ImmPtr(NULL),
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||
|
||||
masm.jump(r0);
|
||||
|
||||
#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
|
||||
masm.callLabel = masm.label();
|
||||
#endif
|
||||
ADD_CALLSITE(false);
|
||||
|
||||
callPatch.joinPoint = masm.label();
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
||||
|
||||
if (callingNew)
|
||||
emitPrimitiveTestForNew(argc);
|
||||
|
||||
|
@ -1982,6 +2007,7 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
|||
|
||||
stubcc.linkExitDirect(notCompiled, stubcc.masm.label());
|
||||
stubcc.rejoin(Changes(0));
|
||||
callPatches.append(callPatch);
|
||||
}
|
||||
|
||||
/* See MonoIC.cpp, CallCompiler for more information on call ICs. */
|
||||
|
@ -2006,6 +2032,8 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
CallGenInfo callIC(argc);
|
||||
uint32 callICIndex = callICs.length();
|
||||
|
||||
CallPatchInfo callPatch;
|
||||
|
||||
/*
|
||||
* Save constant |this| to optimize thisv stores for common call cases
|
||||
* like CALL[LOCAL, GLOBAL, ARG] which push NULL.
|
||||
|
@ -2062,7 +2090,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
Jump j = masm.branchPtrWithPatch(Assembler::NotEqual, dataReg, callIC.funGuard);
|
||||
callIC.funJump = j;
|
||||
|
||||
Jump oolCallDone;
|
||||
Jump rejoin1, rejoin2;
|
||||
{
|
||||
stubcc.linkExitDirect(j, stubcc.masm.label());
|
||||
|
@ -2130,8 +2157,11 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
Registers::ReturnReg);
|
||||
stubcc.masm.move(Imm32(argc), JSParamReg_Argc);
|
||||
stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
||||
stubcc.masm.call(Registers::ReturnReg);
|
||||
oolCallDone = stubcc.masm.jump();
|
||||
callPatch.hasSlowNcode = true;
|
||||
callPatch.slowNcodePatch =
|
||||
stubcc.masm.storePtrWithPatch(ImmPtr(NULL),
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||
stubcc.masm.jump(Registers::ReturnReg);
|
||||
|
||||
/* Catch-all case, for natives this will turn into a MIC. */
|
||||
if (notObjectJump.isSet())
|
||||
|
@ -2163,12 +2193,11 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
flags |= JSFRAME_CONSTRUCTING;
|
||||
|
||||
InlineFrameAssembler inlFrame(masm, callIC, flags);
|
||||
inlFrame.assemble();
|
||||
callPatch.fastNcodePatch = inlFrame.assemble(NULL);
|
||||
|
||||
callIC.hotCall = masm.call();
|
||||
stubcc.crossJump(oolCallDone, masm.label());
|
||||
|
||||
callIC.joinPoint = masm.label();
|
||||
callIC.hotJump = masm.jump();
|
||||
callIC.joinPoint = callPatch.joinPoint = masm.label();
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
||||
|
||||
/*
|
||||
* Functions invoked with |new| can return primitive values.
|
||||
|
@ -2188,6 +2217,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
stubcc.rejoin(Changes(0));
|
||||
|
||||
callICs.append(callIC);
|
||||
callPatches.append(callPatch);
|
||||
#else
|
||||
emitUncachedCall(argc, callingNew);
|
||||
#endif
|
||||
|
@ -2739,6 +2769,7 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom)
|
|||
|
||||
/* Force into a register because getprop won't expect a constant. */
|
||||
RegisterID reg = frame.allocReg();
|
||||
|
||||
masm.move(ImmPtr(obj), reg);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ class Compiler
|
|||
uint32 argc;
|
||||
DataLabelPtr funGuard;
|
||||
Jump funJump;
|
||||
Call hotCall;
|
||||
Jump hotJump;
|
||||
Call oolCall;
|
||||
Label joinPoint;
|
||||
Label slowJoinPoint;
|
||||
|
@ -135,6 +135,17 @@ class Compiler
|
|||
private:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Writes of call return addresses which needs to be delayed until the final
|
||||
* absolute address of the join point is known.
|
||||
*/
|
||||
struct CallPatchInfo {
|
||||
Label joinPoint;
|
||||
DataLabelPtr fastNcodePatch;
|
||||
DataLabelPtr slowNcodePatch;
|
||||
bool hasSlowNcode;
|
||||
};
|
||||
|
||||
#if defined JS_POLYIC
|
||||
struct PICGenInfo {
|
||||
PICGenInfo(ic::PICInfo::Kind kind) : kind(kind)
|
||||
|
@ -215,6 +226,7 @@ class Compiler
|
|||
#if defined JS_POLYIC
|
||||
js::Vector<PICGenInfo, 64> pics;
|
||||
#endif
|
||||
js::Vector<CallPatchInfo, 64> callPatches;
|
||||
js::Vector<InternalCallSite, 64> callSites;
|
||||
js::Vector<DoublePatch, 16> doubleList;
|
||||
js::Vector<uint32, 16> escapingList;
|
||||
|
@ -253,8 +265,6 @@ class Compiler
|
|||
void addCallSite(uint32 id, bool stub);
|
||||
|
||||
/* Emitting helpers. */
|
||||
RegisterID takeHWReturnAddress(Assembler &masm);
|
||||
void restoreReturnAddress(Assembler &masm);
|
||||
void restoreFrameRegs(Assembler &masm);
|
||||
void emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
void iter(uintN flags);
|
||||
|
@ -271,7 +281,9 @@ class Compiler
|
|||
void jsop_getprop_slow();
|
||||
void jsop_getarg(uint32 index);
|
||||
void jsop_this();
|
||||
void emitReturn();
|
||||
void emitReturn(FrameEntry *fe);
|
||||
void emitFinalReturn(Assembler &masm);
|
||||
void loadReturnValue(Assembler &masm);
|
||||
void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
|
||||
void interruptCheckHelper();
|
||||
void emitUncachedCall(uint32 argc, bool callingNew);
|
||||
|
|
|
@ -327,6 +327,49 @@ FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FrameState::storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg, RegisterID tempReg)
|
||||
{
|
||||
JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
|
||||
|
||||
if (fe->isConstant()) {
|
||||
masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
if (fe->isTypeKnown()) {
|
||||
RegisterID data = tempRegForData(fe);
|
||||
if (data != dataReg)
|
||||
masm.move(data, dataReg);
|
||||
masm.move(ImmType(fe->getKnownType()), typeReg);
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterID data = tempRegForData(fe);
|
||||
RegisterID type = tempRegForType(fe);
|
||||
if (data == typeReg && type == dataReg) {
|
||||
masm.move(type, tempReg);
|
||||
masm.move(data, dataReg);
|
||||
masm.move(tempReg, typeReg);
|
||||
} else if (data != dataReg) {
|
||||
if (type == typeReg) {
|
||||
masm.move(data, dataReg);
|
||||
} else if (type != dataReg) {
|
||||
masm.move(data, dataReg);
|
||||
if (type != typeReg)
|
||||
masm.move(type, typeReg);
|
||||
} else {
|
||||
JS_ASSERT(data != typeReg);
|
||||
masm.move(type, typeReg);
|
||||
masm.move(data, dataReg);
|
||||
}
|
||||
} else if (type != typeReg) {
|
||||
masm.move(type, typeReg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
FrameState::assertValidRegisterState() const
|
||||
|
|
|
@ -586,6 +586,12 @@ class FrameState
|
|||
*/
|
||||
void storeTo(FrameEntry *fe, Address address, bool popHint = false);
|
||||
|
||||
/*
|
||||
* Fully stores a FrameEntry into two arbitrary registers. tempReg may be
|
||||
* used as a temporary.
|
||||
*/
|
||||
void storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg, RegisterID tempReg);
|
||||
|
||||
/*
|
||||
* Stores the top stack slot back to a slot.
|
||||
*/
|
||||
|
|
|
@ -71,6 +71,7 @@ class InlineFrameAssembler {
|
|||
typedef JSC::MacroAssembler::Address Address;
|
||||
typedef JSC::MacroAssembler::Imm32 Imm32;
|
||||
typedef JSC::MacroAssembler::ImmPtr ImmPtr;
|
||||
typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
|
||||
|
||||
Assembler &masm;
|
||||
uint32 frameDepth; // script->nfixed + stack depth at caller call site
|
||||
|
@ -105,24 +106,27 @@ class InlineFrameAssembler {
|
|||
tempRegs.takeReg(funObjReg);
|
||||
}
|
||||
|
||||
inline void assemble()
|
||||
DataLabelPtr assemble(void *ncode)
|
||||
{
|
||||
JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
|
||||
|
||||
RegisterID t0 = tempRegs.takeAnyReg();
|
||||
|
||||
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||
|
||||
AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
||||
masm.store32(Imm32(JSFRAME_FUNCTION | flags), adj.addrOf(JSStackFrame::offsetOfFlags()));
|
||||
masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
|
||||
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetOfScopeChain()));
|
||||
masm.storePtr(JSFrameReg, adj.addrOf(JSStackFrame::offsetOfPrev()));
|
||||
|
||||
DataLabelPtr ncodePatch =
|
||||
masm.storePtrWithPatch(ImmPtr(ncode), adj.addrOf(JSStackFrame::offsetOfncode()));
|
||||
|
||||
/* Adjust JSFrameReg. Callee fills in the rest. */
|
||||
masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);
|
||||
|
||||
tempRegs.putReg(t0);
|
||||
|
||||
return ncodePatch;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "jsobjinlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsatominlines.h"
|
||||
#include "StubCalls-inl.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
|
@ -72,19 +73,8 @@ using namespace js;
|
|||
using namespace js::mjit;
|
||||
using namespace JSC;
|
||||
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
return v; \
|
||||
} while (0)
|
||||
static bool
|
||||
InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame = JS_TRUE);
|
||||
|
||||
static jsbytecode *
|
||||
FindExceptionHandler(JSContext *cx)
|
||||
|
@ -179,8 +169,16 @@ top:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up a frame and return. popFrame indicates whether to additionally pop
|
||||
* the frame and store the return value on the caller's stack. The frame will
|
||||
* normally be popped by the caller on return from a call into JIT code,
|
||||
* so must be popped here when that caller code will not execute. This can be
|
||||
* either because of a call into an un-JITable script, or because the call is
|
||||
* throwing an exception.
|
||||
*/
|
||||
static bool
|
||||
InlineReturn(VMFrame &f, JSBool ok)
|
||||
InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = f.regs.fp;
|
||||
|
@ -213,9 +211,11 @@ InlineReturn(VMFrame &f, JSBool ok)
|
|||
if (fp->isConstructing() && fp->returnValue().isPrimitive())
|
||||
fp->setReturnValue(fp->thisValue());
|
||||
|
||||
if (popFrame) {
|
||||
Value *newsp = fp->actualArgs() - 1;
|
||||
newsp[-1] = fp->returnValue();
|
||||
cx->stack().popInlineFrame(cx, fp->prev(), newsp);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -317,10 +317,11 @@ stubs::FixupArity(VMFrame &f, uint32 nactual)
|
|||
void *ncode = oldfp->nativeReturnAddress();
|
||||
|
||||
/* Pop the inline frame. */
|
||||
RemovePartialFrame(cx, oldfp);
|
||||
f.fp() = oldfp->prev();
|
||||
f.regs.sp = (Value*) oldfp;
|
||||
|
||||
/* Reserve enough space for a callee frame. */
|
||||
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, cx->regs->sp, nactual,
|
||||
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual,
|
||||
fun, fun->script(), &flags,
|
||||
f.entryFp, &f.stackLimit);
|
||||
if (!newfp)
|
||||
|
@ -356,11 +357,10 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
|
||||
/*
|
||||
* FixupArity/RemovePartialFrame expect to be called after the early
|
||||
* prologue. Pass null for ncode: either we will jump into jit code, which
|
||||
* will set ncode, or we will jump into js::Interpret, which does not care
|
||||
* about ncode.
|
||||
* prologue. Pass the existing value for ncode, it has already been set
|
||||
* by the jit code calling into this stub.
|
||||
*/
|
||||
fp->initCallFrameEarlyPrologue(fun, NULL);
|
||||
fp->initCallFrameEarlyPrologue(fun, fp->nativeReturnAddress());
|
||||
|
||||
/* Empty script does nothing. */
|
||||
if (script->isEmpty()) {
|
||||
|
@ -897,11 +897,12 @@ RunTracer(VMFrame &f)
|
|||
if (op == JSOP_RETURN && !entryFrame->isBailedAtReturn())
|
||||
entryFrame->setReturnValue(f.regs.sp[-1]);
|
||||
|
||||
/* Don't pop the frame if it's maybe owned by an Invoke. */
|
||||
/* Cleanup activation objects on the frame unless it's owned by an Invoke. */
|
||||
if (f.fp() != f.entryFp) {
|
||||
if (!InlineReturn(f, JS_TRUE))
|
||||
if (!InlineReturn(f, JS_TRUE, JS_FALSE))
|
||||
THROWV(NULL);
|
||||
}
|
||||
|
||||
void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn);
|
||||
*f.returnAddressLocation() = retPtr;
|
||||
return NULL;
|
||||
|
|
|
@ -61,14 +61,14 @@ JSStackFrame::methodjitStaticAsserts()
|
|||
#if defined(JS_CPU_X86)
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x18);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 0x1C);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x2C);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x14);
|
||||
/* ARM uses decimal literals. */
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 24);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 28);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 44);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 20);
|
||||
#elif defined(JS_CPU_X64)
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x30);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x50);
|
||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x28);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -76,13 +76,11 @@ JSStackFrame::methodjitStaticAsserts()
|
|||
* 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.
|
||||
* creates a VMFrame on the machine stack and jumps into JIT'd code. The JIT'd
|
||||
* code will eventually jump back to the VMFrame.
|
||||
*
|
||||
* - Called from C++ function EnterMethodJIT.
|
||||
* - Parameters: cx, fp, code, stackLimit, safePoint
|
||||
* - Notes: safePoint is used in combination with SafePointTrampoline,
|
||||
* explained further down.
|
||||
* - Parameters: cx, fp, code, stackLimit
|
||||
*
|
||||
* JaegerThrowpoline - Calls into an exception handler from JIT'd code, and if a
|
||||
* scripted exception handler is not found, unwinds the VMFrame and returns
|
||||
|
@ -100,19 +98,6 @@ JSStackFrame::methodjitStaticAsserts()
|
|||
* 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 JaegerShotAtSafePoint, 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
|
||||
|
@ -126,11 +111,15 @@ static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
|
|||
static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
#endif
|
||||
|
||||
extern "C" void JaegerTrampolineReturn();
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
PushActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.previous = JS_METHODJIT_DATA(f.cx).activeFrame;
|
||||
JS_METHODJIT_DATA(f.cx).activeFrame = &f;
|
||||
|
||||
f.regs.fp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
||||
}
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
|
@ -229,10 +218,7 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
/* Space for the rest of the VMFrame. */
|
||||
"subq $0x28, %rsp" "\n"
|
||||
|
||||
/*
|
||||
* This is actually part of the VMFrame, but we need to save |r8| for
|
||||
* SafePointTrampoline.
|
||||
*/
|
||||
/* This is actually part of the VMFrame. */
|
||||
"pushq %r8" "\n"
|
||||
|
||||
/* Set cx->regs and set the active frame. Save rdx and align frame in one. */
|
||||
|
@ -242,10 +228,16 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
|
||||
|
||||
/*
|
||||
* Jump into into the JIT'd code.
|
||||
*/
|
||||
"call *0(%rsp)" "\n"
|
||||
/* Jump into the JIT'd code. */
|
||||
"jmp *0(%rsp)" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n"
|
||||
SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n"
|
||||
"or %rdx, %rcx" "\n"
|
||||
"movq %rcx, 0x30(%rbx)" "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
|
||||
|
||||
|
@ -285,21 +277,12 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
|
|||
|
||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
||||
"popq %rax" "\n"
|
||||
"movq %rax, 0x50(%rbx)" "\n"
|
||||
"jmp *8(%rsp)" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
"movq 0x30(%rbx), %rcx" "\n" /* load fp->rval_ into typeReg */
|
||||
"movq 0x50(%rbx), %rax" "\n" /* fp->ncode_ */
|
||||
"movq 0x28(%rbx), %rax" "\n" /* fp->ncode_ */
|
||||
|
||||
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */
|
||||
"movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */
|
||||
|
@ -349,7 +332,15 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
|
||||
|
||||
"call *16(%ebp)" "\n"
|
||||
"jmp *16(%ebp)" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n"
|
||||
SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n"
|
||||
"movl %edx, 0x18(%ebx)" "\n"
|
||||
"movl %ecx, 0x1C(%ebx)" "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
|
||||
|
||||
|
@ -399,23 +390,9 @@ asm volatile (
|
|||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
"movl 0x18(%ebx), %edx" "\n" /* fp->rval_ data */
|
||||
"movl 0x1C(%ebx), %ecx" "\n" /* fp->rval_ type */
|
||||
"movl 0x2C(%ebx), %eax" "\n" /* fp->ncode_ */
|
||||
"movl 0x14(%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, 0x2C(%ebx)" "\n"
|
||||
"jmp *24(%ebp)" "\n"
|
||||
"jmp *%eax" "\n"
|
||||
);
|
||||
|
||||
# elif defined(JS_CPU_ARM)
|
||||
|
@ -448,31 +425,13 @@ FUNCTION_HEADER_EXTRA
|
|||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||
/* Restore frame regs. */
|
||||
"ldr lr, [r11, #44]" "\n" /* fp->ncode */
|
||||
"ldr lr, [r11, #20]" "\n" /* fp->ncode */
|
||||
"ldr r1, [r11, #24]" "\n" /* fp->rval data */
|
||||
"ldr r2, [r11, #28]" "\n" /* fp->rval type */
|
||||
"ldr r11, [sp, #28]" "\n" /* load f.fp */
|
||||
"bx lr" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
FUNCTION_HEADER_EXTRA
|
||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||
SYMBOL_STRING(SafePointTrampoline) ":"
|
||||
/*
|
||||
* On entry to SafePointTrampoline:
|
||||
* r11 = fp
|
||||
* sp[80] = safePoint
|
||||
*/
|
||||
"ldr ip, [sp, #80]" "\n"
|
||||
/* Save the return address (in JaegerTrampoline) to fp->ncode. */
|
||||
"str lr, [r11, #44]" "\n"
|
||||
/* Jump to 'safePoint' via 'ip' because a load into the PC from an address on
|
||||
* the stack looks like a return, and may upset return stack prediction. */
|
||||
"bx ip" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
FUNCTION_HEADER_EXTRA
|
||||
|
@ -484,7 +443,6 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
* r1 = fp
|
||||
* r2 = code
|
||||
* r3 = stackLimit
|
||||
* sp[0] = safePoint
|
||||
*
|
||||
* The VMFrame for ARM looks like this:
|
||||
* [ lr ] \
|
||||
|
@ -521,7 +479,7 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
|
||||
/* Preserve 'code' (r2) in an arbitrary callee-saved register. */
|
||||
" mov r4, r2" "\n"
|
||||
/* Preserve 'fp' (r1) in r11 (JSFrameReg) for SafePointTrampoline. */
|
||||
/* Preserve 'fp' (r1) in r11 (JSFrameReg). */
|
||||
" mov r11, r1" "\n"
|
||||
|
||||
" mov r0, sp" "\n"
|
||||
|
@ -530,7 +488,16 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
" blx " SYMBOL_STRING_VMFRAME(PushActiveVMFrame)"\n"
|
||||
|
||||
/* Call the compiled JavaScript function. */
|
||||
" blx r4" "\n"
|
||||
" bx r4" "\n"
|
||||
);
|
||||
|
||||
asm volatile (
|
||||
".text\n"
|
||||
FUNCTION_HEADER_EXTRA
|
||||
".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n"
|
||||
SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n"
|
||||
" str r1, [r11, #24]" "\n" /* fp->rval data */
|
||||
" str r2, [r11, #28]" "\n" /* fp->rval type */
|
||||
|
||||
/* Tidy up. */
|
||||
" mov r0, sp" "\n"
|
||||
|
@ -608,24 +575,14 @@ extern "C" {
|
|||
__asm {
|
||||
mov edx, [ebx + 0x18];
|
||||
mov ecx, [ebx + 0x1C];
|
||||
mov eax, [ebx + 0x2C];
|
||||
mov eax, [ebx + 0x14];
|
||||
mov ebx, [esp + 0x1C];
|
||||
push eax;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void SafePointTrampoline()
|
||||
{
|
||||
__asm {
|
||||
pop eax;
|
||||
mov [ebx + 0x2C], eax;
|
||||
jmp [ebp + 24];
|
||||
jmp eax;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
||||
Value *stackLimit, void *safePoint)
|
||||
Value *stackLimit)
|
||||
{
|
||||
__asm {
|
||||
/* Prologue. */
|
||||
|
@ -651,7 +608,15 @@ extern "C" {
|
|||
mov ecx, esp;
|
||||
call PushActiveVMFrame;
|
||||
|
||||
call [ebp + 16];
|
||||
jmp dword ptr [ebp + 16];
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void JaegerTrampolineReturn()
|
||||
{
|
||||
__asm {
|
||||
mov [ebx + 0x18], edx;
|
||||
mov [ebx + 0x1C], ecx;
|
||||
mov ecx, esp;
|
||||
call PopActiveVMFrame;
|
||||
|
||||
|
@ -756,11 +721,10 @@ ThreadData::Finish()
|
|||
}
|
||||
|
||||
extern "C" JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
||||
Value *stackLimit, void *safePoint);
|
||||
extern "C" void SafePointTrampoline();
|
||||
Value *stackLimit);
|
||||
|
||||
static inline JSBool
|
||||
EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
||||
EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code)
|
||||
{
|
||||
JS_ASSERT(cx->regs);
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE;);
|
||||
|
@ -769,8 +733,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
|||
Profiler prof;
|
||||
JSScript *script = fp->script();
|
||||
|
||||
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
|
||||
safePoint ? "dropping" : "entering",
|
||||
JaegerSpew(JSpew_Prof, "%s jaeger script, line %d\n",
|
||||
script->filename, script->lineno);
|
||||
prof.start();
|
||||
#endif
|
||||
|
@ -786,7 +749,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
|||
JSFrameRegs *oldRegs = cx->regs;
|
||||
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
||||
JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit, safePoint);
|
||||
JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit);
|
||||
|
||||
cx->setCurrentRegs(oldRegs);
|
||||
|
||||
|
@ -814,7 +777,7 @@ mjit::JaegerShot(JSContext *cx)
|
|||
|
||||
JS_ASSERT(cx->regs->pc == script->code);
|
||||
|
||||
return EnterMethodJIT(cx, cx->fp(), script->jit->invoke, NULL);
|
||||
return EnterMethodJIT(cx, cx->fp(), script->jit->invoke);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -824,9 +787,7 @@ js::mjit::JaegerShotAtSafePoint(JSContext *cx, void *safePoint)
|
|||
JS_ASSERT(!TRACE_RECORDER(cx));
|
||||
#endif
|
||||
|
||||
void *code = JS_FUNC_TO_DATA_PTR(void *, SafePointTrampoline);
|
||||
|
||||
return EnterMethodJIT(cx, cx->fp(), code, safePoint);
|
||||
return EnterMethodJIT(cx, cx->fp(), safePoint);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -317,7 +317,7 @@ class CallCompiler
|
|||
RegisterID t0 = inlFrame.tempRegs.takeAnyReg();
|
||||
|
||||
/* Generate the inline frame creation. */
|
||||
inlFrame.assemble();
|
||||
inlFrame.assemble(ic.funGuard.labelAtOffset(ic.joinPointOffset).executableAddress());
|
||||
|
||||
/* funPtrReg is still valid. Check if a compilation is needed. */
|
||||
Address scriptAddr(ic.funPtrReg, offsetof(JSFunction, u) +
|
||||
|
@ -338,35 +338,25 @@ class CallCompiler
|
|||
JSC::MacroAssembler::Call tryCompile =
|
||||
masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
|
||||
script->code, ic.frameDepth);
|
||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
||||
|
||||
Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
|
||||
Registers::ReturnReg);
|
||||
|
||||
masm.call(Registers::ReturnReg);
|
||||
Jump done = masm.jump();
|
||||
masm.jump(Registers::ReturnReg);
|
||||
|
||||
hasCode.linkTo(masm.label(), &masm);
|
||||
|
||||
/* Get nmap[ARITY], set argc, call. */
|
||||
masm.move(Imm32(ic.argc), JSParamReg_Argc);
|
||||
masm.loadPtr(Address(t0, offsetof(JITScript, arityCheck)), t0);
|
||||
masm.call(t0);
|
||||
|
||||
/* Rejoin with the fast path. */
|
||||
Jump rejoin = masm.jump();
|
||||
|
||||
/* Worst case - function didn't compile. */
|
||||
notCompiled.linkTo(masm.label(), &masm);
|
||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
|
||||
notCompiled = masm.jump();
|
||||
masm.jump(t0);
|
||||
|
||||
JSC::ExecutablePool *ep = poolForSize(masm.size(), CallICInfo::Pool_ScriptStub);
|
||||
if (!ep)
|
||||
return false;
|
||||
|
||||
JSC::LinkBuffer buffer(&masm, ep);
|
||||
buffer.link(rejoin, ic.funGuard.labelAtOffset(ic.joinPointOffset));
|
||||
buffer.link(done, ic.funGuard.labelAtOffset(ic.joinPointOffset));
|
||||
buffer.link(notCompiled, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset));
|
||||
buffer.link(tryCompile,
|
||||
JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction)));
|
||||
|
@ -392,8 +382,8 @@ class CallCompiler
|
|||
ic.fastGuardedObject = obj;
|
||||
|
||||
repatch.repatch(ic.funGuard, obj);
|
||||
repatch.relink(ic.funGuard.callAtOffset(ic.hotCallOffset),
|
||||
JSC::FunctionPtr(script->ncode));
|
||||
repatch.relink(ic.funGuard.jumpAtOffset(ic.hotJumpOffset),
|
||||
JSC::CodeLocationLabel(script->ncode));
|
||||
|
||||
JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %p)\n", start, ic.fastGuardedObject);
|
||||
}
|
||||
|
@ -486,12 +476,15 @@ class CallCompiler
|
|||
|
||||
/* Store pc. */
|
||||
masm.storePtr(ImmPtr(cx->regs->pc),
|
||||
FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
|
||||
FrameAddress(offsetof(VMFrame, regs.pc)));
|
||||
|
||||
/* Store sp. */
|
||||
uint32 spOffset = sizeof(JSStackFrame) + ic.frameDepth * sizeof(Value);
|
||||
masm.addPtr(Imm32(spOffset), JSFrameReg, t0);
|
||||
masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, sp)));
|
||||
masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs.sp)));
|
||||
|
||||
/* Store fp. */
|
||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
|
||||
/* Grab cx early on to avoid stack mucking on x86. */
|
||||
#ifdef JS_CPU_X86
|
||||
|
|
|
@ -145,7 +145,7 @@ struct CallICInfo {
|
|||
JSC::CodeLocationJump funJump;
|
||||
|
||||
/* Offset to inline scripted call, from funGuard. */
|
||||
uint32 hotCallOffset : 16;
|
||||
uint32 hotJumpOffset : 16;
|
||||
uint32 joinPointOffset : 16;
|
||||
|
||||
/* Out of line slow call. */
|
||||
|
|
|
@ -145,6 +145,14 @@ class Assembler : public BaseAssembler
|
|||
return l;
|
||||
}
|
||||
|
||||
void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) {
|
||||
jsval_layout jv;
|
||||
jv.asBits = JSVAL_BITS(Jsvalify(val));
|
||||
|
||||
move(ImmTag(jv.s.tag), type);
|
||||
move(Imm32(jv.s.payload.u32), payload);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores type first, then payload.
|
||||
*/
|
||||
|
|
|
@ -125,6 +125,11 @@ class Assembler : public BaseAssembler
|
|||
return l;
|
||||
}
|
||||
|
||||
void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) {
|
||||
move(Imm64(val.asRawBits() & 0xFFFF800000000000), type);
|
||||
move(Imm64(val.asRawBits() & 0x00007FFFFFFFFFFF), payload);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void storeValueFromComponents(RegisterID type, RegisterID payload, T address) {
|
||||
move(type, Registers::ValueReg);
|
||||
|
|
|
@ -44,19 +44,15 @@
|
|||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
return; \
|
||||
} while (0)
|
||||
static inline void
|
||||
ThrowException(VMFrame &f)
|
||||
{
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline);
|
||||
*f.returnAddressLocation() = ptr;
|
||||
}
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
return v; \
|
||||
} while (0)
|
||||
#define THROW() do { ThrowException(f); return; } while (0)
|
||||
#define THROWV(v) do { ThrowException(f); return v; } while (0)
|
||||
|
||||
static inline JSObject *
|
||||
ValueToObject(JSContext *cx, Value *vp)
|
||||
|
|
|
@ -1346,7 +1346,7 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
|
|||
|
||||
case JSTRAP_RETURN:
|
||||
f.cx->throwing = JS_FALSE;
|
||||
f.cx->fp()->setReturnValue(rval);
|
||||
f.cx->fp()->setAssignedReturnValue(rval);
|
||||
#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
|
||||
*f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
|
||||
JS_METHODJIT_DATA(f.cx).trampolines.forceReturnFast);
|
||||
|
@ -1386,7 +1386,7 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
|
|||
|
||||
case JSTRAP_RETURN:
|
||||
f.cx->throwing = JS_FALSE;
|
||||
f.cx->fp()->setReturnValue(rval);
|
||||
f.cx->fp()->setAssignedReturnValue(rval);
|
||||
#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
|
||||
*f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
|
||||
JS_METHODJIT_DATA(f.cx).trampolines.forceReturnFast);
|
||||
|
|
|
@ -118,31 +118,22 @@ bool
|
|||
TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||
{
|
||||
/* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */
|
||||
Jump noActObjs = masm.branchTest32(Assembler::Zero,
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
||||
Jump noActObjs = masm.branchTest32(Assembler::Zero, FrameFlagsAddress(),
|
||||
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
||||
masm.stubCall(stubs::PutActivationObjects, NULL, 0);
|
||||
noActObjs.linkTo(masm.label(), &masm);
|
||||
|
||||
/*
|
||||
* r = fp->prev
|
||||
* f.fp = r
|
||||
*/
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
|
||||
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
/* Store any known return value */
|
||||
masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data);
|
||||
Jump rvalClear = masm.branchTest32(Assembler::Zero,
|
||||
FrameFlagsAddress(), Imm32(JSFRAME_RVAL_ASSIGNED));
|
||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm.loadValueAsComponents(rvalAddress, JSReturnReg_Type, JSReturnReg_Data);
|
||||
rvalClear.linkTo(masm.label(), &masm);
|
||||
|
||||
Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm.loadValueAsComponents(rval, JSReturnReg_Type, JSReturnReg_Data);
|
||||
|
||||
masm.restoreReturnAddress();
|
||||
|
||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
|
||||
Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||
#endif
|
||||
|
||||
masm.ret();
|
||||
/* Return to the caller */
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg);
|
||||
masm.jump(Registers::ReturnReg);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,8 +84,7 @@ JaegerTrampoline PROC FRAME
|
|||
; Space for the rest of the VMFrame.
|
||||
sub rsp, 28h
|
||||
|
||||
; This is actually part of VMFrame, but we need to save 5th param for
|
||||
; SafePointTrampoline
|
||||
; This is actually part of the VMFrame.
|
||||
mov r10, [rbp+8*5+8]
|
||||
push r10
|
||||
|
||||
|
@ -99,7 +98,13 @@ JaegerTrampoline PROC FRAME
|
|||
add rsp, 20h
|
||||
|
||||
; Jump into the JIT code.
|
||||
call qword ptr [rsp]
|
||||
jmp qword ptr [rsp]
|
||||
JaegerTrampoline ENDP
|
||||
|
||||
; void JaegerTrampolineReturn();
|
||||
JaegerTrampolineReturn PROC FRAME
|
||||
or rcx, rdx
|
||||
mov [rbx + 0x30], rcx
|
||||
sub rsp, 20h
|
||||
lea rcx, [rsp+20h]
|
||||
call PopActiveVMFrame
|
||||
|
@ -147,14 +152,6 @@ throwpoline_exit:
|
|||
JaegerThrowpoline ENDP
|
||||
|
||||
|
||||
; void SafePointTrampoline();
|
||||
SafePointTrampoline PROC FRAME
|
||||
.ENDPROLOG
|
||||
pop rax
|
||||
mov qword ptr [rbx+50h], rax ; fp->ncode_
|
||||
jmp qword ptr [rsp+8]
|
||||
SafePointTrampoline ENDP
|
||||
|
||||
|
||||
; void InjectJaegerReturn();
|
||||
InjectJaegerReturn PROC FRAME
|
||||
|
|
|
@ -71,10 +71,7 @@ JaegerTrampoline:
|
|||
/* Space for the rest of the VMFrame. */
|
||||
subq $0x28, %rsp
|
||||
|
||||
/*
|
||||
* This is actually part of the VMFrame, but we need to save |r8| for
|
||||
* SafePointTrampoline.
|
||||
*/
|
||||
/* This is actually part of the VMFrame. */
|
||||
pushq %r8
|
||||
|
||||
/* Set cx->regs and set the active frame. Save rdx and align frame in one. */
|
||||
|
@ -84,10 +81,16 @@ JaegerTrampoline:
|
|||
movq %rsp, %rdi
|
||||
call PushActiveVMFrame
|
||||
|
||||
/*
|
||||
* Jump into into the JIT'd code.
|
||||
*/
|
||||
call *0(%rsp)
|
||||
/* Jump into into the JIT'd code. */
|
||||
jmp *0(%rsp)
|
||||
.size JaegerTrampoline, . - JaegerTrampoline
|
||||
|
||||
/ void JaegerTrampolineReturn()
|
||||
.global JaegerTrampolineReturn
|
||||
.type JaegerTrampolineReturn, @function
|
||||
JaegerTrampolineReturn:
|
||||
or %rdx, %rcx
|
||||
movq %rcx, 0x30(%rbx)
|
||||
movq %rsp, %rdi
|
||||
call PopActiveVMFrame
|
||||
|
||||
|
@ -100,7 +103,7 @@ JaegerTrampoline:
|
|||
popq %rbp
|
||||
movq $1, %rax
|
||||
ret
|
||||
.size JaegerTrampoline, . - JaegerTrampoline
|
||||
.size JaegerTrampolineReturn, . - JaegerTrampolineReturn
|
||||
|
||||
|
||||
/ void *JaegerThrowpoline(js::VMFrame *vmFrame)
|
||||
|
@ -126,19 +129,11 @@ JaegerThrowpoline:
|
|||
ret
|
||||
.size JaegerThrowpoline, . - JaegerThrowpoline
|
||||
|
||||
.global SafePointTrampoline
|
||||
.type SafePointTrampoline, @function
|
||||
SafePointTrampoline:
|
||||
popq %rax
|
||||
movq %rax, 0x50(%rbx)
|
||||
jmp *8(%rsp)
|
||||
.size SafePointTrampoline, . - SafePointTrampoline
|
||||
|
||||
.global InjectJaegerReturn
|
||||
.type InjectJaegerReturn, @function
|
||||
InjectJaegerReturn:
|
||||
movq 0x30(%rbx), %rcx /* load fp->rval_ into typeReg */
|
||||
movq 0x50(%rbx), %rax /* fp->ncode_ */
|
||||
movq 0x28(%rbx), %rax /* fp->ncode_ */
|
||||
|
||||
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */
|
||||
movq %r14, %rdx /* payloadReg = payloadMaskReg */
|
||||
|
|
|
@ -65,7 +65,15 @@ JaegerTrampoline:
|
|||
call SetVMFrameRegs
|
||||
call PushActiveVMFrame
|
||||
popl %edx
|
||||
call *16(%ebp)
|
||||
jmp *16(%ebp)
|
||||
.size JaegerTrampoline, . - JaegerTrampoline
|
||||
|
||||
/ void JaegerTrampolineReturn()
|
||||
.global JaegerTrampolineReturn
|
||||
.type JaegerTrampolineReturn, @function
|
||||
JaegerTrampolineReturn:
|
||||
movl %edx, 0x18(%ebx)
|
||||
movl %ecx, 0x1C(%ebx)
|
||||
pushl %esp
|
||||
call PopActiveVMFrame
|
||||
|
||||
|
@ -76,7 +84,7 @@ JaegerTrampoline:
|
|||
popl %ebp
|
||||
movl $1, %eax
|
||||
ret
|
||||
.size JaegerTrampoline, . - JaegerTrampoline
|
||||
.size JaegerTrampolineReturn, . - JaegerTrampolineReturn
|
||||
|
||||
|
||||
/ void *JaegerThrowpoline(js::VMFrame *vmFrame)
|
||||
|
@ -117,24 +125,11 @@ throwpoline_exit:
|
|||
InjectJaegerReturn:
|
||||
movl 0x18(%ebx), %edx /* fp->rval_ data */
|
||||
movl 0x1C(%ebx), %ecx /* fp->rval_ type */
|
||||
movl 0x2C(%ebx), %eax /* fp->ncode_ */
|
||||
movl 0x14(%ebx), %eax /* fp->ncode_ */
|
||||
/* For Sun Studio there is no fast call. */
|
||||
/* We add the stack by 8 before. */
|
||||
addl $0x8, %esp
|
||||
/* Restore frame regs. */
|
||||
movl 0x1C(%esp), %ebx /* f.fp */
|
||||
pushl %eax
|
||||
ret
|
||||
jmp *%eax
|
||||
.size InjectJaegerReturn, . - InjectJaegerReturn
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
.global SafePointTrampoline
|
||||
.type SafePointTrampoline, @function
|
||||
SafePointTrampoline:
|
||||
popl %eax
|
||||
movl %eax, 0x2C(%ebx)
|
||||
jmp *24(%ebp)
|
||||
.size SafePointTrampoline, . - SafePointTrampoline
|
||||
|
|
Загрузка…
Ссылка в новой задаче