зеркало из https://github.com/mozilla/pjs.git
Merge backout.
This commit is contained in:
Коммит
a40d689b66
|
@ -2008,7 +2008,7 @@ struct JSContext
|
|||
|
||||
public:
|
||||
friend class js::StackSpace;
|
||||
friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, JSInterpMode);
|
||||
friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, uintN);
|
||||
|
||||
void resetCompartment();
|
||||
|
||||
|
|
|
@ -3716,10 +3716,15 @@ bad:
|
|||
JSBool
|
||||
js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
|
||||
{
|
||||
CG_SWITCH_TO_PROLOG(cg);
|
||||
JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
|
||||
if (js_Emit1(cx, cg, JSOP_BEGIN) < 0)
|
||||
return false;
|
||||
CG_SWITCH_TO_MAIN(cg);
|
||||
|
||||
if (cg->flags & TCF_FUN_IS_GENERATOR) {
|
||||
/* JSOP_GENERATOR must be the first instruction. */
|
||||
/* JSOP_GENERATOR must be the first real instruction. */
|
||||
CG_SWITCH_TO_PROLOG(cg);
|
||||
JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
|
||||
if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)
|
||||
return false;
|
||||
CG_SWITCH_TO_MAIN(cg);
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "jscntxtinlines.h"
|
||||
#include "jsinterpinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsprobes.h"
|
||||
#include "jspropertycacheinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
@ -733,13 +734,28 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
|
|||
}
|
||||
}
|
||||
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
void *hookData = NULL;
|
||||
if (JS_UNLIKELY(hook != NULL))
|
||||
hookData = hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData);
|
||||
|
||||
/* Run function until JSOP_STOP, JSOP_RETURN or error. */
|
||||
JSBool ok;
|
||||
{
|
||||
AutoPreserveEnumerators preserve(cx);
|
||||
Probes::enterJSFun(cx, fun);
|
||||
ok = RunScript(cx, script, fp);
|
||||
Probes::exitJSFun(cx, fun);
|
||||
}
|
||||
|
||||
if (JS_UNLIKELY(hookData != NULL)) {
|
||||
hook = cx->debugHooks->callHook;
|
||||
if (hook)
|
||||
hook(cx, fp, JS_FALSE, &ok, hookData);
|
||||
}
|
||||
|
||||
PutActivationObjects(cx, fp);
|
||||
|
||||
args.rval() = fp->returnValue();
|
||||
JS_ASSERT_IF(ok && (flags & JSINVOKE_CONSTRUCT), !args.rval().isPrimitive());
|
||||
|
||||
|
@ -2145,28 +2161,11 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
|
|||
return js_IteratorNext(cx, iterobj, rval);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ScriptPrologue(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
if (fp->isConstructing()) {
|
||||
JSObject *obj = js_CreateThisForFunction(cx, &fp->callee());
|
||||
if (!obj)
|
||||
return false;
|
||||
fp->functionThis().setObject(*obj);
|
||||
}
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
if (JS_UNLIKELY(hook != NULL))
|
||||
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
|
||||
|
||||
Probes::enterJSFun(cx, fp->maybeFun());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
||||
Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInterpMode interpMode)
|
||||
Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN interpFlags)
|
||||
{
|
||||
#ifdef MOZ_TRACEVIS
|
||||
TraceVisStateObj tvso(cx, S_INTERP);
|
||||
|
@ -2397,7 +2396,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
|
||||
JS_ASSERT(!TRACE_RECORDER(cx)); \
|
||||
interpReturnOK = true; \
|
||||
goto leave_on_safe_point; \
|
||||
goto stop_recording; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
|
@ -2433,25 +2432,13 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
/* Check for too deep of a native thread stack. */
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
|
||||
JSFrameRegs regs = *cx->regs;
|
||||
MUST_FLOW_THROUGH("exit");
|
||||
++cx->interpLevel;
|
||||
|
||||
/* Repoint cx->regs to a local variable for faster access. */
|
||||
struct InterpExitGuard {
|
||||
JSContext *cx;
|
||||
const JSFrameRegs ®s;
|
||||
JSFrameRegs *prevContextRegs;
|
||||
InterpExitGuard(JSContext *cx, JSFrameRegs ®s)
|
||||
: cx(cx), regs(regs), prevContextRegs(cx->regs) {
|
||||
cx->setCurrentRegs(®s);
|
||||
++cx->interpLevel;
|
||||
}
|
||||
~InterpExitGuard() {
|
||||
--cx->interpLevel;
|
||||
JS_ASSERT(cx->regs == ®s);
|
||||
*prevContextRegs = regs;
|
||||
cx->setCurrentRegs(prevContextRegs);
|
||||
}
|
||||
} interpGuard(cx, regs);
|
||||
JSFrameRegs *const prevContextRegs = cx->regs;
|
||||
JSFrameRegs regs = *cx->regs;
|
||||
cx->setCurrentRegs(®s);
|
||||
|
||||
/* Copy in hot values that change infrequently. */
|
||||
JSRuntime *const rt = cx->runtime;
|
||||
|
@ -2463,7 +2450,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
JS_ASSERT(script->length > 1);
|
||||
|
||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||
bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
|
||||
bool leaveOnSafePoint = !!(interpFlags & JSINTERP_SAFEPOINT);
|
||||
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
|
||||
#else
|
||||
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0)
|
||||
|
@ -2483,7 +2470,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_UNLIKELY(regs.fp->isGeneratorFrame())) {
|
||||
JS_ASSERT(interpGuard.prevContextRegs == &cx->generatorFor(regs.fp)->regs);
|
||||
JS_ASSERT(prevContextRegs == &cx->generatorFor(regs.fp)->regs);
|
||||
JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
|
||||
JS_ASSERT((size_t) (regs.sp - regs.fp->base()) <= StackDepth(script));
|
||||
|
||||
|
@ -2502,7 +2489,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
* there should already be a valid recorder. Otherwise...
|
||||
* we cannot reenter the interpreter while recording.
|
||||
*/
|
||||
if (interpMode == JSINTERP_RECORD) {
|
||||
if (interpFlags & JSINTERP_RECORD) {
|
||||
JS_ASSERT(TRACE_RECORDER(cx));
|
||||
ENABLE_INTERRUPTS();
|
||||
} else if (TRACE_RECORDER(cx)) {
|
||||
|
@ -2513,15 +2500,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
atoms = COMMON_ATOMS_START(&rt->atomState);
|
||||
#endif
|
||||
|
||||
/* Don't call the script prologue if executing between Method and Trace JIT. */
|
||||
if (interpMode == JSINTERP_NORMAL) {
|
||||
JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), regs.pc == script->code);
|
||||
if (!ScriptPrologue(cx, regs.fp))
|
||||
goto error;
|
||||
}
|
||||
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
|
||||
/* State communicated between non-local jumps: */
|
||||
JSBool interpReturnOK;
|
||||
JSAtom *atomNotDefined;
|
||||
|
@ -2607,8 +2585,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
|
|||
AbortableRecordingStatus status = tr->monitorRecording(op);
|
||||
JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
|
||||
|
||||
if (interpMode != JSINTERP_NORMAL) {
|
||||
JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT);
|
||||
if (interpFlags & (JSINTERP_RECORD | JSINTERP_SAFEPOINT)) {
|
||||
switch (status) {
|
||||
case ARECORD_IMACRO_ABORTED:
|
||||
case ARECORD_ABORTED:
|
||||
|
@ -2783,11 +2760,27 @@ BEGIN_CASE(JSOP_STOP)
|
|||
inline_return:
|
||||
{
|
||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, ®s.fp->scopeChain(), 0));
|
||||
interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK);
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
if (JS_UNLIKELY(regs.fp->hasHookData())) {
|
||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||
hook(cx, regs.fp, JS_FALSE, &interpReturnOK, regs.fp->hookData());
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
}
|
||||
}
|
||||
|
||||
PutActivationObjects(cx, regs.fp);
|
||||
|
||||
Probes::exitJSFun(cx, regs.fp->maybeFun());
|
||||
|
||||
/*
|
||||
* If inline-constructing, replace primitive rval with the new object
|
||||
* passed in via |this|, and instrument this constructor invocation.
|
||||
*/
|
||||
if (regs.fp->isConstructing()) {
|
||||
if (regs.fp->returnValue().isPrimitive())
|
||||
regs.fp->setReturnValue(ObjectValue(regs.fp->constructorThis()));
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
}
|
||||
|
||||
/* The JIT inlines ScriptEpilogue. */
|
||||
jit_return:
|
||||
Value *newsp = regs.fp->actualArgs() - 1;
|
||||
newsp[-1] = regs.fp->returnValue();
|
||||
cx->stack().popInlineFrame(cx, regs.fp->prev(), newsp);
|
||||
|
@ -2810,6 +2803,18 @@ BEGIN_CASE(JSOP_STOP)
|
|||
goto error;
|
||||
} else {
|
||||
JS_ASSERT(regs.sp == regs.fp->base());
|
||||
if (regs.fp->isConstructing() && regs.fp->returnValue().isPrimitive())
|
||||
regs.fp->setReturnValue(ObjectValue(regs.fp->constructorThis()));
|
||||
|
||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||
/* Hack: re-push rval so either JIT will read it properly. */
|
||||
regs.fp->setBailedAtReturn();
|
||||
if (TRACE_RECORDER(cx)) {
|
||||
AbortRecording(cx, "recording out of Interpret");
|
||||
interpReturnOK = true;
|
||||
goto stop_recording;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
interpReturnOK = true;
|
||||
goto exit;
|
||||
|
@ -4564,6 +4569,41 @@ BEGIN_CASE(JSOP_ENUMELEM)
|
|||
}
|
||||
END_CASE(JSOP_ENUMELEM)
|
||||
|
||||
BEGIN_CASE(JSOP_BEGIN)
|
||||
{
|
||||
if (regs.fp->isConstructing()) {
|
||||
JSObject *obj2 = js_CreateThisForFunction(cx, ®s.fp->callee());
|
||||
if (!obj2)
|
||||
goto error;
|
||||
regs.fp->functionThis().setObject(*obj2);
|
||||
}
|
||||
|
||||
/* Call the debugger hook if present. */
|
||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||
regs.fp->setHookData(hook(cx, regs.fp, JS_TRUE, 0,
|
||||
cx->debugHooks->callHookData));
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
}
|
||||
|
||||
JS_RUNTIME_METER(rt, inlineCalls);
|
||||
|
||||
Probes::enterJSFun(cx, regs.fp->fun());
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Try to ensure methods are method JIT'd. */
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
|
||||
if (status == mjit::Compile_Error)
|
||||
goto error;
|
||||
if (!TRACE_RECORDER(cx) && status == mjit::Compile_Okay) {
|
||||
if (!mjit::JaegerShot(cx))
|
||||
goto error;
|
||||
interpReturnOK = true;
|
||||
goto inline_return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
END_CASE(JSOP_BEGIN)
|
||||
|
||||
{
|
||||
JSFunction *newfun;
|
||||
JSObject *callee;
|
||||
|
@ -4663,31 +4703,12 @@ BEGIN_CASE(JSOP_APPLY)
|
|||
goto error;
|
||||
|
||||
inlineCallCount++;
|
||||
JS_RUNTIME_METER(rt, inlineCalls);
|
||||
|
||||
TRACE_0(EnterFrame);
|
||||
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Try to ensure methods are method JIT'd. */
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
|
||||
if (status == mjit::Compile_Error)
|
||||
goto error;
|
||||
if (!TRACE_RECORDER(cx) && status == mjit::Compile_Okay) {
|
||||
interpReturnOK = mjit::JaegerShot(cx);
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
goto jit_return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ScriptPrologue(cx, regs.fp))
|
||||
goto error;
|
||||
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
|
||||
/* Load first op and dispatch it (safe since JSOP_STOP). */
|
||||
op = (JSOp) *regs.pc;
|
||||
JS_ASSERT(op == JSOP_BEGIN);
|
||||
DO_OP();
|
||||
}
|
||||
|
||||
|
@ -6912,9 +6933,6 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
goto inline_return;
|
||||
|
||||
exit:
|
||||
interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK);
|
||||
regs.fp->setFinishedInInterpreter();
|
||||
|
||||
/*
|
||||
* At this point we are inevitably leaving an interpreted function or a
|
||||
* top-level script, and returning to one of:
|
||||
|
@ -6927,15 +6945,20 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
* frame pc.
|
||||
*/
|
||||
JS_ASSERT(entryFrame == regs.fp);
|
||||
JS_ASSERT(cx->regs == ®s);
|
||||
*prevContextRegs = regs;
|
||||
cx->setCurrentRegs(prevContextRegs);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
JS_ASSERT_IF(interpReturnOK && interpMode == JSINTERP_RECORD, !TRACE_RECORDER(cx));
|
||||
JS_ASSERT_IF(interpReturnOK && (interpFlags & JSINTERP_RECORD), !TRACE_RECORDER(cx));
|
||||
if (TRACE_RECORDER(cx))
|
||||
AbortRecording(cx, "recording out of Interpret");
|
||||
#endif
|
||||
|
||||
JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), !js_IsActiveWithOrBlock(cx, ®s.fp->scopeChain(), 0));
|
||||
|
||||
--cx->interpLevel;
|
||||
|
||||
return interpReturnOK;
|
||||
|
||||
atom_not_defined:
|
||||
|
@ -6948,13 +6971,12 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* This path is used when it's guaranteed the method can be finished
|
||||
* inside the JIT.
|
||||
*/
|
||||
#if defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||
leave_on_safe_point:
|
||||
stop_recording:
|
||||
#endif
|
||||
JS_ASSERT(cx->regs == ®s);
|
||||
*prevContextRegs = regs;
|
||||
cx->setCurrentRegs(prevContextRegs);
|
||||
return interpReturnOK;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,11 +59,10 @@ struct JSFrameRegs
|
|||
};
|
||||
|
||||
/* Flags to toggle js::Interpret() execution. */
|
||||
enum JSInterpMode
|
||||
enum JSInterpFlags
|
||||
{
|
||||
JSINTERP_NORMAL = 0, /* Interpreter is running normally. */
|
||||
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
|
||||
JSINTERP_SAFEPOINT = 2 /* interpreter should leave on a method JIT safe point */
|
||||
JSINTERP_RECORD = 0x1, /* interpreter has been started to record/run traces */
|
||||
JSINTERP_SAFEPOINT = 0x2 /* interpreter should leave on a method JIT safe point */
|
||||
};
|
||||
|
||||
/* Flags used in JSStackFrame::flags_ */
|
||||
|
@ -84,7 +83,7 @@ enum JSFrameFlags
|
|||
/* Temporary frame states */
|
||||
JSFRAME_ASSIGNING = 0x100, /* not-JOF_ASSIGNING op is assigning */
|
||||
JSFRAME_YIELDING = 0x200, /* js::Interpret dispatched JSOP_YIELD */
|
||||
JSFRAME_FINISHED_IN_INTERPRETER = 0x400, /* set if frame finished in Interpret() */
|
||||
JSFRAME_BAILED_AT_RETURN = 0x400, /* bailed at JSOP_RETURN */
|
||||
|
||||
/* Concerning function arguments */
|
||||
JSFRAME_OVERRIDE_ARGS = 0x1000, /* overridden arguments local variable */
|
||||
|
@ -681,12 +680,12 @@ struct JSStackFrame
|
|||
flags_ &= ~JSFRAME_YIELDING;
|
||||
}
|
||||
|
||||
void setFinishedInInterpreter() {
|
||||
flags_ |= JSFRAME_FINISHED_IN_INTERPRETER;
|
||||
bool isBailedAtReturn() const {
|
||||
return flags_ & JSFRAME_BAILED_AT_RETURN;
|
||||
}
|
||||
|
||||
bool finishedInInterpreter() const {
|
||||
return !!(flags_ & JSFRAME_FINISHED_IN_INTERPRETER);
|
||||
void setBailedAtReturn() {
|
||||
flags_ |= JSFRAME_BAILED_AT_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -983,7 +982,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
* pointed to by cx->fp until completion or error.
|
||||
*/
|
||||
extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
||||
Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, JSInterpMode mode = JSINTERP_NORMAL);
|
||||
Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, uintN interpFlags = 0);
|
||||
|
||||
extern JS_REQUIRES_STACK bool
|
||||
RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
@ -112,7 +111,7 @@ JSStackFrame::resetInvokeCallFrame()
|
|||
JSFRAME_HAS_RVAL |
|
||||
JSFRAME_HAS_SCOPECHAIN |
|
||||
JSFRAME_HAS_ANNOTATION |
|
||||
JSFRAME_FINISHED_IN_INTERPRETER)));
|
||||
JSFRAME_BAILED_AT_RETURN)));
|
||||
flags_ &= JSFRAME_FUNCTION |
|
||||
JSFRAME_OVERFLOW_ARGS |
|
||||
JSFRAME_HAS_PREVPC |
|
||||
|
@ -263,11 +262,6 @@ JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
|
|||
if (hasCallObj()) {
|
||||
callObj().setPrivate(this);
|
||||
otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
|
||||
if (js_IsNamedLambda(fun())) {
|
||||
JSObject *env = callObj().getParent();
|
||||
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
||||
env->setPrivate(this);
|
||||
}
|
||||
}
|
||||
if (hasArgsObj()) {
|
||||
argsObj().setPrivate(this);
|
||||
|
@ -679,35 +673,6 @@ ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
|
|||
return pobj;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
|
||||
{
|
||||
Probes::exitJSFun(cx, fp->maybeFun());
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
if (hook && fp->hasHookData())
|
||||
hook(cx, fp, JS_FALSE, &ok, fp->hookData());
|
||||
|
||||
/*
|
||||
* An eval frame's parent owns its activation objects. A yielding frame's
|
||||
* activation objects are transferred to the floating frame, stored in the
|
||||
* generator.
|
||||
*/
|
||||
if (fp->isFunctionFrame() && !fp->isEvalFrame() && !fp->isYielding())
|
||||
PutActivationObjects(cx, fp);
|
||||
|
||||
/*
|
||||
* If inline-constructing, replace primitive rval with the new object
|
||||
* passed in via |this|, and instrument this constructor invocation.
|
||||
*/
|
||||
if (fp->isConstructing()) {
|
||||
if (fp->returnValue().isPrimitive())
|
||||
fp->setReturnValue(ObjectValue(fp->constructorThis()));
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* jsinterpinlines_h__ */
|
||||
|
|
|
@ -1272,7 +1272,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
if (!cx->ensureGeneratorStackSpace())
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
|
||||
JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
|
||||
switch (op) {
|
||||
case JSGENOP_NEXT:
|
||||
case JSGENOP_SEND:
|
||||
|
|
|
@ -623,4 +623,6 @@ OPDEF(JSOP_FORGLOBAL, 246,"forglobal", NULL, 3, 1, 1, 19, JOF_GLOBAL
|
|||
OPDEF(JSOP_BLOCKCHAIN, 247,"blockchain", NULL, 3, 0, 0, 0, JOF_OBJECT)
|
||||
OPDEF(JSOP_NULLBLOCKCHAIN,248,"nullblockchain",NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/* When changing bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */
|
||||
OPDEF(JSOP_BEGIN, 249,"begin", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_TMPSLOT)
|
||||
|
||||
/* When adding bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */
|
||||
|
|
|
@ -308,7 +308,7 @@ GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs
|
|||
|
||||
// The method JIT's implementation of instanceof contains an internal lookup
|
||||
// of the prototype property.
|
||||
if (op == JSOP_INSTANCEOF)
|
||||
if (op == JSOP_INSTANCEOF || op == JSOP_BEGIN)
|
||||
return cx->runtime->atomState.classPrototypeAtom;
|
||||
|
||||
ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||
|
|
|
@ -10453,13 +10453,6 @@ TraceRecorder::record_EnterFrame()
|
|||
RETURN_STOP_A("recursion started inlining");
|
||||
}
|
||||
|
||||
if (fp->isConstructing()) {
|
||||
LIns* args[] = { callee_ins, INS_CONSTPTR(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
|
||||
set(&fp->thisValue(), tv_ins);
|
||||
}
|
||||
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -11163,6 +11156,20 @@ TraceRecorder::emitNativePropertyOp(const Shape* shape, LIns* obj_ins,
|
|||
guard(true, lir->insEqI_0(status_ins), STATUS_EXIT);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_BEGIN()
|
||||
{
|
||||
JSStackFrame* fp = cx->fp();
|
||||
if (fp->isConstructing()) {
|
||||
LIns* callee_ins = get(&cx->fp()->calleeValue());
|
||||
LIns* args[] = { callee_ins, INS_CONSTPTR(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
|
||||
set(&fp->thisValue(), tv_ins);
|
||||
}
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], bool rooted)
|
||||
{
|
||||
|
|
|
@ -205,7 +205,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
|||
* before deserialization of bytecode. If the saved version does not match
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 74)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 73)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
|
|
@ -307,12 +307,6 @@ mjit::Compiler::generatePrologue()
|
|||
}
|
||||
}
|
||||
|
||||
if (isConstructing)
|
||||
constructThis();
|
||||
|
||||
if (debugMode)
|
||||
stubCall(stubs::EnterScript);
|
||||
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
|
@ -1349,16 +1343,16 @@ mjit::Compiler::generateMethod()
|
|||
END_CASE(JSOP_LOCALDEC)
|
||||
|
||||
BEGIN_CASE(JSOP_BINDNAME)
|
||||
jsop_bindname(fullAtomIndex(PC), true);
|
||||
jsop_bindname(fullAtomIndex(PC));
|
||||
END_CASE(JSOP_BINDNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_SETPROP)
|
||||
jsop_setprop(script->getAtom(fullAtomIndex(PC)), true);
|
||||
jsop_setprop(script->getAtom(fullAtomIndex(PC)));
|
||||
END_CASE(JSOP_SETPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_SETNAME)
|
||||
BEGIN_CASE(JSOP_SETMETHOD)
|
||||
jsop_setprop(script->getAtom(fullAtomIndex(PC)), true);
|
||||
jsop_setprop(script->getAtom(fullAtomIndex(PC)));
|
||||
END_CASE(JSOP_SETNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_THROW)
|
||||
|
@ -1708,6 +1702,11 @@ mjit::Compiler::generateMethod()
|
|||
break;
|
||||
END_CASE(JSOP_GLOBALINC)
|
||||
|
||||
BEGIN_CASE(JSOP_BEGIN)
|
||||
if (isConstructing)
|
||||
constructThis();
|
||||
END_CASE(JSOP_BEGIN)
|
||||
|
||||
default:
|
||||
/* Sorry, this opcode isn't implemented yet. */
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
|
@ -1931,11 +1930,6 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
|||
/* Only the top of the stack can be returned. */
|
||||
JS_ASSERT_IF(fe, fe == frame.peek(-1));
|
||||
|
||||
if (debugMode) {
|
||||
prepareStubCall(Uses(0));
|
||||
stubCall(stubs::LeaveScript);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -2368,28 +2362,20 @@ mjit::Compiler::emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_setprop_slow(JSAtom *atom, bool usePropCache)
|
||||
mjit::Compiler::jsop_setprop_slow(JSAtom *atom)
|
||||
{
|
||||
prepareStubCall(Uses(2));
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
if (usePropCache)
|
||||
stubCall(STRICT_VARIANT(stubs::SetName));
|
||||
else
|
||||
stubCall(STRICT_VARIANT(stubs::SetPropNoCache));
|
||||
stubCall(STRICT_VARIANT(stubs::SetName));
|
||||
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
|
||||
frame.shimmy(1);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache)
|
||||
mjit::Compiler::jsop_getprop_slow()
|
||||
{
|
||||
prepareStubCall(Uses(1));
|
||||
if (usePropCache) {
|
||||
stubCall(stubs::GetProp);
|
||||
} else {
|
||||
masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubCall(stubs::GetPropNoCache);
|
||||
}
|
||||
stubCall(stubs::GetProp);
|
||||
frame.pop();
|
||||
frame.pushSynced();
|
||||
}
|
||||
|
@ -2454,7 +2440,7 @@ mjit::Compiler::passPICAddress(PICGenInfo &pic)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
||||
{
|
||||
FrameEntry *top = frame.peek(-1);
|
||||
|
||||
|
@ -2462,7 +2448,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_OBJECT) {
|
||||
JS_ASSERT_IF(atom == cx->runtime->atomState.lengthAtom,
|
||||
top->getKnownType() != JSVAL_TYPE_STRING);
|
||||
jsop_getprop_slow(atom, usePropCache);
|
||||
jsop_getprop_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2478,7 +2464,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
shapeReg = frame.allocReg();
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::GET, usePropCache);
|
||||
PICGenInfo pic(ic::PICInfo::GET);
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
Jump typeCheck;
|
||||
|
@ -2585,7 +2571,7 @@ void
|
|||
mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
RegisterID idReg, RegisterID shapeReg)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::GETELEM, true);
|
||||
PICGenInfo pic(ic::PICInfo::GETELEM);
|
||||
|
||||
pic.objRemat = frame.dataRematInfo(obj);
|
||||
pic.idRemat = frame.dataRematInfo(id);
|
||||
|
@ -2698,7 +2684,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
RegisterID objReg = frame.copyDataIntoReg(top);
|
||||
RegisterID shapeReg = frame.allocReg();
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::CALL, true);
|
||||
PICGenInfo pic(ic::PICInfo::CALL);
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
pic.typeReg = frame.copyTypeIntoReg(top);
|
||||
|
@ -2866,7 +2852,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
{
|
||||
FrameEntry *top = frame.peek(-1);
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::CALL, true);
|
||||
PICGenInfo pic(ic::PICInfo::CALL);
|
||||
|
||||
JS_ASSERT(top->isTypeKnown());
|
||||
JS_ASSERT(top->getKnownType() == JSVAL_TYPE_OBJECT);
|
||||
|
@ -2983,20 +2969,20 @@ mjit::Compiler::jsop_callprop(JSAtom *atom)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
||||
mjit::Compiler::jsop_setprop(JSAtom *atom)
|
||||
{
|
||||
FrameEntry *lhs = frame.peek(-2);
|
||||
FrameEntry *rhs = frame.peek(-1);
|
||||
|
||||
/* If the incoming type will never PIC, take slow path. */
|
||||
if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) {
|
||||
jsop_setprop_slow(atom, usePropCache);
|
||||
jsop_setprop_slow(atom);
|
||||
return;
|
||||
}
|
||||
|
||||
JSOp op = JSOp(*PC);
|
||||
|
||||
PICGenInfo pic(op == JSOP_SETMETHOD ? ic::PICInfo::SETMETHOD : ic::PICInfo::SET, usePropCache);
|
||||
PICGenInfo pic(op == JSOP_SETMETHOD ? ic::PICInfo::SETMETHOD : ic::PICInfo::SET);
|
||||
pic.atom = atom;
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
|
@ -3012,11 +2998,19 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
pic.typeCheck = stubcc.linkExit(j, Uses(2));
|
||||
stubcc.leave();
|
||||
|
||||
/*
|
||||
* This gets called from PROPINC/PROPDEC which aren't compatible with
|
||||
* the normal SETNAME property cache logic.
|
||||
*/
|
||||
JSOp op = JSOp(*PC);
|
||||
stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
if (usePropCache)
|
||||
if (op == JSOP_SETNAME || op == JSOP_SETPROP || op == JSOP_SETGNAME || op ==
|
||||
JSOP_SETMETHOD) {
|
||||
stubcc.call(STRICT_VARIANT(stubs::SetName));
|
||||
else
|
||||
} else {
|
||||
stubcc.call(STRICT_VARIANT(stubs::SetPropNoCache));
|
||||
}
|
||||
|
||||
typeCheck = stubcc.masm.jump();
|
||||
pic.hasTypeCheck = true;
|
||||
} else {
|
||||
|
@ -3119,7 +3113,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
void
|
||||
mjit::Compiler::jsop_name(JSAtom *atom)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::NAME, true);
|
||||
PICGenInfo pic(ic::PICInfo::NAME);
|
||||
|
||||
pic.shapeReg = frame.allocReg();
|
||||
pic.objReg = frame.allocReg();
|
||||
|
@ -3151,7 +3145,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
|||
void
|
||||
mjit::Compiler::jsop_xname(JSAtom *atom)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::XNAME, true);
|
||||
PICGenInfo pic(ic::PICInfo::XNAME);
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
|
||||
|
@ -3193,9 +3187,9 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
||||
mjit::Compiler::jsop_bindname(uint32 index)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::BIND, usePropCache);
|
||||
PICGenInfo pic(ic::PICInfo::BIND);
|
||||
|
||||
pic.shapeReg = frame.allocReg();
|
||||
pic.objReg = frame.allocReg();
|
||||
|
@ -3256,9 +3250,9 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache)
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck)
|
||||
{
|
||||
jsop_getprop_slow(atom, usePropCache);
|
||||
jsop_getprop_slow();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3268,13 +3262,13 @@ mjit::Compiler::jsop_callprop(JSAtom *atom)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
||||
mjit::Compiler::jsop_setprop(JSAtom *atom)
|
||||
{
|
||||
jsop_setprop_slow(atom, usePropCache);
|
||||
jsop_setprop_slow(atom);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
||||
mjit::Compiler::jsop_bindname(uint32 index)
|
||||
{
|
||||
RegisterID reg = frame.allocReg();
|
||||
Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
|
||||
|
@ -3286,12 +3280,7 @@ mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
|||
|
||||
stubcc.linkExit(j, Uses(0));
|
||||
stubcc.leave();
|
||||
if (usePropCache) {
|
||||
stubcc.call(stubs::BindName);
|
||||
} else {
|
||||
masm.move(ImmPtr(script->getAtom(index)), Registers::ArgReg1);
|
||||
stubcc.call(stubs::BindNameNoCache);
|
||||
}
|
||||
stubcc.call(stubs::BindName);
|
||||
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
|
||||
|
||||
|
@ -3434,7 +3423,7 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
jsop_binary(JSOP_SUB, stubs::Sub);
|
||||
// N+1
|
||||
|
||||
jsop_bindname(index, false);
|
||||
jsop_bindname(index);
|
||||
// V+1 OBJ
|
||||
|
||||
frame.dup2();
|
||||
|
@ -3446,7 +3435,7 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
frame.shift(-1);
|
||||
// OBJ V+1
|
||||
|
||||
jsop_setprop(atom, false);
|
||||
jsop_setprop(atom);
|
||||
// V+1
|
||||
|
||||
if (pop)
|
||||
|
@ -3469,7 +3458,7 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
jsop_binary(JSOP_ADD, stubs::Add);
|
||||
// N N+1
|
||||
|
||||
jsop_bindname(index, false);
|
||||
jsop_bindname(index);
|
||||
// N N+1 OBJ
|
||||
|
||||
frame.dup2();
|
||||
|
@ -3481,7 +3470,7 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
frame.shift(-1);
|
||||
// N OBJ N+1
|
||||
|
||||
jsop_setprop(atom, false);
|
||||
jsop_setprop(atom);
|
||||
// N N+1
|
||||
|
||||
frame.pop();
|
||||
|
@ -3527,7 +3516,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
jsop_binary(JSOP_SUB, stubs::Sub);
|
||||
// OBJ V+1
|
||||
|
||||
jsop_setprop(atom, false);
|
||||
jsop_setprop(atom);
|
||||
// V+1
|
||||
|
||||
if (pop)
|
||||
|
@ -3559,7 +3548,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
|
|||
frame.dupAt(-2);
|
||||
// OBJ N N+1 OBJ N+1
|
||||
|
||||
jsop_setprop(atom, false);
|
||||
jsop_setprop(atom);
|
||||
// OBJ N N+1 N+1
|
||||
|
||||
frame.popn(2);
|
||||
|
@ -4364,7 +4353,7 @@ mjit::Compiler::constructThis()
|
|||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg);
|
||||
|
||||
// Get callee.prototype.
|
||||
jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false, false);
|
||||
jsop_getprop(cx->runtime->atomState.classPrototypeAtom);
|
||||
|
||||
// Reach into the proto Value and grab a register for its data.
|
||||
FrameEntry *protoFe = frame.peek(-1);
|
||||
|
|
|
@ -139,8 +139,7 @@ class Compiler : public BaseCompiler
|
|||
|
||||
#if defined JS_POLYIC
|
||||
struct PICGenInfo {
|
||||
PICGenInfo(ic::PICInfo::Kind kind, bool usePropCache)
|
||||
: kind(kind), usePropCache(usePropCache)
|
||||
PICGenInfo(ic::PICInfo::Kind kind) : kind(kind)
|
||||
{ }
|
||||
ic::PICInfo::Kind kind;
|
||||
Label fastPathStart;
|
||||
|
@ -158,25 +157,23 @@ class Compiler : public BaseCompiler
|
|||
StateRemat idRemat;
|
||||
Call callReturn;
|
||||
bool hasTypeCheck;
|
||||
bool usePropCache;
|
||||
ValueRemat vr;
|
||||
# if defined JS_CPU_X64
|
||||
ic::PICLabels labels;
|
||||
# endif
|
||||
|
||||
void copySimpleMembersTo(ic::PICInfo &ic) const {
|
||||
ic.kind = kind;
|
||||
ic.shapeReg = shapeReg;
|
||||
ic.objReg = objReg;
|
||||
ic.atom = atom;
|
||||
ic.usePropCache = usePropCache;
|
||||
void copySimpleMembersTo(ic::PICInfo &pi) const {
|
||||
pi.kind = kind;
|
||||
pi.shapeReg = shapeReg;
|
||||
pi.objReg = objReg;
|
||||
pi.atom = atom;
|
||||
if (kind == ic::PICInfo::SET) {
|
||||
ic.u.vr = vr;
|
||||
pi.u.vr = vr;
|
||||
} else if (kind != ic::PICInfo::NAME) {
|
||||
ic.u.get.idReg = idReg;
|
||||
ic.u.get.typeReg = typeReg;
|
||||
ic.u.get.hasTypeCheck = hasTypeCheck;
|
||||
ic.u.get.objRemat = objRemat.offset;
|
||||
pi.u.get.idReg = idReg;
|
||||
pi.u.get.typeReg = typeReg;
|
||||
pi.u.get.hasTypeCheck = hasTypeCheck;
|
||||
pi.u.get.objRemat = objRemat.offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,10 +275,10 @@ class Compiler : public BaseCompiler
|
|||
|
||||
/* Opcode handlers. */
|
||||
void jumpAndTrace(Jump j, jsbytecode *target, Jump *slowOne = NULL, Jump *slowTwo = NULL);
|
||||
void jsop_bindname(uint32 index, bool usePropCache);
|
||||
void jsop_bindname(uint32 index);
|
||||
void jsop_setglobal(uint32 index);
|
||||
void jsop_getglobal(uint32 index);
|
||||
void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true);
|
||||
void jsop_getprop_slow();
|
||||
void jsop_getarg(uint32 index);
|
||||
void jsop_this();
|
||||
void emitReturn(FrameEntry *fe);
|
||||
|
@ -305,10 +302,10 @@ class Compiler : public BaseCompiler
|
|||
void jsop_setelem_slow();
|
||||
void jsop_getelem_slow();
|
||||
void jsop_unbrand();
|
||||
void jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
|
||||
void jsop_getprop(JSAtom *atom, bool typeCheck = true);
|
||||
void jsop_length();
|
||||
void jsop_setprop(JSAtom *atom, bool usePropCache = true);
|
||||
void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
|
||||
void jsop_setprop(JSAtom *atom);
|
||||
void jsop_setprop_slow(JSAtom *atom);
|
||||
bool jsop_callprop_slow(JSAtom *atom);
|
||||
bool jsop_callprop(JSAtom *atom);
|
||||
bool jsop_callprop_obj(JSAtom *atom);
|
||||
|
|
|
@ -73,6 +73,9 @@ using namespace js;
|
|||
using namespace js::mjit;
|
||||
using namespace JSC;
|
||||
|
||||
static bool
|
||||
InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame = JS_TRUE);
|
||||
|
||||
static jsbytecode *
|
||||
FindExceptionHandler(JSContext *cx)
|
||||
{
|
||||
|
@ -174,8 +177,8 @@ top:
|
|||
* either because of a call into an un-JITable script, or because the call is
|
||||
* throwing an exception.
|
||||
*/
|
||||
static void
|
||||
InlineReturn(VMFrame &f)
|
||||
static bool
|
||||
InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = f.regs.fp;
|
||||
|
@ -184,9 +187,36 @@ InlineReturn(VMFrame &f)
|
|||
|
||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0));
|
||||
|
||||
Value *newsp = fp->actualArgs() - 1;
|
||||
newsp[-1] = fp->returnValue();
|
||||
cx->stack().popInlineFrame(cx, fp->prev(), newsp);
|
||||
// Marker for debug support.
|
||||
if (JS_UNLIKELY(fp->hasHookData())) {
|
||||
JSInterpreterHook hook;
|
||||
JSBool status;
|
||||
|
||||
hook = cx->debugHooks->callHook;
|
||||
if (hook) {
|
||||
/*
|
||||
* Do not pass &ok directly as exposing the address inhibits
|
||||
* optimizations and uninitialised warnings.
|
||||
*/
|
||||
status = ok;
|
||||
hook(cx, fp, JS_FALSE, &status, fp->hookData());
|
||||
ok = (status == JS_TRUE);
|
||||
// CHECK_INTERRUPT_HANDLER();
|
||||
}
|
||||
}
|
||||
|
||||
PutActivationObjects(cx, fp);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
|
@ -342,7 +372,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
|
||||
/* Function did not compile... interpret it. */
|
||||
JSBool ok = Interpret(cx, fp);
|
||||
InlineReturn(f);
|
||||
InlineReturn(f, ok);
|
||||
|
||||
if (!ok)
|
||||
THROWV(NULL);
|
||||
|
@ -354,6 +384,7 @@ static inline bool
|
|||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = f.fp();
|
||||
Value *vp = f.regs.sp - (argc + 2);
|
||||
JSObject &callee = vp->toObject();
|
||||
JSFunction *newfun = callee.getFunctionPrivate();
|
||||
|
@ -381,11 +412,17 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp))
|
||||
return false;
|
||||
|
||||
/* Marker for debug support. */
|
||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||
newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
|
||||
cx->debugHooks->callHookData));
|
||||
}
|
||||
|
||||
/* Try to compile if not already compiled. */
|
||||
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
|
||||
if (mjit::TryCompile(cx, newfp) == Compile_Error) {
|
||||
/* A runtime exception was thrown, get out. */
|
||||
InlineReturn(f);
|
||||
InlineReturn(f, JS_FALSE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -398,7 +435,7 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
|
||||
/* Otherwise, run newscript in the interpreter. */
|
||||
bool ok = !!Interpret(cx, cx->fp());
|
||||
InlineReturn(f);
|
||||
InlineReturn(f, JS_TRUE);
|
||||
|
||||
*pret = NULL;
|
||||
return ok;
|
||||
|
@ -537,18 +574,11 @@ js_InternalThrow(VMFrame &f)
|
|||
// JS function.
|
||||
bool lastFrame = (f.entryFp == f.fp());
|
||||
js_UnwindScope(cx, 0, cx->throwing);
|
||||
|
||||
// For consistency with Interpret(), always run the script epilogue.
|
||||
// This simplifies interactions with RunTracer(), since it can assume
|
||||
// no matter how a function exited (error or not), that the epilogue
|
||||
// does not need to be run.
|
||||
ScriptEpilogue(f.cx, f.fp(), false);
|
||||
|
||||
if (lastFrame)
|
||||
break;
|
||||
|
||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
||||
InlineReturn(f);
|
||||
InlineReturn(f, JS_FALSE);
|
||||
}
|
||||
|
||||
JS_ASSERT(f.regs.sp == cx->regs->sp);
|
||||
|
@ -581,43 +611,21 @@ stubs::CreateThis(VMFrame &f, JSObject *proto)
|
|||
fp->formalArgs()[-1].setObject(*obj);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::EnterScript(VMFrame &f)
|
||||
static inline void
|
||||
AdvanceReturnPC(JSContext *cx)
|
||||
{
|
||||
JSStackFrame *fp = f.fp();
|
||||
JSContext *cx = f.cx;
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
if (JS_UNLIKELY(hook != NULL))
|
||||
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
|
||||
|
||||
Probes::enterJSFun(cx, fp->maybeFun());
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::LeaveScript(VMFrame &f)
|
||||
{
|
||||
JSStackFrame *fp = f.fp();
|
||||
JSContext *cx = f.cx;
|
||||
Probes::exitJSFun(cx, fp->maybeFun());
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
|
||||
if (hook && fp->hasHookData()) {
|
||||
JSBool ok = JS_TRUE;
|
||||
hook(cx, fp, JS_FALSE, &ok, fp->hookData());
|
||||
if (!ok)
|
||||
THROW();
|
||||
}
|
||||
/* Simulate an inline_return by advancing the pc. */
|
||||
JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
|
||||
*cx->regs->pc == JSOP_NEW ||
|
||||
*cx->regs->pc == JSOP_EVAL ||
|
||||
*cx->regs->pc == JSOP_APPLY);
|
||||
cx->regs->pc += JSOP_CALL_LENGTH;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
/*
|
||||
* Called when an error is in progress and the topmost frame could not handle
|
||||
* it. This will unwind to a given frame, or find and align to an exception
|
||||
* handler in the process.
|
||||
*/
|
||||
static inline bool
|
||||
HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostFrame = true)
|
||||
HandleErrorInExcessFrames(VMFrame &f, JSStackFrame *stopFp)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
|
@ -625,19 +633,14 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
|||
* Callers of this called either Interpret() or JaegerShot(), which would
|
||||
* have searched for exception handlers already. If we see stopFp, just
|
||||
* return false. Otherwise, pop the frame, since it's guaranteed useless.
|
||||
*
|
||||
* Note that this also guarantees ScriptEpilogue() has been called.
|
||||
*/
|
||||
JSStackFrame *fp = cx->fp();
|
||||
if (searchedTopmostFrame) {
|
||||
if (fp == stopFp)
|
||||
return false;
|
||||
if (fp == stopFp)
|
||||
return false;
|
||||
|
||||
InlineReturn(f);
|
||||
}
|
||||
bool returnOK = InlineReturn(f, false);
|
||||
|
||||
/* Remove the bottom frame. */
|
||||
bool returnOK = false;
|
||||
for (;;) {
|
||||
fp = cx->fp();
|
||||
|
||||
|
@ -664,8 +667,7 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
|||
|
||||
/* Unwind and return. */
|
||||
returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->throwing));
|
||||
returnOK = ScriptEpilogue(cx, fp, returnOK);
|
||||
InlineReturn(f);
|
||||
returnOK = InlineReturn(f, returnOK);
|
||||
}
|
||||
|
||||
JS_ASSERT(&f.regs == cx->regs);
|
||||
|
@ -674,7 +676,6 @@ HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostF
|
|||
return returnOK;
|
||||
}
|
||||
|
||||
/* Returns whether the current PC has method JIT'd code. */
|
||||
static inline void *
|
||||
AtSafePoint(JSContext *cx)
|
||||
{
|
||||
|
@ -686,10 +687,6 @@ AtSafePoint(JSContext *cx)
|
|||
return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interprets until either a safe point is reached that has method JIT'd
|
||||
* code, or the current frame tries to return.
|
||||
*/
|
||||
static inline JSBool
|
||||
PartialInterpret(VMFrame &f)
|
||||
{
|
||||
|
@ -698,7 +695,6 @@ PartialInterpret(VMFrame &f)
|
|||
|
||||
#ifdef DEBUG
|
||||
JSScript *script = fp->script();
|
||||
JS_ASSERT(!fp->finishedInInterpreter());
|
||||
JS_ASSERT(fp->hasImacropc() ||
|
||||
!script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc));
|
||||
#endif
|
||||
|
@ -711,7 +707,6 @@ PartialInterpret(VMFrame &f)
|
|||
|
||||
JS_STATIC_ASSERT(JSOP_NOP == 0);
|
||||
|
||||
/* Returns whether the current PC would return, popping the frame. */
|
||||
static inline JSOp
|
||||
FrameIsFinished(JSContext *cx)
|
||||
{
|
||||
|
@ -723,134 +718,39 @@ FrameIsFinished(JSContext *cx)
|
|||
: JSOP_NOP;
|
||||
}
|
||||
|
||||
|
||||
/* Simulate an inline_return by advancing the pc. */
|
||||
static inline void
|
||||
AdvanceReturnPC(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
|
||||
*cx->regs->pc == JSOP_NEW ||
|
||||
*cx->regs->pc == JSOP_EVAL ||
|
||||
*cx->regs->pc == JSOP_APPLY);
|
||||
cx->regs->pc += JSOP_CALL_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a frame that is about to return, make sure its return value and
|
||||
* activation objects are fixed up. Then, pop the frame and advance the
|
||||
* current PC. Note that while we could enter the JIT at this point, the
|
||||
* logic would still be necessary for the interpreter, so it's easier
|
||||
* (and faster) to finish frames in C++ even if at a safe point here.
|
||||
*/
|
||||
static bool
|
||||
HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
JS_ASSERT(FrameIsFinished(cx));
|
||||
|
||||
/*
|
||||
* This is the most difficult and complicated piece of the tracer
|
||||
* integration, and historically has been very buggy. The problem is that
|
||||
* although this frame has to be popped (see RemoveExcessFrames), it may
|
||||
* be at a JSOP_RETURN opcode, and it might not have ever been executed.
|
||||
* That is, fp->rval may not be set to the top of the stack, and if it
|
||||
* has, the stack has already been decremented. Note that fp->rval is not
|
||||
* the only problem: the epilogue may never have been executed.
|
||||
*
|
||||
* Here are the edge cases and whether the frame has been exited cleanly:
|
||||
* 1. No: A trace exited directly before a RETURN op, and the
|
||||
* interpreter never ran.
|
||||
* 2. Yes: The interpreter exited cleanly.
|
||||
* 3. No: The interpreter exited on a safe point. LEAVE_ON_SAFE_POINT
|
||||
* is not used in between JSOP_RETURN and advancing the PC,
|
||||
* therefore, it cannot have been run if at a safe point.
|
||||
* 4. No: Somewhere in the RunTracer call tree, we removed a frame,
|
||||
* and we returned to a JSOP_RETURN opcode. Note carefully
|
||||
* that in this situation, FrameIsFinished() returns true!
|
||||
* 5. Yes: The function exited in the method JIT. However, in this
|
||||
* case, we'll never enter HandleFinishedFrame(): we always
|
||||
* immediately pop JIT'd frames.
|
||||
*
|
||||
* Since the only scenario where this fixup is NOT needed is a normal exit
|
||||
* from the interpreter, we can cleanly check for this scenario by checking
|
||||
* a bit it sets in the frame.
|
||||
*/
|
||||
bool returnOK = true;
|
||||
if (!cx->fp()->finishedInInterpreter()) {
|
||||
if (JSOp(*cx->regs->pc) == JSOP_RETURN)
|
||||
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
||||
|
||||
returnOK = ScriptEpilogue(cx, cx->fp(), true);
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(cx->fp()->isFunctionFrame() &&
|
||||
!cx->fp()->isEvalFrame(),
|
||||
!cx->fp()->hasCallObj());
|
||||
|
||||
if (cx->fp() != entryFrame) {
|
||||
InlineReturn(f);
|
||||
AdvanceReturnPC(cx);
|
||||
}
|
||||
|
||||
return returnOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a frame newer than the entry frame, try to finish it. If it's at a
|
||||
* return position, pop the frame. If it's at a safe point, execute it in
|
||||
* Jaeger code. Otherwise, try to interpret until a safe point.
|
||||
*
|
||||
* While this function is guaranteed to make progress, it may not actually
|
||||
* finish or pop the current frame. It can either:
|
||||
* 1) Finalize a finished frame, or
|
||||
* 2) Finish and finalize the frame in the Method JIT, or
|
||||
* 3) Interpret, which can:
|
||||
* a) Propagate an error, or
|
||||
* b) Finish the frame, but not finalize it, or
|
||||
* c) Abruptly leave at any point in the frame, or in a newer frame
|
||||
* pushed by a call, that has method JIT'd code.
|
||||
*/
|
||||
static bool
|
||||
EvaluateExcessFrame(VMFrame &f, JSStackFrame *entryFrame)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = cx->fp();
|
||||
|
||||
/*
|
||||
* A "finished" frame is when the interpreter rested on a STOP,
|
||||
* RETURN, RETRVAL, etc. We check for finished frames BEFORE looking
|
||||
* for a safe point. If the frame was finished, we could have already
|
||||
* called ScriptEpilogue(), and entering the JIT could call it twice.
|
||||
*/
|
||||
if (!fp->hasImacropc() && FrameIsFinished(cx))
|
||||
return HandleFinishedFrame(f, entryFrame);
|
||||
|
||||
if (void *ncode = AtSafePoint(cx)) {
|
||||
if (!JaegerShotAtSafePoint(cx, ncode))
|
||||
return false;
|
||||
InlineReturn(f);
|
||||
AdvanceReturnPC(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return PartialInterpret(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate frames newer than the entry frame until all are gone. This will
|
||||
* always leave f.regs.fp == entryFrame.
|
||||
*/
|
||||
static bool
|
||||
FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
|
||||
if (!EvaluateExcessFrame(f, entryFrame)) {
|
||||
if (!HandleErrorInExcessFrame(f, entryFrame))
|
||||
return false;
|
||||
if (void *ncode = AtSafePoint(cx)) {
|
||||
if (!JaegerShotAtSafePoint(cx, ncode)) {
|
||||
if (!HandleErrorInExcessFrames(f, entryFrame))
|
||||
return false;
|
||||
|
||||
/* Could be anywhere - restart outer loop. */
|
||||
continue;
|
||||
}
|
||||
InlineReturn(f, JS_TRUE);
|
||||
AdvanceReturnPC(cx);
|
||||
} else {
|
||||
if (!PartialInterpret(f)) {
|
||||
if (!HandleErrorInExcessFrames(f, entryFrame))
|
||||
return false;
|
||||
} else if (cx->fp() != entryFrame) {
|
||||
/*
|
||||
* Partial interpret could have dropped us anywhere. Deduce the
|
||||
* edge case: at a RETURN, needing to pop a frame.
|
||||
*/
|
||||
JS_ASSERT(!cx->fp()->hasImacropc());
|
||||
if (FrameIsFinished(cx)) {
|
||||
JSOp op = JSOp(*cx->regs->pc);
|
||||
if (op == JSOP_RETURN && !cx->fp()->isBailedAtReturn())
|
||||
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
||||
InlineReturn(f, JS_TRUE);
|
||||
AdvanceReturnPC(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -925,18 +825,18 @@ RunTracer(VMFrame &f)
|
|||
DisableTraceHint(f, mic);
|
||||
#endif
|
||||
|
||||
// Even though ExecuteTree() bypasses the interpreter, it should propagate
|
||||
// error failures correctly.
|
||||
JS_ASSERT_IF(cx->throwing, tpa == TPA_Error);
|
||||
if ((tpa == TPA_RanStuff || tpa == TPA_Recorded) && cx->throwing)
|
||||
tpa = TPA_Error;
|
||||
|
||||
/* Sync up the VMFrame's view of cx->fp(). */
|
||||
f.fp() = cx->fp();
|
||||
JS_ASSERT(f.fp() == cx->fp());
|
||||
|
||||
switch (tpa) {
|
||||
case TPA_Nothing:
|
||||
return NULL;
|
||||
|
||||
case TPA_Error:
|
||||
if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter()))
|
||||
if (!HandleErrorInExcessFrames(f, entryFrame))
|
||||
THROWV(NULL);
|
||||
JS_ASSERT(!cx->fp()->hasImacropc());
|
||||
break;
|
||||
|
@ -974,26 +874,32 @@ RunTracer(VMFrame &f)
|
|||
THROWV(NULL);
|
||||
|
||||
/* IMacros are guaranteed to have been removed by now. */
|
||||
JS_ASSERT(f.fp() == entryFrame);
|
||||
JS_ASSERT(!entryFrame->hasImacropc());
|
||||
|
||||
/* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */
|
||||
if (FrameIsFinished(cx)) {
|
||||
if (!HandleFinishedFrame(f, entryFrame))
|
||||
THROWV(NULL);
|
||||
/* Step 2. If entryFrame is at a safe point, just leave. */
|
||||
if (void *ncode = AtSafePoint(cx))
|
||||
return ncode;
|
||||
|
||||
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
|
||||
if (JSOp op = FrameIsFinished(cx)) {
|
||||
/* We're not guaranteed that the RETURN was run. */
|
||||
if (op == JSOP_RETURN && !entryFrame->isBailedAtReturn())
|
||||
entryFrame->setReturnValue(f.regs.sp[-1]);
|
||||
|
||||
/* Cleanup activation objects on the frame unless it's owned by an Invoke. */
|
||||
if (f.fp() != f.entryFp) {
|
||||
if (!InlineReturn(f, JS_TRUE, JS_FALSE))
|
||||
THROWV(NULL);
|
||||
}
|
||||
|
||||
void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn);
|
||||
*f.returnAddressLocation() = retPtr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Step 3. If entryFrame is at a safe point, just leave. */
|
||||
if (void *ncode = AtSafePoint(cx))
|
||||
return ncode;
|
||||
|
||||
/* Step 4. Do a partial interp, then restart the whole process. */
|
||||
if (!PartialInterpret(f)) {
|
||||
if (!HandleErrorInExcessFrame(f, entryFrame))
|
||||
if (!HandleErrorInExcessFrames(f, entryFrame))
|
||||
THROWV(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -690,10 +690,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
|
||||
class GetPropCompiler : public PICStubCompiler
|
||||
{
|
||||
JSObject *obj;
|
||||
JSAtom *atom;
|
||||
VoidStubPIC stub;
|
||||
int lastStubSecondShapeGuard;
|
||||
JSObject *obj;
|
||||
JSAtom *atom;
|
||||
void *stub;
|
||||
int lastStubSecondShapeGuard;
|
||||
|
||||
static int32 inlineShapeOffset(ic::PICInfo &pic) {
|
||||
#if defined JS_NUNBOX32
|
||||
|
@ -732,12 +732,17 @@ class GetPropCompiler : public PICStubCompiler
|
|||
}
|
||||
|
||||
public:
|
||||
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
|
||||
VoidStub stub)
|
||||
: PICStubCompiler("getprop", f, script, pic), obj(obj), atom(atom),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
|
||||
lastStubSecondShapeGuard(pic.secondShapeGuard)
|
||||
{ }
|
||||
|
||||
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
|
||||
VoidStubPIC stub)
|
||||
: PICStubCompiler(pic.kind == ic::PICInfo::CALL ? "callprop" : "getprop", f, script, pic),
|
||||
obj(obj),
|
||||
atom(atom),
|
||||
stub(stub),
|
||||
: PICStubCompiler("callprop", f, script, pic), obj(obj), atom(atom),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
|
||||
lastStubSecondShapeGuard(pic.secondShapeGuard)
|
||||
{ }
|
||||
|
||||
|
@ -2007,24 +2012,6 @@ class BindNameCompiler : public PICStubCompiler
|
|||
}
|
||||
};
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledLengthIC(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::Length(f);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledGetPropIC(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::GetProp(f);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledGetPropICNoCache(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::GetPropNoCache(f, pic->atom);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
|
@ -2033,7 +2020,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
JSAtom *atom = pic->atom;
|
||||
if (atom == f.cx->runtime->atomState.lengthAtom) {
|
||||
if (f.regs.sp[-1].isString()) {
|
||||
GetPropCompiler cc(f, script, NULL, *pic, NULL, DisabledLengthIC);
|
||||
GetPropCompiler cc(f, script, NULL, *pic, NULL, stubs::Length);
|
||||
if (!cc.generateStringLengthStub()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
|
@ -2044,7 +2031,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
} else if (!f.regs.sp[-1].isPrimitive()) {
|
||||
JSObject *obj = &f.regs.sp[-1].toObject();
|
||||
if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden())) {
|
||||
GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledLengthIC);
|
||||
GetPropCompiler cc(f, script, obj, *pic, NULL, stubs::Length);
|
||||
if (obj->isArray()) {
|
||||
if (!cc.generateArrayLengthStub()) {
|
||||
cc.disable("error");
|
||||
|
@ -2069,10 +2056,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
THROW();
|
||||
|
||||
if (pic->shouldGenerate()) {
|
||||
VoidStubPIC stub = pic->usePropCache
|
||||
? DisabledGetPropIC
|
||||
: DisabledGetPropICNoCache;
|
||||
GetPropCompiler cc(f, script, obj, *pic, atom, stub);
|
||||
GetPropCompiler cc(f, script, obj, *pic, atom, stubs::GetProp);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
|
@ -2116,16 +2100,16 @@ ic::GetElem(VMFrame &f, ic::PICInfo *pic)
|
|||
|
||||
template <JSBool strict>
|
||||
static void JS_FASTCALL
|
||||
DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
|
||||
SetPropDumb(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::SetName<strict>(f, pic->atom);
|
||||
stubs::SetPropNoCache<strict>(f, pic->atom);
|
||||
}
|
||||
|
||||
template <JSBool strict>
|
||||
static void JS_FASTCALL
|
||||
DisabledSetPropICNoCache(VMFrame &f, ic::PICInfo *pic)
|
||||
SetPropSlow(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::SetPropNoCache<strict>(f, pic->atom);
|
||||
stubs::SetName<strict>(f, pic->atom);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
|
@ -2147,9 +2131,22 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
// cache can't handle a GET and SET from the same scripted PC.
|
||||
//
|
||||
|
||||
VoidStubPIC stub = pic->usePropCache
|
||||
? STRICT_VARIANT(DisabledSetPropIC)
|
||||
: STRICT_VARIANT(DisabledSetPropICNoCache);
|
||||
VoidStubPIC stub;
|
||||
switch (JSOp(*f.regs.pc)) {
|
||||
case JSOP_PROPINC:
|
||||
case JSOP_PROPDEC:
|
||||
case JSOP_INCPROP:
|
||||
case JSOP_DECPROP:
|
||||
case JSOP_NAMEINC:
|
||||
case JSOP_NAMEDEC:
|
||||
case JSOP_INCNAME:
|
||||
case JSOP_DECNAME:
|
||||
stub = STRICT_VARIANT(SetPropDumb);
|
||||
break;
|
||||
default:
|
||||
stub = STRICT_VARIANT(SetPropSlow);
|
||||
break;
|
||||
}
|
||||
|
||||
SetPropCompiler cc(f, script, obj, *pic, pic->atom, stub);
|
||||
if (!cc.update()) {
|
||||
|
@ -2162,7 +2159,7 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic)
|
|||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledCallPropIC(VMFrame &f, ic::PICInfo *pic)
|
||||
CallPropSlow(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::CallProp(f, pic->atom);
|
||||
}
|
||||
|
@ -2257,7 +2254,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||
}
|
||||
}
|
||||
|
||||
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC);
|
||||
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, CallPropSlow);
|
||||
if (usePIC) {
|
||||
if (lval.isObject()) {
|
||||
if (!cc.update()) {
|
||||
|
@ -2286,13 +2283,13 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledNameIC(VMFrame &f, ic::PICInfo *pic)
|
||||
SlowName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::Name(f);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledXNameIC(VMFrame &f, ic::PICInfo *pic)
|
||||
SlowXName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::GetProp(f);
|
||||
}
|
||||
|
@ -2305,7 +2302,7 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
|
|||
/* GETXPROP is guaranteed to have an object. */
|
||||
JSObject *obj = &f.regs.sp[-1].toObject();
|
||||
|
||||
ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, DisabledXNameIC);
|
||||
ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, SlowXName);
|
||||
|
||||
if (!cc.updateForXName()) {
|
||||
cc.disable("error");
|
||||
|
@ -2323,7 +2320,7 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
|
|||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
|
||||
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, DisabledNameIC);
|
||||
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowName);
|
||||
|
||||
if (!cc.updateForName()) {
|
||||
cc.disable("error");
|
||||
|
@ -2337,26 +2334,17 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
|
|||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
|
||||
SlowBindName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::BindName(f);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
DisabledBindNameICNoCache(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::BindNameNoCache(f, pic->atom);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::BindName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
|
||||
VoidStubPIC stub = pic->usePropCache
|
||||
? DisabledBindNameIC
|
||||
: DisabledBindNameICNoCache;
|
||||
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, stub);
|
||||
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowBindName);
|
||||
|
||||
JSObject *obj = cc.update();
|
||||
if (!obj) {
|
||||
|
|
|
@ -236,9 +236,6 @@ struct PICInfo {
|
|||
// last stub.
|
||||
bool shapeRegHasBaseShape : 1;
|
||||
|
||||
// True if can use the property cache.
|
||||
bool usePropCache : 1;
|
||||
|
||||
// State flags.
|
||||
bool hit : 1; // this PIC has been executed
|
||||
bool inlinePathPatched : 1; // inline path has been patched
|
||||
|
|
|
@ -99,15 +99,6 @@ stubs::BindName(VMFrame &f)
|
|||
f.regs.sp[-1].setObject(*obj);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::BindNameNoCache(VMFrame &f, JSAtom *atom)
|
||||
{
|
||||
JSObject *obj = js_FindIdentifierBase(f.cx, &f.fp()->scopeChain(), ATOM_TO_JSID(atom));
|
||||
if (!obj)
|
||||
THROW();
|
||||
f.regs.sp[0].setObject(*obj);
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
stubs::BindGlobalName(VMFrame &f)
|
||||
{
|
||||
|
@ -2077,20 +2068,6 @@ stubs::GetProp(VMFrame &f)
|
|||
THROW();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::GetPropNoCache(VMFrame &f, JSAtom *atom)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
Value *vp = &f.regs.sp[-1];
|
||||
JSObject *obj = ValueToObject(cx, vp);
|
||||
if (!obj)
|
||||
THROW();
|
||||
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(atom), vp))
|
||||
THROW();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::CallProp(VMFrame &f, JSAtom *origAtom)
|
||||
{
|
||||
|
|
|
@ -65,8 +65,6 @@ void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
|
|||
void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
|
||||
void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
|
||||
void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc);
|
||||
void JS_FASTCALL EnterScript(VMFrame &f);
|
||||
void JS_FASTCALL LeaveScript(VMFrame &f);
|
||||
|
||||
/*
|
||||
* Result struct for UncachedXHelper.
|
||||
|
@ -114,7 +112,6 @@ void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
|
|||
void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
|
||||
|
||||
void JS_FASTCALL BindName(VMFrame &f);
|
||||
void JS_FASTCALL BindNameNoCache(VMFrame &f, JSAtom *atom);
|
||||
JSObject * JS_FASTCALL BindGlobalName(VMFrame &f);
|
||||
template<JSBool strict> void JS_FASTCALL SetName(VMFrame &f, JSAtom *atom);
|
||||
template<JSBool strict> void JS_FASTCALL SetPropNoCache(VMFrame &f, JSAtom *atom);
|
||||
|
@ -122,7 +119,6 @@ template<JSBool strict> void JS_FASTCALL SetGlobalName(VMFrame &f, JSAtom *atom)
|
|||
template<JSBool strict> void JS_FASTCALL SetGlobalNameDumb(VMFrame &f, JSAtom *atom);
|
||||
void JS_FASTCALL Name(VMFrame &f);
|
||||
void JS_FASTCALL GetProp(VMFrame &f);
|
||||
void JS_FASTCALL GetPropNoCache(VMFrame &f, JSAtom *atom);
|
||||
void JS_FASTCALL GetElem(VMFrame &f);
|
||||
void JS_FASTCALL CallElem(VMFrame &f);
|
||||
template<JSBool strict> void JS_FASTCALL SetElem(VMFrame &f);
|
||||
|
|
|
@ -3,5 +3,5 @@ function main() {
|
|||
return "failure";
|
||||
}
|
||||
/* JSOP_RETURN in main. */
|
||||
trap(main, 3, "'success'");
|
||||
trap(main, 4, "'success'");
|
||||
assertEq(main(), "success");
|
||||
|
|
|
@ -10,8 +10,8 @@ function child() {
|
|||
function parent() {
|
||||
x = "failure2";
|
||||
}
|
||||
/* First op in parent. */
|
||||
trap(parent, 0, "child()");
|
||||
/* First op in parent: because of JSOP_BEGIN, it is op 1. */
|
||||
trap(parent, 1, "child()");
|
||||
|
||||
function success() {
|
||||
x = "success";
|
||||
|
|
|
@ -6,14 +6,14 @@ function doNothing() { }
|
|||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* JSOP_CALL to doNothing in myparent with nested = true. */
|
||||
trap(myparent, 24, "success()");
|
||||
trap(myparent, 25, "success()");
|
||||
doNothing();
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
/* JSOP_CALL to doNothing in myparent with nested = false. */
|
||||
trap(myparent, 35, "myparent(true)");
|
||||
trap(myparent, 36, "myparent(true)");
|
||||
|
||||
function success() {
|
||||
x = "success";
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
var o = { };
|
||||
for (var i = 0; i <= 50; i++)
|
||||
o[i] = i;
|
||||
|
||||
Object.defineProperty(o, "51", { get: assertEq });
|
||||
|
||||
var threw = 0;
|
||||
function g(o, i) {
|
||||
try {
|
||||
assertEq(o[i], i);
|
||||
} catch (e) {
|
||||
threw++;
|
||||
}
|
||||
}
|
||||
|
||||
function f() {
|
||||
for (var i = 0; i <= 51; i++)
|
||||
g(o, i);
|
||||
}
|
||||
|
||||
f();
|
||||
f();
|
||||
f();
|
||||
assertEq(threw, 3);
|
||||
|
Загрузка…
Ссылка в новой задаче