зеркало из https://github.com/mozilla/gecko-dev.git
ICs for scripted new (bug 589398, r=luke,dmandelin).
This commit is contained in:
Родитель
7673da965e
Коммит
8ab67f850c
|
@ -2990,7 +2990,7 @@ JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
|
|||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, *vp);
|
||||
|
||||
return js_NewInstance(cx, JSVAL_TO_OBJECT(*vp));
|
||||
return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
|
|
@ -612,7 +612,7 @@ JS_DECLARE_CALLINFO(js_NumberToString)
|
|||
|
||||
/* Defined in jsobj.cpp. */
|
||||
JS_DECLARE_CALLINFO(js_Object_tn)
|
||||
JS_DECLARE_CALLINFO(js_NewInstanceFromTrace)
|
||||
JS_DECLARE_CALLINFO(js_CreateThisFromTrace)
|
||||
JS_DECLARE_CALLINFO(js_NonEmptyObject)
|
||||
|
||||
/* Defined in jsregexp.cpp. */
|
||||
|
|
|
@ -318,7 +318,7 @@ JSCompartment::sweep(JSContext *cx)
|
|||
#if defined JS_METHODJIT && defined JS_MONOIC
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
if (script->jit)
|
||||
if (script->hasJITCode())
|
||||
mjit::ic::SweepCallICs(script);
|
||||
}
|
||||
#endif
|
||||
|
@ -333,7 +333,7 @@ JSCompartment::purge(JSContext *cx)
|
|||
for (JSScript *script = (JSScript *)scripts.next;
|
||||
&script->links != &scripts;
|
||||
script = (JSScript *)script->links.next) {
|
||||
if (script->jit) {
|
||||
if (script->hasJITCode()) {
|
||||
# if defined JS_POLYIC
|
||||
mjit::ic::PurgePICs(cx, script);
|
||||
# endif
|
||||
|
|
|
@ -116,8 +116,7 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
|
|||
&script->links != &cx->compartment->scripts;
|
||||
script = (JSScript *)script->links.next) {
|
||||
if (script->debugMode != debug &&
|
||||
script->ncode &&
|
||||
script->ncode != JS_UNJITTABLE_METHOD &&
|
||||
script->hasJITCode() &&
|
||||
!IsScriptLive(cx, script)) {
|
||||
/*
|
||||
* In the event that this fails, debug mode is left partially on,
|
||||
|
@ -236,6 +235,10 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
// Do not trap BEGIN, it's a special prologue opcode.
|
||||
if (JSOp(*pc) == JSOP_BEGIN)
|
||||
pc += JSOP_BEGIN_LENGTH;
|
||||
|
||||
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
|
||||
junk = NULL;
|
||||
rt = cx->runtime;
|
||||
|
@ -274,7 +277,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
cx->free(junk);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
|
||||
if (script->hasJITCode()) {
|
||||
mjit::Recompiler recompiler(cx, script);
|
||||
if (!recompiler.recompile())
|
||||
return JS_FALSE;
|
||||
|
@ -327,7 +330,7 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
DBG_UNLOCK(cx->runtime);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
|
||||
if (script->hasJITCode()) {
|
||||
mjit::Recompiler recompiler(cx, script);
|
||||
recompiler.recompile();
|
||||
}
|
||||
|
|
|
@ -3678,10 +3678,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);
|
||||
|
|
|
@ -134,12 +134,13 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
|
|||
|
||||
#if defined(JS_METHODJIT) && defined(JS_MONOIC)
|
||||
JSScript *script = this->script();
|
||||
js::mjit::JITScript *jit = script->getJIT(isConstructing());
|
||||
size_t low = 0;
|
||||
size_t high = script->jit->nCallICs;
|
||||
size_t high = 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();
|
||||
void *entry = jit->callICs[mid].funGuard.executableAddress();
|
||||
|
||||
/*
|
||||
* Use >= here as the return address of the call is likely to be
|
||||
|
@ -151,7 +152,7 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
|
|||
low = mid;
|
||||
}
|
||||
|
||||
js::mjit::ic::CallICInfo &callIC = script->callICs[low];
|
||||
js::mjit::ic::CallICInfo &callIC = jit->callICs[low];
|
||||
|
||||
JS_ASSERT((uint8*)callIC.funGuard.executableAddress() + callIC.joinPointOffset == next->ncode_);
|
||||
return callIC.pc;
|
||||
|
@ -616,7 +617,7 @@ struct AutoInterpPreparer {
|
|||
};
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain)
|
||||
RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(script);
|
||||
|
||||
|
@ -626,8 +627,11 @@ RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain
|
|||
|
||||
AutoInterpPreparer prepareInterp(cx, script);
|
||||
|
||||
JS_ASSERT(fp == cx->fp());
|
||||
JS_ASSERT(fp->script() == script);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fun, &scopeChain);
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fp);
|
||||
if (status == mjit::Compile_Error)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -635,7 +639,7 @@ RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain
|
|||
return mjit::JaegerShot(cx);
|
||||
#endif
|
||||
|
||||
return Interpret(cx, cx->fp());
|
||||
return Interpret(cx, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -686,8 +690,10 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
|
|||
/* Handle the empty-script special case. */
|
||||
if (JS_UNLIKELY(script->isEmpty())) {
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(args.thisv().isObject());
|
||||
args.rval() = args.thisv();
|
||||
JSObject *obj = js_CreateThisForFunction(cx, &callee);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.rval().setObject(*obj);
|
||||
} else {
|
||||
args.rval().setUndefined();
|
||||
}
|
||||
|
@ -718,19 +724,20 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
|
|||
* and fp->scopeChain is correct because the thisObject hook may call
|
||||
* JS_GetScopeChain.
|
||||
*/
|
||||
Value &thisv = fp->functionThis();
|
||||
JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !thisv.isPrimitive());
|
||||
if (thisv.isObject() && !(flags & JSINVOKE_CONSTRUCT)) {
|
||||
/*
|
||||
* We must call the thisObject hook in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*/
|
||||
JSObject *thisp = thisv.toObject().thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
JS_ASSERT(IsSaneThisObject(*thisp));
|
||||
thisv.setObject(*thisp);
|
||||
if (!(flags & JSINVOKE_CONSTRUCT)) {
|
||||
Value &thisv = fp->functionThis();
|
||||
if (thisv.isObject()) {
|
||||
/*
|
||||
* We must call the thisObject hook in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*/
|
||||
JSObject *thisp = thisv.toObject().thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
JS_ASSERT(IsSaneThisObject(*thisp));
|
||||
thisv.setObject(*thisp);
|
||||
}
|
||||
}
|
||||
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
|
@ -743,7 +750,7 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
|
|||
{
|
||||
AutoPreserveEnumerators preserve(cx);
|
||||
Probes::enterJSFun(cx, fun);
|
||||
ok = RunScript(cx, script, fun, fp->scopeChain());
|
||||
ok = RunScript(cx, script, fp);
|
||||
Probes::exitJSFun(cx, fun);
|
||||
}
|
||||
|
||||
|
@ -756,6 +763,8 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
|
|||
PutActivationObjects(cx, fp);
|
||||
|
||||
args.rval() = fp->returnValue();
|
||||
JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !args.rval().isPrimitive());
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -900,7 +909,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|||
|
||||
/* Run script until JSOP_STOP or error. */
|
||||
AutoPreserveEnumerators preserve(cx);
|
||||
JSBool ok = RunScript(cx, script, NULL, frame.fp()->scopeChain());
|
||||
JSBool ok = RunScript(cx, script, frame.fp());
|
||||
if (result)
|
||||
*result = frame.fp()->returnValue();
|
||||
|
||||
|
@ -1153,8 +1162,9 @@ InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
|
|||
|
||||
/* Handle the fast-constructors cases before falling into the general case . */
|
||||
Class *clasp = callee->getClass();
|
||||
JSFunction *fun = NULL;
|
||||
if (clasp == &js_FunctionClass) {
|
||||
JSFunction *fun = callee->getFunctionPrivate();
|
||||
fun = callee->getFunctionPrivate();
|
||||
if (fun->isConstructor()) {
|
||||
args.thisv().setMagicWithObjectOrNullPayload(NULL);
|
||||
return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base());
|
||||
|
@ -1164,25 +1174,30 @@ InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
|
|||
return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base());
|
||||
}
|
||||
|
||||
/* Construct 'this'. */
|
||||
JSObject *obj = js_NewInstance(cx, callee);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.thisv().setObject(*obj);
|
||||
/* Scripts create their own |this| in JSOP_BEGIN */
|
||||
if (!fun || !fun->isInterpreted()) {
|
||||
JSObject *obj = js_CreateThis(cx, callee);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.thisv().setObject(*obj);
|
||||
}
|
||||
|
||||
if (!Invoke(cx, args, JSINVOKE_CONSTRUCT))
|
||||
return false;
|
||||
|
||||
/* Check the return value and if it's primitive, force it to be obj. */
|
||||
if (args.rval().isPrimitive()) {
|
||||
if (callee->getClass() != &js_FunctionClass) {
|
||||
if (clasp != &js_FunctionClass) {
|
||||
/* native [[Construct]] returning primitive is error */
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_NEW_RESULT,
|
||||
js_ValueToPrintableString(cx, args.rval()));
|
||||
return false;
|
||||
}
|
||||
args.rval().setObject(*obj);
|
||||
|
||||
/* The interpreter fixes rval for us. */
|
||||
JS_ASSERT(!fun->isInterpreted());
|
||||
|
||||
args.rval() = args.thisv();
|
||||
}
|
||||
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
|
@ -2290,7 +2305,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN
|
|||
do { \
|
||||
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \
|
||||
if (leaveOnSafePoint && !regs.fp->hasImacropc() && \
|
||||
script->nmap && script->nmap[regs.pc - script->code]) { \
|
||||
script->hasNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
|
||||
JS_ASSERT(!TRACE_RECORDER(cx)); \
|
||||
interpReturnOK = true; \
|
||||
goto stop_recording; \
|
||||
|
@ -4477,6 +4492,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;
|
||||
|
@ -4498,24 +4548,15 @@ BEGIN_CASE(JSOP_NEW)
|
|||
if (IsFunctionObject(vp[0], &callee)) {
|
||||
newfun = callee->getFunctionPrivate();
|
||||
if (newfun->isInterpreted()) {
|
||||
/* Root as we go using vp[1]. */
|
||||
if (!callee->getProperty(cx,
|
||||
ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
|
||||
&vp[1])) {
|
||||
goto error;
|
||||
}
|
||||
JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
|
||||
JSObject *obj2 = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent());
|
||||
if (!obj2)
|
||||
goto error;
|
||||
|
||||
if (newfun->u.i.script->isEmpty()) {
|
||||
JSObject *obj2 = js_CreateThisForFunction(cx, callee);
|
||||
if (!obj2)
|
||||
goto error;
|
||||
vp[0].setObject(*obj2);
|
||||
regs.sp = vp + 1;
|
||||
goto end_new;
|
||||
}
|
||||
|
||||
vp[1].setObject(*obj2);
|
||||
flags = JSFRAME_CONSTRUCTING;
|
||||
goto inline_call;
|
||||
}
|
||||
|
@ -4584,38 +4625,13 @@ BEGIN_CASE(JSOP_APPLY)
|
|||
if (newfun->isHeavyweight() && !js_GetCallObject(cx, regs.fp))
|
||||
goto error;
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
inlineCallCount++;
|
||||
JS_RUNTIME_METER(rt, inlineCalls);
|
||||
|
||||
Probes::enterJSFun(cx, newfun);
|
||||
|
||||
TRACE_0(EnterFrame);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/* Try to ensure methods are method JIT'd. */
|
||||
{
|
||||
JSObject *scope = ®s.fp->scopeChain();
|
||||
mjit::CompileStatus status = mjit::CanMethodJIT(cx, newscript, newfun, scope);
|
||||
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
|
||||
|
||||
/* Load first op and dispatch it (safe since JSOP_STOP). */
|
||||
op = (JSOp) *regs.pc;
|
||||
JS_ASSERT(op == JSOP_BEGIN);
|
||||
DO_OP();
|
||||
}
|
||||
|
||||
|
|
|
@ -968,7 +968,7 @@ extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
|
|||
Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, uintN interpFlags = 0);
|
||||
|
||||
extern JS_REQUIRES_STACK bool
|
||||
RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain);
|
||||
RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp);
|
||||
|
||||
#define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */
|
||||
|
||||
|
|
|
@ -1283,7 +1283,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||
JSObject *enumerators = cx->enumerators;
|
||||
cx->enumerators = gen->enumerators;
|
||||
|
||||
ok = RunScript(cx, stackfp->script(), stackfp->fun(), stackfp->scopeChain());
|
||||
ok = RunScript(cx, stackfp->script(), stackfp);
|
||||
|
||||
gen->enumerators = cx->enumerators;
|
||||
cx->enumerators = enumerators;
|
||||
|
|
|
@ -2770,7 +2770,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
js_NewInstance(JSContext *cx, JSObject *callee)
|
||||
js_CreateThis(JSContext *cx, JSObject *callee)
|
||||
{
|
||||
Class *clasp = callee->getClass();
|
||||
|
||||
|
@ -2790,6 +2790,25 @@ js_NewInstance(JSContext *cx, JSObject *callee)
|
|||
return NewObject<WithProto::Class>(cx, newclasp, proto, parent);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
|
||||
{
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent());
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_CreateThisForFunction(JSContext *cx, JSObject *callee)
|
||||
{
|
||||
Value protov;
|
||||
if (!callee->getProperty(cx,
|
||||
ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
|
||||
&protov)) {
|
||||
return NULL;
|
||||
}
|
||||
JSObject *proto = protov.isObject() ? &protov.toObject() : NULL;
|
||||
return js_CreateThisForFunctionWithProto(cx, callee, proto);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject*
|
||||
|
@ -2840,7 +2859,7 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, ST
|
|||
nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_NewInstanceFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
|
||||
js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JS_ASSERT(ctor->isFunction());
|
||||
|
@ -2891,7 +2910,7 @@ js_NewInstanceFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
|
|||
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstanceFromTrace, CONTEXT, CLASS, OBJECT, 0,
|
||||
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
#else /* !JS_TRACER */
|
||||
|
|
|
@ -1407,8 +1407,18 @@ extern JSObject *
|
|||
js_ConstructObject(JSContext *cx, js::Class *clasp, JSObject *proto,
|
||||
JSObject *parent, uintN argc, js::Value *argv);
|
||||
|
||||
// Specialized call for constructing |this| with a known function callee,
|
||||
// and a known prototype.
|
||||
extern JSObject *
|
||||
js_NewInstance(JSContext *cx, JSObject *callee);
|
||||
js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto);
|
||||
|
||||
// Specialized call for constructing |this| with a known function callee.
|
||||
extern JSObject *
|
||||
js_CreateThisForFunction(JSContext *cx, JSObject *callee);
|
||||
|
||||
// Generic call for constructing |this|.
|
||||
extern JSObject *
|
||||
js_CreateThis(JSContext *cx, JSObject *callee);
|
||||
|
||||
extern jsid
|
||||
js_CheckForStringIndex(jsid id);
|
||||
|
|
|
@ -620,3 +620,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)
|
||||
|
||||
OPDEF(JSOP_BEGIN, 249,"begin", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_TMPSLOT)
|
||||
|
||||
|
|
|
@ -1235,7 +1235,7 @@ callable_Call(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *thisobj = js_NewInstance(cx, &JS_CALLEE(cx, vp).toObject());
|
||||
JSObject *thisobj = js_CreateThis(cx, &JS_CALLEE(cx, vp).toObject());
|
||||
if (!thisobj)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
|||
uint32 length, lineno, nslots, magic;
|
||||
uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, nconsts, i;
|
||||
uint32 prologLength, version, encodedClosedCount;
|
||||
uint16 nClosedArgs, nClosedVars;
|
||||
uint16 nClosedArgs = 0, nClosedVars = 0;
|
||||
JSPrincipals *principals;
|
||||
uint32 encodeable;
|
||||
JSBool filenameWasSaved;
|
||||
|
@ -1641,16 +1641,6 @@ js_GetScriptLineExtent(JSScript *script)
|
|||
return 1 + lineno - script->lineno;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
bool
|
||||
JSScript::isValidJitCode(void *jcode)
|
||||
{
|
||||
return (char*)jcode >= (char*)jit->invoke &&
|
||||
(char*)jcode < (char*)jit->invoke +
|
||||
jit->inlineLength + jit->outOfLineLength;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
JSScript::copyClosedSlotsTo(JSScript *other)
|
||||
{
|
||||
|
|
|
@ -169,21 +169,20 @@ struct GlobalSlotArray {
|
|||
namespace JSC {
|
||||
class ExecutablePool;
|
||||
}
|
||||
|
||||
#define JS_UNJITTABLE_SCRIPT (reinterpret_cast<void*>(1))
|
||||
|
||||
enum JITScriptStatus {
|
||||
JITScript_None,
|
||||
JITScript_Invalid,
|
||||
JITScript_Valid
|
||||
};
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
struct JITScript;
|
||||
|
||||
namespace ic {
|
||||
# if defined JS_POLYIC
|
||||
struct PICInfo;
|
||||
# endif
|
||||
# if defined JS_MONOIC
|
||||
struct MICInfo;
|
||||
struct CallICInfo;
|
||||
# endif
|
||||
}
|
||||
struct CallSite;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -285,20 +284,35 @@ struct JSScript {
|
|||
|
||||
public:
|
||||
#ifdef JS_METHODJIT
|
||||
// Note: the other pointers in this group may be non-NULL only if
|
||||
// |execPool| is non-NULL.
|
||||
void *ncode; /* native code compiled by the method JIT */
|
||||
void **nmap; /* maps PCs to native code */
|
||||
js::mjit::JITScript *jit; /* Extra JIT info */
|
||||
# if defined JS_POLYIC
|
||||
js::mjit::ic::PICInfo *pics; /* PICs in this script */
|
||||
# endif
|
||||
# if defined JS_MONOIC
|
||||
js::mjit::ic::MICInfo *mics; /* MICs in this script. */
|
||||
js::mjit::ic::CallICInfo *callICs; /* CallICs in this script. */
|
||||
# endif
|
||||
// Fast-cached pointers to make calls faster. These are also used to
|
||||
// quickly test whether there is JIT code; a NULL value means no
|
||||
// compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
|
||||
// compilation failed. Any value is the arity-check entry point.
|
||||
void *jitArityCheckNormal;
|
||||
void *jitArityCheckCtor;
|
||||
|
||||
bool isValidJitCode(void *jcode);
|
||||
js::mjit::JITScript *jitNormal; /* Extra JIT info for normal scripts */
|
||||
js::mjit::JITScript *jitCtor; /* Extra JIT info for constructors */
|
||||
|
||||
bool hasJITCode() {
|
||||
return jitNormal || jitCtor;
|
||||
}
|
||||
|
||||
inline void **maybeNativeMap(bool constructing);
|
||||
inline bool hasNativeCodeForPC(bool constructing, jsbytecode *pc);
|
||||
|
||||
js::mjit::JITScript *getJIT(bool constructing) {
|
||||
return constructing ? jitCtor : jitNormal;
|
||||
}
|
||||
|
||||
JITScriptStatus getJITStatus(bool constructing) {
|
||||
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
|
||||
if (addr == NULL)
|
||||
return JITScript_None;
|
||||
if (addr == JS_UNJITTABLE_SCRIPT)
|
||||
return JITScript_Invalid;
|
||||
return JITScript_Valid;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Script notes are allocated right after the code. */
|
||||
|
@ -393,17 +407,6 @@ struct JSScript {
|
|||
return const_cast<JSScript *>(&emptyScriptConst);
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/*
|
||||
* Map the given PC to the corresponding native code address.
|
||||
*/
|
||||
void *pcToNative(jsbytecode *pc) {
|
||||
JS_ASSERT(nmap);
|
||||
JS_ASSERT(nmap[pc - code]);
|
||||
return nmap[pc - code];
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32 getClosedArg(uint32 index) {
|
||||
JS_ASSERT(index < nClosedArgs);
|
||||
return closedSlots[index];
|
||||
|
|
|
@ -11051,6 +11051,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)
|
||||
{
|
||||
|
@ -11360,7 +11374,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
clasp = &js_ObjectClass;
|
||||
JS_ASSERT(((jsuword) clasp & 3) == 0);
|
||||
|
||||
// Abort on |new Function|. js_NewInstance would allocate a regular-
|
||||
// Abort on |new Function|. js_CreateThis would allocate a regular-
|
||||
// sized JSObject, not a Function-sized one. (The Function ctor would
|
||||
// deep-bail anyway but let's not go there.)
|
||||
if (clasp == &js_FunctionClass)
|
||||
|
@ -11379,7 +11393,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
|
|||
args[0] = INS_CONSTOBJ(funobj);
|
||||
args[1] = INS_CONSTPTR(clasp);
|
||||
args[2] = cx_ins;
|
||||
newobj_ins = lir->insCall(&js_NewInstanceFromTrace_ci, args);
|
||||
newobj_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT);
|
||||
|
||||
/*
|
||||
|
@ -11504,15 +11518,8 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
if (mode == JSOP_NEW) {
|
||||
LIns* args[] = { get(&fval), INS_CONSTPTR(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = lir->insCall(&js_NewInstanceFromTrace_ci, args);
|
||||
guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
|
||||
set(&tval, tv_ins);
|
||||
}
|
||||
if (FUN_INTERPRETED(fun))
|
||||
return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW);
|
||||
}
|
||||
|
||||
Native native = fun->maybeNative();
|
||||
Value* argv = &tval + 1;
|
||||
|
@ -13306,7 +13313,15 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
|
|||
* and does not call any TR::record_*CallComplete hook.
|
||||
*/
|
||||
if (fun->u.i.script->isEmpty()) {
|
||||
LIns* rval_ins = constructing ? stack(-1 - argc) : INS_UNDEFINED();
|
||||
LIns* rval_ins;
|
||||
if (constructing) {
|
||||
LIns* args[] = { get(&fval), INS_CONSTPTR(&js_ObjectClass), cx_ins };
|
||||
LIns* tv_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
|
||||
guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
|
||||
rval_ins = tv_ins;
|
||||
} else {
|
||||
rval_ins = INS_UNDEFINED();
|
||||
}
|
||||
stack(-2 - argc, rval_ins);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -949,7 +949,7 @@ class TraceRecorder
|
|||
/* Carry the return value from a native call to the record_NativeCallComplete. */
|
||||
nanojit::LIns* native_rval_ins;
|
||||
|
||||
/* Carry the return value of js_NewInstance to record_NativeCallComplete. */
|
||||
/* Carry the return value of js_CreateThis to record_NativeCallComplete. */
|
||||
nanojit::LIns* newobj_ins;
|
||||
|
||||
/* Carry the JSSpecializedNative used to generate a call to record_NativeCallComplete. */
|
||||
|
|
|
@ -342,6 +342,11 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
}
|
||||
};
|
||||
|
||||
/* Return f<true> if the script is strict mode code, f<false> otherwise. */
|
||||
#define STRICT_VARIANT(f) \
|
||||
(FunctionTemplateConditional(script->strictModeCode, \
|
||||
f<true>, f<false>))
|
||||
|
||||
/* Save some typing. */
|
||||
static const JSC::MacroAssembler::RegisterID JSFrameReg = BaseAssembler::JSFrameReg;
|
||||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = BaseAssembler::JSReturnReg_Type;
|
||||
|
|
|
@ -74,12 +74,16 @@ static const char *OpcodeNames[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
|
||||
mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
||||
: BaseCompiler(cx),
|
||||
script(script),
|
||||
scopeChain(scopeChain),
|
||||
fp(fp),
|
||||
script(fp->script()),
|
||||
scopeChain(&fp->scopeChain()),
|
||||
globalObj(scopeChain->getGlobal()),
|
||||
fun(fun),
|
||||
fun(fp->isFunctionFrame() && !fp->isEvalFrame()
|
||||
? fp->fun()
|
||||
: NULL),
|
||||
isConstructing(fp->isConstructing()),
|
||||
analysis(cx, script), jumpMap(NULL), frame(cx, script, masm),
|
||||
branchPatches(ContextAllocPolicy(cx)),
|
||||
#if defined JS_MONOIC
|
||||
|
@ -99,6 +103,34 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObj
|
|||
{
|
||||
}
|
||||
|
||||
CompileStatus
|
||||
mjit::Compiler::compile()
|
||||
{
|
||||
JS_ASSERT(!script->isEmpty());
|
||||
JS_ASSERT_IF(isConstructing, !script->jitCtor);
|
||||
JS_ASSERT_IF(!isConstructing, !script->jitNormal);
|
||||
|
||||
JITScript **jit = isConstructing ? &script->jitCtor : &script->jitNormal;
|
||||
void **checkAddr = isConstructing
|
||||
? &script->jitArityCheckCtor
|
||||
: &script->jitArityCheckNormal;
|
||||
|
||||
CompileStatus status = performCompilation(jit);
|
||||
if (status == Compile_Okay) {
|
||||
// Global scripts don't have an arity check entry. That's okay, we
|
||||
// just need a pointer so the VM can quickly decide whether this
|
||||
// method can be JIT'd or not. Global scripts cannot be IC'd, since
|
||||
// they have no functions, so there is no danger.
|
||||
*checkAddr = (*jit)->arityCheckEntry
|
||||
? (*jit)->arityCheckEntry
|
||||
: (*jit)->invokeEntry;
|
||||
} else {
|
||||
*checkAddr = JS_UNJITTABLE_SCRIPT;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define CHECK_STATUS(expr) \
|
||||
JS_BEGIN_MACRO \
|
||||
CompileStatus status_ = (expr); \
|
||||
|
@ -107,10 +139,8 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObj
|
|||
JS_END_MACRO
|
||||
|
||||
CompileStatus
|
||||
mjit::Compiler::Compile()
|
||||
mjit::Compiler::performCompilation(JITScript **jitp)
|
||||
{
|
||||
JS_ASSERT(!script->ncode);
|
||||
|
||||
JaegerSpew(JSpew_Scripts, "compiling script (file \"%s\") (line \"%d\") (length \"%d\")\n",
|
||||
script->filename, script->lineno, script->length);
|
||||
|
||||
|
@ -152,7 +182,7 @@ mjit::Compiler::Compile()
|
|||
CHECK_STATUS(generatePrologue());
|
||||
CHECK_STATUS(generateMethod());
|
||||
CHECK_STATUS(generateEpilogue());
|
||||
CHECK_STATUS(finishThisUp());
|
||||
CHECK_STATUS(finishThisUp(jitp));
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
prof.stop();
|
||||
|
@ -160,7 +190,7 @@ mjit::Compiler::Compile()
|
|||
#endif
|
||||
|
||||
JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
|
||||
(void*)script->ncode, masm.size() + stubcc.size());
|
||||
(*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
|
||||
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
@ -173,18 +203,13 @@ mjit::Compiler::~Compiler()
|
|||
}
|
||||
|
||||
CompileStatus JS_NEVER_INLINE
|
||||
mjit::TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
|
||||
mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
Compiler cc(cx, script, fun, scopeChain);
|
||||
JS_ASSERT(cx->fp() == fp);
|
||||
|
||||
JS_ASSERT(!script->ncode);
|
||||
JS_ASSERT(!script->isEmpty());
|
||||
Compiler cc(cx, fp);
|
||||
|
||||
CompileStatus status = cc.Compile();
|
||||
if (status != Compile_Okay)
|
||||
script->ncode = JS_UNJITTABLE_METHOD;
|
||||
|
||||
return status;
|
||||
return cc.compile();
|
||||
}
|
||||
|
||||
CompileStatus
|
||||
|
@ -290,7 +315,7 @@ mjit::Compiler::generateEpilogue()
|
|||
}
|
||||
|
||||
CompileStatus
|
||||
mjit::Compiler::finishThisUp()
|
||||
mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
{
|
||||
for (size_t i = 0; i < branchPatches.length(); i++) {
|
||||
Label label = labelOf(branchPatches[i].pc);
|
||||
|
@ -336,18 +361,16 @@ mjit::Compiler::finishThisUp()
|
|||
return Compile_Error;
|
||||
}
|
||||
|
||||
script->jit = (JITScript *)cursor;
|
||||
JITScript *jit = (JITScript *)cursor;
|
||||
cursor += sizeof(JITScript);
|
||||
|
||||
script->jit->execPool = execPool;
|
||||
script->jit->inlineLength = masm.size();
|
||||
script->jit->outOfLineLength = stubcc.size();
|
||||
script->jit->nCallSites = callSites.length();
|
||||
script->jit->invoke = result;
|
||||
jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
|
||||
jit->nCallSites = callSites.length();
|
||||
jit->invokeEntry = result;
|
||||
|
||||
/* Build the pc -> ncode mapping. */
|
||||
void **nmap = (void **)cursor;
|
||||
script->nmap = nmap;
|
||||
jit->nmap = nmap;
|
||||
cursor += sizeof(void *) * script->length;
|
||||
|
||||
for (size_t i = 0; i < script->length; i++) {
|
||||
|
@ -358,107 +381,116 @@ mjit::Compiler::finishThisUp()
|
|||
}
|
||||
}
|
||||
|
||||
if (fun)
|
||||
script->jit->arityCheck = stubCode.locationOf(arityLabel).executableAddress();
|
||||
|
||||
#if defined JS_MONOIC
|
||||
script->jit->nMICs = mics.length();
|
||||
if (mics.length()) {
|
||||
script->mics = (ic::MICInfo *)cursor;
|
||||
cursor += sizeof(ic::MICInfo) * mics.length();
|
||||
} else {
|
||||
script->mics = NULL;
|
||||
if (fun) {
|
||||
jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
|
||||
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mics.length(); i++) {
|
||||
script->mics[i].kind = mics[i].kind;
|
||||
script->mics[i].entry = fullCode.locationOf(mics[i].entry);
|
||||
switch (mics[i].kind) {
|
||||
case ic::MICInfo::GET:
|
||||
case ic::MICInfo::SET:
|
||||
script->mics[i].load = fullCode.locationOf(mics[i].load);
|
||||
script->mics[i].shape = fullCode.locationOf(mics[i].shape);
|
||||
script->mics[i].stubCall = stubCode.locationOf(mics[i].call);
|
||||
script->mics[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
|
||||
script->mics[i].u.name.typeConst = mics[i].u.name.typeConst;
|
||||
script->mics[i].u.name.dataConst = mics[i].u.name.dataConst;
|
||||
#if defined JS_MONOIC
|
||||
jit->nMICs = mics.length();
|
||||
if (mics.length()) {
|
||||
jit->mics = (ic::MICInfo *)cursor;
|
||||
cursor += sizeof(ic::MICInfo) * mics.length();
|
||||
} else {
|
||||
jit->mics = NULL;
|
||||
}
|
||||
|
||||
if (ic::MICInfo *scriptMICs = jit->mics) {
|
||||
for (size_t i = 0; i < mics.length(); i++) {
|
||||
scriptMICs[i].kind = mics[i].kind;
|
||||
scriptMICs[i].entry = fullCode.locationOf(mics[i].entry);
|
||||
switch (mics[i].kind) {
|
||||
case ic::MICInfo::GET:
|
||||
case ic::MICInfo::SET:
|
||||
scriptMICs[i].load = fullCode.locationOf(mics[i].load);
|
||||
scriptMICs[i].shape = fullCode.locationOf(mics[i].shape);
|
||||
scriptMICs[i].stubCall = stubCode.locationOf(mics[i].call);
|
||||
scriptMICs[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
|
||||
scriptMICs[i].u.name.typeConst = mics[i].u.name.typeConst;
|
||||
scriptMICs[i].u.name.dataConst = mics[i].u.name.dataConst;
|
||||
#if defined JS_PUNBOX64
|
||||
script->mics[i].patchValueOffset = mics[i].patchValueOffset;
|
||||
scriptMICs[i].patchValueOffset = mics[i].patchValueOffset;
|
||||
#endif
|
||||
break;
|
||||
case ic::MICInfo::TRACER: {
|
||||
uint32 offs = uint32(mics[i].jumpTarget - script->code);
|
||||
JS_ASSERT(jumpMap[offs].isValid());
|
||||
script->mics[i].traceHint = fullCode.locationOf(mics[i].traceHint);
|
||||
script->mics[i].load = fullCode.locationOf(jumpMap[offs]);
|
||||
script->mics[i].u.hints.hasSlowTraceHintOne = mics[i].slowTraceHintOne.isSet();
|
||||
if (mics[i].slowTraceHintOne.isSet())
|
||||
script->mics[i].slowTraceHintOne = stubCode.locationOf(mics[i].slowTraceHintOne.get());
|
||||
script->mics[i].u.hints.hasSlowTraceHintTwo = mics[i].slowTraceHintTwo.isSet();
|
||||
if (mics[i].slowTraceHintTwo.isSet())
|
||||
script->mics[i].slowTraceHintTwo = stubCode.locationOf(mics[i].slowTraceHintTwo.get());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
JS_NOT_REACHED("Bad MIC kind");
|
||||
break;
|
||||
case ic::MICInfo::TRACER: {
|
||||
uint32 offs = uint32(mics[i].jumpTarget - script->code);
|
||||
JS_ASSERT(jumpMap[offs].isValid());
|
||||
scriptMICs[i].traceHint = fullCode.locationOf(mics[i].traceHint);
|
||||
scriptMICs[i].load = fullCode.locationOf(jumpMap[offs]);
|
||||
scriptMICs[i].u.hints.hasSlowTraceHintOne = mics[i].slowTraceHintOne.isSet();
|
||||
if (mics[i].slowTraceHintOne.isSet())
|
||||
scriptMICs[i].slowTraceHintOne = stubCode.locationOf(mics[i].slowTraceHintOne.get());
|
||||
scriptMICs[i].u.hints.hasSlowTraceHintTwo = mics[i].slowTraceHintTwo.isSet();
|
||||
if (mics[i].slowTraceHintTwo.isSet())
|
||||
scriptMICs[i].slowTraceHintTwo = stubCode.locationOf(mics[i].slowTraceHintTwo.get());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
JS_NOT_REACHED("Bad MIC kind");
|
||||
}
|
||||
stubCode.patch(mics[i].addrLabel, &scriptMICs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
script->jit->nCallICs = callICs.length();
|
||||
jit->nCallICs = callICs.length();
|
||||
if (callICs.length()) {
|
||||
script->callICs = (ic::CallICInfo *)cursor;
|
||||
jit->callICs = (ic::CallICInfo *)cursor;
|
||||
cursor += sizeof(ic::CallICInfo) * callICs.length();
|
||||
} else {
|
||||
script->callICs = NULL;
|
||||
jit->callICs = NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < callICs.length(); i++) {
|
||||
script->callICs[i].reset();
|
||||
script->callICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
|
||||
script->callICs[i].funJump = fullCode.locationOf(callICs[i].funJump);
|
||||
script->callICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
|
||||
if (ic::CallICInfo *cics = jit->callICs) {
|
||||
for (size_t i = 0; i < callICs.length(); i++) {
|
||||
cics[i].reset();
|
||||
cics[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
|
||||
cics[i].funJump = fullCode.locationOf(callICs[i].funJump);
|
||||
cics[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
|
||||
|
||||
/* Compute the hot call offset. */
|
||||
uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
|
||||
fullCode.locationOf(callICs[i].funGuard);
|
||||
script->callICs[i].hotJumpOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].hotJumpOffset == offset);
|
||||
/* Compute the hot call offset. */
|
||||
uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
|
||||
fullCode.locationOf(callICs[i].funGuard);
|
||||
cics[i].hotJumpOffset = offset;
|
||||
JS_ASSERT(cics[i].hotJumpOffset == offset);
|
||||
|
||||
/* Compute the join point offset. */
|
||||
offset = fullCode.locationOf(callICs[i].joinPoint) -
|
||||
fullCode.locationOf(callICs[i].funGuard);
|
||||
script->callICs[i].joinPointOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].joinPointOffset == offset);
|
||||
|
||||
/* Compute the OOL call offset. */
|
||||
offset = stubCode.locationOf(callICs[i].oolCall) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
script->callICs[i].oolCallOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].oolCallOffset == offset);
|
||||
/* Compute the join point offset. */
|
||||
offset = fullCode.locationOf(callICs[i].joinPoint) -
|
||||
fullCode.locationOf(callICs[i].funGuard);
|
||||
cics[i].joinPointOffset = offset;
|
||||
JS_ASSERT(cics[i].joinPointOffset == offset);
|
||||
|
||||
/* Compute the OOL call offset. */
|
||||
offset = stubCode.locationOf(callICs[i].oolCall) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
cics[i].oolCallOffset = offset;
|
||||
JS_ASSERT(cics[i].oolCallOffset == offset);
|
||||
|
||||
/* Compute the OOL jump offset. */
|
||||
offset = stubCode.locationOf(callICs[i].oolJump) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
script->callICs[i].oolJumpOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].oolJumpOffset == offset);
|
||||
/* Compute the OOL jump offset. */
|
||||
offset = stubCode.locationOf(callICs[i].oolJump) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
cics[i].oolJumpOffset = offset;
|
||||
JS_ASSERT(cics[i].oolJumpOffset == offset);
|
||||
|
||||
/* Compute the slow join point offset. */
|
||||
offset = stubCode.locationOf(callICs[i].slowJoinPoint) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
script->callICs[i].slowJoinOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].slowJoinOffset == offset);
|
||||
/* Compute the slow join point offset. */
|
||||
offset = stubCode.locationOf(callICs[i].slowJoinPoint) -
|
||||
stubCode.locationOf(callICs[i].slowPathStart);
|
||||
cics[i].slowJoinOffset = offset;
|
||||
JS_ASSERT(cics[i].slowJoinOffset == offset);
|
||||
|
||||
/* Compute the join point offset for continuing on the hot path. */
|
||||
offset = stubCode.locationOf(callICs[i].hotPathLabel) -
|
||||
stubCode.locationOf(callICs[i].funGuard);
|
||||
script->callICs[i].hotPathOffset = offset;
|
||||
JS_ASSERT(script->callICs[i].hotPathOffset == offset);
|
||||
/* Compute the join point offset for continuing on the hot path. */
|
||||
offset = stubCode.locationOf(callICs[i].hotPathLabel) -
|
||||
stubCode.locationOf(callICs[i].funGuard);
|
||||
cics[i].hotPathOffset = offset;
|
||||
JS_ASSERT(cics[i].hotPathOffset == offset);
|
||||
|
||||
script->callICs[i].pc = callICs[i].pc;
|
||||
script->callICs[i].argc = callICs[i].argc;
|
||||
script->callICs[i].funObjReg = callICs[i].funObjReg;
|
||||
script->callICs[i].funPtrReg = callICs[i].funPtrReg;
|
||||
script->callICs[i].frameDepth = callICs[i].frameDepth;
|
||||
cics[i].pc = callICs[i].pc;
|
||||
cics[i].argc = callICs[i].argc;
|
||||
cics[i].funObjReg = callICs[i].funObjReg;
|
||||
cics[i].funPtrReg = callICs[i].funPtrReg;
|
||||
cics[i].frameDepth = callICs[i].frameDepth;
|
||||
stubCode.patch(callICs[i].addrLabel1, &cics[i]);
|
||||
stubCode.patch(callICs[i].addrLabel2, &cics[i]);
|
||||
}
|
||||
}
|
||||
#endif /* JS_MONOIC */
|
||||
|
||||
|
@ -471,44 +503,47 @@ mjit::Compiler::finishThisUp()
|
|||
}
|
||||
|
||||
#if defined JS_POLYIC
|
||||
script->jit->nPICs = pics.length();
|
||||
jit->nPICs = pics.length();
|
||||
if (pics.length()) {
|
||||
script->pics = (ic::PICInfo *)cursor;
|
||||
jit->pics = (ic::PICInfo *)cursor;
|
||||
cursor += sizeof(ic::PICInfo) * pics.length();
|
||||
} else {
|
||||
script->pics = NULL;
|
||||
jit->pics = NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pics.length(); i++) {
|
||||
pics[i].copySimpleMembersTo(script->pics[i]);
|
||||
script->pics[i].fastPathStart = fullCode.locationOf(pics[i].fastPathStart);
|
||||
script->pics[i].storeBack = fullCode.locationOf(pics[i].storeBack);
|
||||
script->pics[i].slowPathStart = stubCode.locationOf(pics[i].slowPathStart);
|
||||
script->pics[i].callReturn = uint16((uint8*)stubCode.locationOf(pics[i].callReturn).executableAddress() -
|
||||
(uint8*)script->pics[i].slowPathStart.executableAddress());
|
||||
script->pics[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].fastPathStart);
|
||||
JS_ASSERT(script->pics[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].fastPathStart));
|
||||
script->pics[i].shapeRegHasBaseShape = true;
|
||||
if (ic::PICInfo *scriptPICs = jit->pics) {
|
||||
for (size_t i = 0; i < pics.length(); i++) {
|
||||
pics[i].copySimpleMembersTo(scriptPICs[i]);
|
||||
scriptPICs[i].fastPathStart = fullCode.locationOf(pics[i].fastPathStart);
|
||||
scriptPICs[i].storeBack = fullCode.locationOf(pics[i].storeBack);
|
||||
scriptPICs[i].slowPathStart = stubCode.locationOf(pics[i].slowPathStart);
|
||||
scriptPICs[i].callReturn = uint16((uint8*)stubCode.locationOf(pics[i].callReturn).executableAddress() -
|
||||
(uint8*)scriptPICs[i].slowPathStart.executableAddress());
|
||||
scriptPICs[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].fastPathStart);
|
||||
JS_ASSERT(scriptPICs[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].fastPathStart));
|
||||
scriptPICs[i].shapeRegHasBaseShape = true;
|
||||
|
||||
# if defined JS_CPU_X64
|
||||
memcpy(&script->pics[i].labels, &pics[i].labels, sizeof(PICLabels));
|
||||
memcpy(&scriptPICs[i].labels, &pics[i].labels, sizeof(PICLabels));
|
||||
# endif
|
||||
|
||||
if (pics[i].kind == ic::PICInfo::SET ||
|
||||
pics[i].kind == ic::PICInfo::SETMETHOD) {
|
||||
script->pics[i].u.vr = pics[i].vr;
|
||||
} else if (pics[i].kind != ic::PICInfo::NAME) {
|
||||
if (pics[i].hasTypeCheck) {
|
||||
int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) -
|
||||
stubcc.masm.distanceOf(pics[i].slowPathStart);
|
||||
JS_ASSERT(distance <= 0);
|
||||
script->pics[i].u.get.typeCheckOffset = distance;
|
||||
if (pics[i].kind == ic::PICInfo::SET ||
|
||||
pics[i].kind == ic::PICInfo::SETMETHOD) {
|
||||
scriptPICs[i].u.vr = pics[i].vr;
|
||||
} else if (pics[i].kind != ic::PICInfo::NAME) {
|
||||
if (pics[i].hasTypeCheck) {
|
||||
int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) -
|
||||
stubcc.masm.distanceOf(pics[i].slowPathStart);
|
||||
JS_ASSERT(distance <= 0);
|
||||
scriptPICs[i].u.get.typeCheckOffset = distance;
|
||||
}
|
||||
}
|
||||
new (&scriptPICs[i].execPools) ic::PICInfo::ExecPoolVector(SystemAllocPolicy());
|
||||
scriptPICs[i].reset();
|
||||
stubCode.patch(pics[i].addrLabel, &scriptPICs[i]);
|
||||
}
|
||||
new (&script->pics[i].execPools) ic::PICInfo::ExecPoolVector(SystemAllocPolicy());
|
||||
script->pics[i].reset();
|
||||
}
|
||||
#endif /* JS_POLYIC */
|
||||
|
||||
|
@ -534,10 +569,8 @@ mjit::Compiler::finishThisUp()
|
|||
JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
|
||||
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
|
||||
|
||||
script->ncode = (uint8 *)(result + masm.distanceOf(invokeLabel));
|
||||
|
||||
/* Build the table of call sites. */
|
||||
script->jit->nCallSites = callSites.length();
|
||||
jit->nCallSites = callSites.length();
|
||||
if (callSites.length()) {
|
||||
CallSite *callSiteList = (CallSite *)cursor;
|
||||
cursor += sizeof(CallSite) * callSites.length();
|
||||
|
@ -550,12 +583,14 @@ mjit::Compiler::finishThisUp()
|
|||
callSiteList[i].pcOffset = callSites[i].pc - script->code;
|
||||
callSiteList[i].id = callSites[i].id;
|
||||
}
|
||||
script->jit->callSites = callSiteList;
|
||||
jit->callSites = callSiteList;
|
||||
} else {
|
||||
script->jit->callSites = NULL;
|
||||
jit->callSites = NULL;
|
||||
}
|
||||
|
||||
JS_ASSERT(size_t(cursor - (uint8*)script->jit) == totalBytes);
|
||||
JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes);
|
||||
|
||||
*jitp = jit;
|
||||
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
@ -1662,6 +1697,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
|
||||
|
@ -1717,15 +1757,17 @@ mjit::Compiler::findCallSite(const CallSite &callSite)
|
|||
{
|
||||
JS_ASSERT(callSite.pcOffset < script->length);
|
||||
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
uint8* ilPath = (uint8 *)jit->code.m_code.executableAddress();
|
||||
uint8* oolPath = ilPath + masm.size();
|
||||
|
||||
for (uint32 i = 0; i < callSites.length(); i++) {
|
||||
if (callSites[i].pc == script->code + callSite.pcOffset &&
|
||||
callSites[i].id == callSite.id) {
|
||||
if (callSites[i].stub) {
|
||||
return (uint8*)script->jit->invoke + masm.size() +
|
||||
stubcc.masm.distanceOf(callSites[i].location);
|
||||
return oolPath + stubcc.masm.distanceOf(callSites[i].location);
|
||||
}
|
||||
return (uint8*)script->jit->invoke +
|
||||
stubcc.masm.distanceOf(callSites[i].location);
|
||||
return ilPath + masm.distanceOf(callSites[i].location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1781,24 +1823,100 @@ mjit::Compiler::emitFinalReturn(Assembler &masm)
|
|||
masm.jump(Registers::ReturnReg);
|
||||
}
|
||||
|
||||
// Emits code to load a return value of the frame into the scripted-ABI
|
||||
// type & data register pair. If the return value is in fp->rval, then |fe|
|
||||
// is NULL. Otherwise, |fe| contains the return value.
|
||||
//
|
||||
// If reading from fp->rval, |undefined| is loaded optimistically, before
|
||||
// checking if fp->rval is set in the frame flags and loading that instead.
|
||||
//
|
||||
// Otherwise, if |masm| is the inline path, it is loaded as efficiently as
|
||||
// the FrameState can manage. If |masm| is the OOL path, the value is simply
|
||||
// loaded from its slot in the frame, since the caller has guaranteed it's
|
||||
// been synced.
|
||||
//
|
||||
void
|
||||
mjit::Compiler::loadReturnValue(Assembler &masm)
|
||||
mjit::Compiler::loadReturnValue(Assembler *masm, FrameEntry *fe)
|
||||
{
|
||||
/*
|
||||
* Load a return value from POPV or SETRVAL into the return registers,
|
||||
* otherwise return undefined.
|
||||
*/
|
||||
masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data);
|
||||
if (analysis.usesReturnValue()) {
|
||||
Jump rvalClear = masm.branchTest32(Assembler::Zero,
|
||||
FrameFlagsAddress(), Imm32(JSFRAME_HAS_RVAL));
|
||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm.loadValueAsComponents(rvalAddress,
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
rvalClear.linkTo(masm.label(), &masm);
|
||||
RegisterID typeReg = JSReturnReg_Type;
|
||||
RegisterID dataReg = JSReturnReg_Data;
|
||||
|
||||
if (fe) {
|
||||
// If using the OOL assembler, the caller signifies that the |fe| is
|
||||
// synced, but not to rely on its register state.
|
||||
if (masm != &this->masm) {
|
||||
if (fe->isConstant()) {
|
||||
stubcc.masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg);
|
||||
} else {
|
||||
Address rval(frame.addressOf(fe));
|
||||
if (fe->isTypeKnown()) {
|
||||
stubcc.masm.loadPayload(rval, dataReg);
|
||||
stubcc.masm.move(ImmType(fe->getKnownType()), typeReg);
|
||||
} else {
|
||||
stubcc.masm.loadValueAsComponents(rval, typeReg, dataReg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
frame.loadTo(fe, typeReg, dataReg, Registers::ReturnReg);
|
||||
}
|
||||
} else {
|
||||
// Load a return value from POPV or SETRVAL into the return registers,
|
||||
// otherwise return undefined.
|
||||
masm->loadValueAsComponents(UndefinedValue(), typeReg, dataReg);
|
||||
if (analysis.usesReturnValue()) {
|
||||
Jump rvalClear = masm->branchTest32(Assembler::Zero,
|
||||
FrameFlagsAddress(),
|
||||
Imm32(JSFRAME_HAS_RVAL));
|
||||
Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||
masm->loadValueAsComponents(rvalAddress, typeReg, dataReg);
|
||||
rvalClear.linkTo(masm->label(), masm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This ensures that constructor return values are an object. If a non-object
|
||||
// is returned, either explicitly or implicitly, the newly created object is
|
||||
// loaded out of the frame. Otherwise, the explicitly returned object is kept.
|
||||
//
|
||||
void
|
||||
mjit::Compiler::fixPrimitiveReturn(Assembler *masm, FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(isConstructing);
|
||||
|
||||
Address thisv(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
||||
|
||||
// Easy cases - no return value, or known primitive, so just return thisv.
|
||||
if (!fe || (fe->isTypeKnown() && fe->getKnownType() != JSVAL_TYPE_OBJECT)) {
|
||||
masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the type is known to be an object, just load the return value as normal.
|
||||
if (fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_OBJECT) {
|
||||
loadReturnValue(masm, fe);
|
||||
return;
|
||||
}
|
||||
|
||||
// There's a return value, and its type is unknown. Test the type and load
|
||||
// |thisv| if necessary.
|
||||
loadReturnValue(masm, fe);
|
||||
Jump j = masm->testObject(Assembler::Equal, JSReturnReg_Type);
|
||||
masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
|
||||
j.linkTo(masm->label(), masm);
|
||||
}
|
||||
|
||||
// Loads the return value into the scripted ABI register pair, such that JS
|
||||
// semantics in constructors are preserved.
|
||||
//
|
||||
void
|
||||
mjit::Compiler::emitReturnValue(Assembler *masm, FrameEntry *fe)
|
||||
{
|
||||
if (isConstructing)
|
||||
fixPrimitiveReturn(masm, fe);
|
||||
else
|
||||
loadReturnValue(masm, fe);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||
{
|
||||
|
@ -1823,8 +1941,7 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
|||
stubCall(stubs::PutActivationObjects);
|
||||
|
||||
if (fe) {
|
||||
masm.loadValueAsComponents(frame.addressOf(fe),
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
emitReturnValue(&masm, fe);
|
||||
emitFinalReturn(masm);
|
||||
frame.discardFrame();
|
||||
return;
|
||||
|
@ -1839,22 +1956,12 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
|||
stubcc.leave();
|
||||
stubcc.call(stubs::PutActivationObjects);
|
||||
|
||||
if (fe) {
|
||||
stubcc.masm.loadValueAsComponents(frame.addressOf(fe),
|
||||
JSReturnReg_Type, JSReturnReg_Data);
|
||||
} else {
|
||||
loadReturnValue(stubcc.masm);
|
||||
}
|
||||
|
||||
emitReturnValue(&stubcc.masm, fe);
|
||||
emitFinalReturn(stubcc.masm);
|
||||
}
|
||||
}
|
||||
|
||||
if (fe)
|
||||
frame.storeTo(fe, JSReturnReg_Data, JSReturnReg_Type, Registers::ReturnReg);
|
||||
else
|
||||
loadReturnValue(masm);
|
||||
|
||||
emitReturnValue(&masm, fe);
|
||||
emitFinalReturn(masm);
|
||||
frame.discardFrame();
|
||||
}
|
||||
|
@ -1929,18 +2036,6 @@ mjit::Compiler::interruptCheckHelper()
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitPrimitiveTestForNew(uint32 argc)
|
||||
{
|
||||
Jump primitive = masm.testPrimitive(Assembler::Equal, JSReturnReg_Type);
|
||||
stubcc.linkExitDirect(primitive, stubcc.masm.label());
|
||||
FrameEntry *fe = frame.peek(-int(argc + 1));
|
||||
Address thisv(frame.addressOf(fe));
|
||||
stubcc.masm.loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
|
||||
Jump primFix = stubcc.masm.jump();
|
||||
stubcc.crossJump(primFix, masm.label());
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
||||
{
|
||||
|
@ -1973,9 +2068,6 @@ mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
|
|||
callPatch.joinPoint = masm.label();
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
||||
|
||||
if (callingNew)
|
||||
emitPrimitiveTestForNew(argc);
|
||||
|
||||
frame.popn(argc + 2);
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
|
@ -1993,6 +2085,10 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
/* Check for interrupts on function call */
|
||||
interruptCheckHelper();
|
||||
|
||||
// |thisv| does not need to be synced for constructing.
|
||||
if (callingNew)
|
||||
frame.discardFe(frame.peek(-int(argc + 1)));
|
||||
|
||||
FrameEntry *fe = frame.peek(-int(argc + 2));
|
||||
|
||||
/* Currently, we don't support constant functions. */
|
||||
|
@ -2002,12 +2098,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
}
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
FrameEntry *thisvFe = frame.peek(-int(argc + 1));
|
||||
Address thisvAddr = frame.addressOf(thisvFe);
|
||||
|
||||
CallGenInfo callIC(argc);
|
||||
uint32 callICIndex = callICs.length();
|
||||
|
||||
CallPatchInfo callPatch;
|
||||
|
||||
/*
|
||||
|
@ -2044,16 +2135,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
if (typeReg.isSet())
|
||||
notObjectJump = masm.testObject(Assembler::NotEqual, typeReg.reg());
|
||||
|
||||
/*
|
||||
* Ensure that dataReg stays in a register which won't be clobbered
|
||||
* by the intervening call to NewObject.
|
||||
*/
|
||||
if (callingNew && !(Registers::maskReg(dataReg) & Registers::SavedRegs)) {
|
||||
RegisterID reg = Registers(Registers::SavedRegs).takeAnyReg();
|
||||
masm.move(dataReg, reg);
|
||||
dataReg = reg;
|
||||
}
|
||||
|
||||
tempRegs.takeReg(dataReg);
|
||||
RegisterID t0 = tempRegs.takeAnyReg();
|
||||
RegisterID t1 = tempRegs.takeAnyReg();
|
||||
|
@ -2083,28 +2164,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
stubcc.masm.and32(Imm32(JSFUN_KINDMASK), t1);
|
||||
Jump isNative = stubcc.masm.branch32(Assembler::Below, t1, Imm32(JSFUN_INTERPRETED));
|
||||
|
||||
/* Create the new object. This requires some fiddling to save the two values. */
|
||||
if (callingNew) {
|
||||
void *pfun = stubcc.masm.getCallTarget(JS_FUNC_TO_DATA_PTR(void *, stubs::NewObject));
|
||||
stubcc.masm.storePtr(ImmPtr(PC),
|
||||
FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
|
||||
stubcc.masm.fixScriptStack(frame.frameDepth());
|
||||
stubcc.masm.setupVMFrame();
|
||||
#if defined(JS_CPU_X86)
|
||||
/* Need to stay 16-byte aligned on x86. */
|
||||
stubcc.masm.subPtr(Imm32(8), JSC::MacroAssembler::stackPointerRegister);
|
||||
#endif
|
||||
stubcc.masm.push(dataReg);
|
||||
stubcc.masm.push(t0);
|
||||
stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
stubcc.masm.wrapCall(pfun);
|
||||
stubcc.masm.pop(t0);
|
||||
stubcc.masm.pop(dataReg);
|
||||
#if defined(JS_CPU_X86)
|
||||
stubcc.masm.addPtr(Imm32(8), JSC::MacroAssembler::stackPointerRegister);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* No-op jump that gets re-patched. This is so ArgReg1 won't be
|
||||
* clobbered, with the added bonus that the generated stub doesn't
|
||||
|
@ -2115,7 +2174,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
callIC.oolJump = toPatch;
|
||||
|
||||
/* At this point the function is definitely scripted. Call the link routine. */
|
||||
stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
|
||||
callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
callIC.oolCall = stubcc.call(callingNew ? ic::New : ic::Call);
|
||||
|
||||
callIC.funObjReg = dataReg;
|
||||
|
@ -2145,7 +2204,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
notFunction.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
isNative.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
|
||||
stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
|
||||
callIC.addrLabel2 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
stubcc.call(callingNew ? ic::NativeNew : ic::NativeCall);
|
||||
|
||||
rejoin2 = stubcc.masm.jump();
|
||||
|
@ -2157,13 +2216,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
*/
|
||||
callIC.hotPathLabel = masm.label();
|
||||
|
||||
/* If calling |new|, make sure to allocate a new object. */
|
||||
if (callingNew) {
|
||||
prepareStubCall(Uses(argc + 2));
|
||||
masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
stubCall(stubs::NewObject);
|
||||
}
|
||||
|
||||
uint32 flags = 0;
|
||||
if (callingNew)
|
||||
flags |= JSFRAME_CONSTRUCTING;
|
||||
|
@ -2175,13 +2227,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
|||
callIC.joinPoint = callPatch.joinPoint = masm.label();
|
||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg);
|
||||
|
||||
/*
|
||||
* Functions invoked with |new| can return primitive values.
|
||||
* Just deal with this here.
|
||||
*/
|
||||
if (callingNew)
|
||||
emitPrimitiveTestForNew(argc);
|
||||
|
||||
frame.popn(argc + 2);
|
||||
frame.takeReg(JSReturnReg_Type);
|
||||
frame.takeReg(JSReturnReg_Data);
|
||||
|
@ -2375,6 +2420,19 @@ mjit::Compiler::jsop_length()
|
|||
}
|
||||
|
||||
#if defined JS_POLYIC
|
||||
|
||||
void
|
||||
mjit::Compiler::passPICAddress(PICGenInfo &pic)
|
||||
{
|
||||
pic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::passMICAddress(MICGenInfo &mic)
|
||||
{
|
||||
mic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
||||
{
|
||||
|
@ -2445,7 +2503,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::GetProp);
|
||||
|
||||
/* Load dslots. */
|
||||
|
@ -2546,7 +2604,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj
|
|||
pic.slowPathStart = stubcc.linkExit(jmpShapeGuard, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::GetElem);
|
||||
|
||||
/* Load dslots. */
|
||||
|
@ -2672,7 +2730,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
|
||||
/* Slow path. */
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::CallProp);
|
||||
|
||||
/* Adjust the frame. None of this will generate code. */
|
||||
|
@ -2836,7 +2894,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::CallProp);
|
||||
|
||||
/* Load dslots. */
|
||||
|
@ -2958,13 +3016,12 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
|
|||
* the normal SETNAME property cache logic.
|
||||
*/
|
||||
JSOp op = JSOp(*PC);
|
||||
stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
if (op == JSOP_SETNAME || op == JSOP_SETPROP || op == JSOP_SETGNAME || op ==
|
||||
JSOP_SETMETHOD) {
|
||||
stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
|
||||
stubcc.call(STRICT_VARIANT(stubs::SetName));
|
||||
} else {
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
stubcc.call(ic::SetPropDumb);
|
||||
stubcc.call(STRICT_VARIANT(stubs::SetPropNoCache));
|
||||
}
|
||||
|
||||
typeCheck = stubcc.masm.jump();
|
||||
|
@ -3004,7 +3061,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::SetProp);
|
||||
}
|
||||
|
||||
|
@ -3084,7 +3141,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::Name);
|
||||
}
|
||||
|
||||
|
@ -3127,7 +3184,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::XName);
|
||||
}
|
||||
|
||||
|
@ -3169,7 +3226,7 @@ mjit::Compiler::jsop_bindname(uint32 index)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
passPICAddress(pic);
|
||||
pic.callReturn = stubcc.call(ic::BindName);
|
||||
}
|
||||
|
||||
|
@ -3876,7 +3933,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
|
|||
stubcc.linkExit(shapeGuard, Uses(0));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
|
||||
passMICAddress(mic);
|
||||
mic.stubEntry = stubcc.masm.label();
|
||||
mic.call = stubcc.call(ic::GetGlobalName);
|
||||
|
||||
|
@ -3975,7 +4032,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
|||
stubcc.linkExit(shapeGuard, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
|
||||
passMICAddress(mic);
|
||||
mic.stubEntry = stubcc.masm.label();
|
||||
mic.call = stubcc.call(ic::SetGlobalName);
|
||||
|
||||
|
@ -4226,7 +4283,7 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slowOne, Jump *sl
|
|||
if (slowTwo)
|
||||
slowTwo->linkTo(traceStart, &stubcc.masm);
|
||||
# if JS_MONOIC
|
||||
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
|
||||
passMICAddress(mic);
|
||||
# endif
|
||||
|
||||
/* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
|
||||
|
@ -4296,3 +4353,45 @@ mjit::Compiler::leaveBlock()
|
|||
frame.leaveBlock(n);
|
||||
}
|
||||
|
||||
// Creates the new object expected for constructors, and places it in |thisv|.
|
||||
// It is broken down into the following operations:
|
||||
// CALLEE
|
||||
// GETPROP "prototype"
|
||||
// IFPRIMTOP:
|
||||
// NULL
|
||||
// call js_CreateThisFromFunctionWithProto(...)
|
||||
//
|
||||
void
|
||||
mjit::Compiler::constructThis()
|
||||
{
|
||||
JS_ASSERT(isConstructing);
|
||||
|
||||
// Load the callee.
|
||||
Address callee(JSFrameReg, JSStackFrame::offsetOfCallee(fun));
|
||||
RegisterID calleeReg = frame.allocReg();
|
||||
masm.loadPayload(callee, calleeReg);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg);
|
||||
|
||||
// Get callee.prototype.
|
||||
jsop_getprop(cx->runtime->atomState.classPrototypeAtom);
|
||||
|
||||
// Reach into the proto Value and grab a register for its data.
|
||||
FrameEntry *protoFe = frame.peek(-1);
|
||||
RegisterID protoReg = frame.ownRegForData(protoFe);
|
||||
|
||||
// Now, get the type. If it's not an object, set protoReg to NULL.
|
||||
Jump isNotObject = frame.testObject(Assembler::NotEqual, protoFe);
|
||||
stubcc.linkExitDirect(isNotObject, stubcc.masm.label());
|
||||
stubcc.masm.move(ImmPtr(NULL), protoReg);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
|
||||
// Done with the protoFe.
|
||||
frame.pop();
|
||||
|
||||
prepareStubCall(Uses(0));
|
||||
if (protoReg != Registers::ArgReg1)
|
||||
masm.move(protoReg, Registers::ArgReg1);
|
||||
stubCall(stubs::CreateThis);
|
||||
frame.freeReg(protoReg);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ class Compiler : public BaseCompiler
|
|||
Label entry;
|
||||
Label stubEntry;
|
||||
DataLabel32 shape;
|
||||
DataLabelPtr addrLabel;
|
||||
#if defined JS_PUNBOX64
|
||||
uint32 patchValueOffset;
|
||||
#endif
|
||||
|
@ -114,6 +115,8 @@ class Compiler : public BaseCompiler
|
|||
Label slowJoinPoint;
|
||||
Label slowPathStart;
|
||||
Label hotPathLabel;
|
||||
DataLabelPtr addrLabel1;
|
||||
DataLabelPtr addrLabel2;
|
||||
Jump oolJump;
|
||||
RegisterID funObjReg;
|
||||
RegisterID funPtrReg;
|
||||
|
@ -143,6 +146,7 @@ class Compiler : public BaseCompiler
|
|||
Label storeBack;
|
||||
Label typeCheck;
|
||||
Label slowPathStart;
|
||||
DataLabelPtr addrLabel;
|
||||
RegisterID shapeReg;
|
||||
RegisterID objReg;
|
||||
RegisterID idReg;
|
||||
|
@ -196,10 +200,12 @@ class Compiler : public BaseCompiler
|
|||
bool ool;
|
||||
};
|
||||
|
||||
JSStackFrame *fp;
|
||||
JSScript *script;
|
||||
JSObject *scopeChain;
|
||||
JSObject *globalObj;
|
||||
JSFunction *fun;
|
||||
bool isConstructing;
|
||||
BytecodeAnalyzer analysis;
|
||||
Label *jumpMap;
|
||||
jsbytecode *PC;
|
||||
|
@ -211,7 +217,7 @@ class Compiler : public BaseCompiler
|
|||
js::Vector<CallGenInfo, 64> callICs;
|
||||
#endif
|
||||
#if defined JS_POLYIC
|
||||
js::Vector<PICGenInfo, 64> pics;
|
||||
js::Vector<PICGenInfo, 16> pics;
|
||||
#endif
|
||||
js::Vector<CallPatchInfo, 64> callPatches;
|
||||
js::Vector<InternalCallSite, 64> callSites;
|
||||
|
@ -226,10 +232,10 @@ class Compiler : public BaseCompiler
|
|||
// follows interpreter usage in JSOP_LENGTH.
|
||||
enum { LengthAtomIndex = uint32(-2) };
|
||||
|
||||
Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
|
||||
Compiler(JSContext *cx, JSStackFrame *fp);
|
||||
~Compiler();
|
||||
|
||||
CompileStatus Compile();
|
||||
CompileStatus compile();
|
||||
|
||||
jsbytecode *getPC() { return PC; }
|
||||
Label getLabel() { return masm.label(); }
|
||||
|
@ -238,10 +244,11 @@ class Compiler : public BaseCompiler
|
|||
void *findCallSite(const CallSite &callSite);
|
||||
|
||||
private:
|
||||
CompileStatus performCompilation(JITScript **jitp);
|
||||
CompileStatus generatePrologue();
|
||||
CompileStatus generateMethod();
|
||||
CompileStatus generateEpilogue();
|
||||
CompileStatus finishThisUp();
|
||||
CompileStatus finishThisUp(JITScript **jitp);
|
||||
|
||||
/* Non-emitting helpers. */
|
||||
uint32 fullAtomIndex(jsbytecode *pc);
|
||||
|
@ -257,6 +264,9 @@ class Compiler : public BaseCompiler
|
|||
void iterMore();
|
||||
void iterEnd();
|
||||
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
|
||||
void passPICAddress(PICGenInfo &pic);
|
||||
void passMICAddress(MICGenInfo &mic);
|
||||
void constructThis();
|
||||
|
||||
/* Opcode handlers. */
|
||||
void jumpAndTrace(Jump j, jsbytecode *target, Jump *slowOne = NULL, Jump *slowTwo = NULL);
|
||||
|
@ -268,12 +278,13 @@ class Compiler : public BaseCompiler
|
|||
void jsop_this();
|
||||
void emitReturn(FrameEntry *fe);
|
||||
void emitFinalReturn(Assembler &masm);
|
||||
void loadReturnValue(Assembler &masm);
|
||||
void loadReturnValue(Assembler *masm, FrameEntry *fe);
|
||||
void emitReturnValue(Assembler *masm, FrameEntry *fe);
|
||||
void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
|
||||
void interruptCheckHelper();
|
||||
void emitUncachedCall(uint32 argc, bool callingNew);
|
||||
void emitPrimitiveTestForNew(uint32 argc);
|
||||
void inlineCallHelper(uint32 argc, bool callingNew);
|
||||
void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
|
||||
void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
|
||||
void jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
|
||||
void jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
|
||||
|
|
|
@ -327,7 +327,7 @@ FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FrameState::storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg, RegisterID tempReg)
|
||||
void FrameState::loadTo(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
|
||||
{
|
||||
JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
|
||||
|
||||
|
@ -347,6 +347,15 @@ void FrameState::storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_PUNBOX64
|
||||
// If the value is synced, and requires at least one load, we can do
|
||||
// better on x64.
|
||||
if (fe->type.inMemory() && fe->data.inMemory()) {
|
||||
masm.loadValueAsComponents(addressOf(fe), typeReg, dataReg);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
RegisterID data = tempRegForData(fe);
|
||||
RegisterID type = tempRegForType(fe);
|
||||
if (data == typeReg && type == dataReg) {
|
||||
|
@ -893,6 +902,14 @@ FrameState::ownRegForData(FrameEntry *fe)
|
|||
return reg;
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::discardFe(FrameEntry *fe)
|
||||
{
|
||||
forgetEntry(fe);
|
||||
fe->type.setMemory();
|
||||
fe->data.setMemory();
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::pushCopyOf(uint32 index)
|
||||
{
|
||||
|
|
|
@ -590,7 +590,7 @@ class FrameState
|
|||
* 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);
|
||||
void loadTo(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
|
||||
|
||||
/*
|
||||
* Stores the top stack slot back to a slot.
|
||||
|
@ -654,6 +654,11 @@ class FrameState
|
|||
*/
|
||||
inline void forgetType(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Discards a FrameEntry, tricking the FS into thinking it's synced.
|
||||
*/
|
||||
void discardFe(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Helper function. Tests if a slot's type is null. Condition should
|
||||
* be Equal or NotEqual.
|
||||
|
|
|
@ -219,29 +219,6 @@ InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame)
|
|||
return ok;
|
||||
}
|
||||
|
||||
JSBool JS_FASTCALL
|
||||
stubs::NewObject(VMFrame &f, uint32 argc)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
Value *vp = f.regs.sp - (argc + 2);
|
||||
|
||||
JSObject *funobj = &vp[0].toObject();
|
||||
JS_ASSERT(funobj->isFunction());
|
||||
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
|
||||
if (!funobj->getProperty(cx, id, &vp[1]))
|
||||
THROWV(JS_FALSE);
|
||||
|
||||
JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent());
|
||||
if (!obj)
|
||||
THROWV(JS_FALSE);
|
||||
|
||||
vp[1].setObject(*obj);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::SlowCall(VMFrame &f, uint32 argc)
|
||||
{
|
||||
|
@ -361,8 +338,8 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
fp->initCallFrameEarlyPrologue(fun, fp->nativeReturnAddress());
|
||||
|
||||
/* Empty script does nothing. */
|
||||
bool callingNew = fp->isConstructing();
|
||||
if (script->isEmpty()) {
|
||||
bool callingNew = fp->isConstructing();
|
||||
RemovePartialFrame(cx, fp);
|
||||
Value *vp = f.regs.sp - (nactual + 2);
|
||||
if (callingNew)
|
||||
|
@ -389,9 +366,9 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
|||
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
||||
THROWV(NULL);
|
||||
|
||||
CompileStatus status = CanMethodJIT(cx, script, fun, &fp->scopeChain());
|
||||
CompileStatus status = CanMethodJIT(cx, script, fp);
|
||||
if (status == Compile_Okay)
|
||||
return script->jit->invoke;
|
||||
return script->getJIT(callingNew)->invokeEntry;
|
||||
|
||||
/* Function did not compile... interpret it. */
|
||||
JSBool ok = Interpret(cx, fp);
|
||||
|
@ -441,8 +418,8 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
}
|
||||
|
||||
/* Try to compile if not already compiled. */
|
||||
if (!newscript->ncode) {
|
||||
if (mjit::TryCompile(cx, newscript, newfp->fun(), &newfp->scopeChain()) == Compile_Error) {
|
||||
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
|
||||
if (mjit::TryCompile(cx, newfp) == Compile_Error) {
|
||||
/* A runtime exception was thrown, get out. */
|
||||
InlineReturn(f, JS_FALSE);
|
||||
return false;
|
||||
|
@ -450,9 +427,8 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|||
}
|
||||
|
||||
/* If newscript was successfully compiled, run it. */
|
||||
JS_ASSERT(newscript->ncode);
|
||||
if (newscript->ncode != JS_UNJITTABLE_METHOD) {
|
||||
*pret = newscript->jit->invoke;
|
||||
if (JITScript *jit = newscript->getJIT(newfp->isConstructing())) {
|
||||
*pret = jit->invokeEntry;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -484,9 +460,6 @@ stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
|||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted() &&
|
||||
!ucr->fun->script()->isEmpty())
|
||||
{
|
||||
if (!stubs::NewObject(f, argc))
|
||||
return;
|
||||
|
||||
ucr->callee = &vp->toObject();
|
||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, argc))
|
||||
THROW();
|
||||
|
@ -612,7 +585,10 @@ js_InternalThrow(VMFrame &f)
|
|||
if (!pc)
|
||||
return NULL;
|
||||
|
||||
return cx->fp()->script()->pcToNative(pc);
|
||||
JSStackFrame *fp = cx->fp();
|
||||
JSScript *script = fp->script();
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
return jit->nmap[pc - script->code];
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
|
@ -623,6 +599,18 @@ stubs::GetCallObject(VMFrame &f)
|
|||
THROW();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::CreateThis(VMFrame &f, JSObject *proto)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = f.fp();
|
||||
JSObject *callee = &fp->callee();
|
||||
JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
|
||||
if (!obj)
|
||||
THROW();
|
||||
fp->formalArgs()[-1].setObject(*obj);
|
||||
}
|
||||
|
||||
static inline void
|
||||
AdvanceReturnPC(JSContext *cx)
|
||||
{
|
||||
|
@ -696,11 +684,12 @@ AtSafePoint(JSContext *cx)
|
|||
return false;
|
||||
|
||||
JSScript *script = fp->script();
|
||||
if (!script->nmap)
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
if (!jit->nmap)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(cx->regs->pc >= script->code && cx->regs->pc < script->code + script->length);
|
||||
return !!script->nmap[cx->regs->pc - script->code];
|
||||
return !!jit->nmap[cx->regs->pc - script->code];
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
|
@ -709,8 +698,11 @@ PartialInterpret(VMFrame &f)
|
|||
JSContext *cx = f.cx;
|
||||
JSStackFrame *fp = cx->fp();
|
||||
|
||||
JS_ASSERT(fp->hasImacropc() || !fp->script()->nmap ||
|
||||
!fp->script()->nmap[cx->regs->pc - fp->script()->code]);
|
||||
#ifdef DEBUG
|
||||
JITScript *jit = fp->script()->getJIT(fp->isConstructing());
|
||||
JS_ASSERT(fp->hasImacropc() || !jit->nmap ||
|
||||
!jit->nmap[cx->regs->pc - fp->script()->code]);
|
||||
#endif
|
||||
|
||||
JSBool ok = JS_TRUE;
|
||||
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
|
||||
|
@ -740,7 +732,8 @@ FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
|||
|
||||
if (AtSafePoint(cx)) {
|
||||
JSScript *script = fp->script();
|
||||
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
if (!JaegerShotAtSafePoint(cx, jit->nmap[cx->regs->pc - script->code])) {
|
||||
if (!HandleErrorInExcessFrames(f, entryFrame))
|
||||
return false;
|
||||
|
||||
|
@ -894,9 +887,10 @@ RunTracer(VMFrame &f)
|
|||
|
||||
/* Step 2. If entryFrame is at a safe point, just leave. */
|
||||
if (AtSafePoint(cx)) {
|
||||
JITScript *jit = entryFrame->script()->getJIT(entryFrame->isConstructing());
|
||||
uint32 offs = uint32(cx->regs->pc - entryFrame->script()->code);
|
||||
JS_ASSERT(entryFrame->script()->nmap[offs]);
|
||||
return entryFrame->script()->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
|
||||
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
|
||||
|
@ -930,14 +924,10 @@ RunTracer(VMFrame &f)
|
|||
#if defined JS_TRACER
|
||||
# if defined JS_MONOIC
|
||||
void *JS_FASTCALL
|
||||
stubs::InvokeTracer(VMFrame &f, uint32 index)
|
||||
stubs::InvokeTracer(VMFrame &f, ic::MICInfo *mic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::MICInfo &mic = script->mics[index];
|
||||
|
||||
JS_ASSERT(mic.kind == ic::MICInfo::TRACER);
|
||||
|
||||
return RunTracer(f, mic);
|
||||
JS_ASSERT(mic->kind == ic::MICInfo::TRACER);
|
||||
return RunTracer(f, *mic);
|
||||
}
|
||||
|
||||
# else
|
||||
|
|
|
@ -764,9 +764,9 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code)
|
|||
JSBool
|
||||
mjit::JaegerShot(JSContext *cx)
|
||||
{
|
||||
JSScript *script = cx->fp()->script();
|
||||
|
||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||
JSStackFrame *fp = cx->fp();
|
||||
JSScript *script = fp->script();
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
|
||||
#ifdef JS_TRACER
|
||||
if (TRACE_RECORDER(cx))
|
||||
|
@ -775,7 +775,7 @@ mjit::JaegerShot(JSContext *cx)
|
|||
|
||||
JS_ASSERT(cx->regs->pc == script->code);
|
||||
|
||||
return EnterMethodJIT(cx, cx->fp(), script->jit->invoke);
|
||||
return EnterMethodJIT(cx, cx->fp(), jit->invokeEntry);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -795,37 +795,47 @@ static inline void Destroy(T &t)
|
|||
}
|
||||
|
||||
void
|
||||
mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
mjit::JITScript::release()
|
||||
{
|
||||
if (script->jit) {
|
||||
#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64)
|
||||
memset(script->jit->invoke, 0xcc, script->jit->inlineLength +
|
||||
script->jit->outOfLineLength);
|
||||
void *addr = code.m_code.executableAddress();
|
||||
memset(addr, 0xcc, code.m_size);
|
||||
#endif
|
||||
script->jit->execPool->release();
|
||||
script->jit->execPool = NULL;
|
||||
|
||||
// Releasing the execPool takes care of releasing the code.
|
||||
script->ncode = NULL;
|
||||
code.m_executablePool->release();
|
||||
|
||||
#if defined JS_POLYIC
|
||||
for (uint32 i = 0; i < script->jit->nPICs; i++) {
|
||||
script->pics[i].releasePools();
|
||||
Destroy(script->pics[i].execPools);
|
||||
}
|
||||
for (uint32 i = 0; i < nPICs; i++) {
|
||||
pics[i].releasePools();
|
||||
Destroy(pics[i].execPools);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined JS_MONOIC
|
||||
for (uint32 i = 0; i < script->jit->nCallICs; i++)
|
||||
script->callICs[i].releasePools();
|
||||
for (uint32 i = 0; i < nCallICs; i++)
|
||||
callICs[i].releasePools();
|
||||
#endif
|
||||
}
|
||||
|
||||
cx->free(script->jit);
|
||||
void
|
||||
mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
{
|
||||
// NB: The recompiler may call ReleaseScriptCode, in which case it
|
||||
// will get called again when the script is destroyed, so we
|
||||
// must protect against calling ReleaseScriptCode twice.
|
||||
|
||||
// The recompiler may call ReleaseScriptCode, in which case it
|
||||
// will get called again when the script is destroyed, so we
|
||||
// must protect against calling ReleaseScriptCode twice.
|
||||
script->jit = NULL;
|
||||
if (script->jitNormal) {
|
||||
script->jitNormal->release();
|
||||
script->jitArityCheckNormal = NULL;
|
||||
cx->free(script->jitNormal);
|
||||
script->jitNormal = NULL;
|
||||
}
|
||||
|
||||
if (script->jitCtor) {
|
||||
script->jitCtor->release();
|
||||
script->jitArityCheckCtor = NULL;
|
||||
cx->free(script->jitCtor);
|
||||
script->jitCtor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,18 @@ struct VMFrame
|
|||
extern "C" void JaegerStubVeneer(void);
|
||||
#endif
|
||||
|
||||
namespace mjit {
|
||||
namespace ic {
|
||||
# if defined JS_POLYIC
|
||||
struct PICInfo;
|
||||
# endif
|
||||
# if defined JS_MONOIC
|
||||
struct MICInfo;
|
||||
struct CallICInfo;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (JS_FASTCALL *VoidStub)(VMFrame &);
|
||||
typedef void (JS_FASTCALL *VoidVpStub)(VMFrame &, Value *);
|
||||
typedef void (JS_FASTCALL *VoidStubUInt32)(VMFrame &, uint32);
|
||||
|
@ -158,26 +170,47 @@ typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32);
|
|||
typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *);
|
||||
typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
|
||||
typedef JSBool (JS_FASTCALL *BoolStubUInt32)(VMFrame &f, uint32);
|
||||
|
||||
#define JS_UNJITTABLE_METHOD (reinterpret_cast<void*>(1))
|
||||
typedef void (JS_FASTCALL *VoidStubMIC)(VMFrame &, js::mjit::ic::MICInfo *);
|
||||
typedef void * (JS_FASTCALL *VoidPtrStubMIC)(VMFrame &, js::mjit::ic::MICInfo *);
|
||||
typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *);
|
||||
typedef void (JS_FASTCALL *VoidStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
|
||||
typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
|
||||
|
||||
namespace mjit {
|
||||
|
||||
struct CallSite;
|
||||
|
||||
struct JITScript {
|
||||
JSC::ExecutablePool *execPool; /* pool that contains |ncode|; script owns the pool */
|
||||
uint32 inlineLength; /* length of inline JIT'd code */
|
||||
uint32 outOfLineLength; /* length of out of line JIT'd code */
|
||||
typedef JSC::MacroAssemblerCodeRef CodeRef;
|
||||
CodeRef code; /* pool & code addresses */
|
||||
|
||||
js::mjit::CallSite *callSites;
|
||||
uint32 nCallSites;
|
||||
void **nmap; /* scripted pc to native code map. */
|
||||
#ifdef JS_MONOIC
|
||||
uint32 nMICs; /* number of MonoICs */
|
||||
uint32 nCallICs; /* number of call ICs */
|
||||
ic::MICInfo *mics; /* MICs in this script. */
|
||||
uint32 nMICs; /* number of MonoICs */
|
||||
ic::CallICInfo *callICs; /* CallICs in this script. */
|
||||
uint32 nCallICs; /* number of call ICs */
|
||||
#endif
|
||||
#ifdef JS_POLYIC
|
||||
uint32 nPICs; /* number of PolyICs */
|
||||
ic::PICInfo *pics; /* PICs in this script */
|
||||
uint32 nPICs; /* number of PolyICs */
|
||||
#endif
|
||||
void *invoke; /* invoke address */
|
||||
void *arityCheck; /* arity check address */
|
||||
void *invokeEntry; /* invoke address */
|
||||
void *fastEntry; /* cached entry, fastest */
|
||||
void *arityCheckEntry; /* arity check address */
|
||||
|
||||
bool isValidCode(void *ptr) {
|
||||
char *jitcode = (char *)code.m_code.executableAddress();
|
||||
char *jcheck = (char *)ptr;
|
||||
return jcheck >= jitcode && jcheck < jitcode + code.m_size;
|
||||
}
|
||||
|
||||
void sweepCallICs();
|
||||
void purgeMICs();
|
||||
void purgePICs();
|
||||
void release();
|
||||
};
|
||||
|
||||
/* Execute a method that has been JIT compiled. */
|
||||
|
@ -197,18 +230,21 @@ void JS_FASTCALL
|
|||
ProfileStubCall(VMFrame &f);
|
||||
|
||||
CompileStatus JS_NEVER_INLINE
|
||||
TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
|
||||
TryCompile(JSContext *cx, JSStackFrame *fp);
|
||||
|
||||
void
|
||||
ReleaseScriptCode(JSContext *cx, JSScript *script);
|
||||
|
||||
static inline CompileStatus
|
||||
CanMethodJIT(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
|
||||
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp)
|
||||
{
|
||||
if (!cx->methodJitEnabled || script->ncode == JS_UNJITTABLE_METHOD)
|
||||
if (!cx->methodJitEnabled)
|
||||
return Compile_Abort;
|
||||
if (script->ncode == NULL)
|
||||
return TryCompile(cx, script, fun, scopeChain);
|
||||
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
|
||||
if (status == JITScript_Invalid)
|
||||
return Compile_Abort;
|
||||
if (status == JITScript_None)
|
||||
return TryCompile(cx, fp);
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
|
@ -223,6 +259,25 @@ struct CallSite
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
inline void **
|
||||
JSScript::maybeNativeMap(bool constructing)
|
||||
{
|
||||
js::mjit::JITScript *jit = constructing ? jitCtor : jitNormal;
|
||||
if (!jit)
|
||||
return NULL;
|
||||
return jit->nmap;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::hasNativeCodeForPC(bool constructing, jsbytecode *pc)
|
||||
{
|
||||
js::mjit::JITScript *jit = getJIT(constructing);
|
||||
if (!jit)
|
||||
return false;
|
||||
JS_ASSERT(pc >= code && pc < code + length);
|
||||
return !!jit->nmap[pc - code];
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame);
|
||||
#else
|
||||
|
|
|
@ -70,22 +70,21 @@ typedef JSC::MacroAssembler::Call Call;
|
|||
#if defined JS_MONOIC
|
||||
|
||||
static void
|
||||
PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
|
||||
PatchGetFallback(VMFrame &f, ic::MICInfo *ic)
|
||||
{
|
||||
JSC::RepatchBuffer repatch(mic.stubEntry.executableAddress(), 64);
|
||||
JSC::RepatchBuffer repatch(ic->stubEntry.executableAddress(), 64);
|
||||
JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::GetGlobalName));
|
||||
repatch.relink(mic.stubCall, fptr);
|
||||
repatch.relink(ic->stubCall, fptr);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetGlobalName(VMFrame &f, uint32 index)
|
||||
ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
|
||||
{
|
||||
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||
ic::MICInfo &mic = f.fp()->script()->mics[index];
|
||||
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
JS_ASSERT(mic.kind == ic::MICInfo::GET);
|
||||
JS_ASSERT(ic->kind == ic::MICInfo::GET);
|
||||
|
||||
JS_LOCK_OBJ(f.cx, obj);
|
||||
const Shape *shape = obj->nativeLookup(id);
|
||||
|
@ -95,33 +94,33 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
|
|||
{
|
||||
JS_UNLOCK_OBJ(f.cx, obj);
|
||||
if (shape)
|
||||
PatchGetFallback(f, mic);
|
||||
PatchGetFallback(f, ic);
|
||||
stubs::GetGlobalName(f);
|
||||
return;
|
||||
}
|
||||
uint32 slot = shape->slot;
|
||||
JS_UNLOCK_OBJ(f.cx, obj);
|
||||
|
||||
mic.u.name.touched = true;
|
||||
ic->u.name.touched = true;
|
||||
|
||||
/* Patch shape guard. */
|
||||
JSC::RepatchBuffer repatch(mic.entry.executableAddress(), 50);
|
||||
repatch.repatch(mic.shape, obj->shape());
|
||||
JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
|
||||
repatch.repatch(ic->shape, obj->shape());
|
||||
|
||||
/* Patch loads. */
|
||||
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
|
||||
slot -= JS_INITIAL_NSLOTS;
|
||||
slot *= sizeof(Value);
|
||||
JSC::RepatchBuffer loads(mic.load.executableAddress(), 32, false);
|
||||
JSC::RepatchBuffer loads(ic->load.executableAddress(), 32, false);
|
||||
#if defined JS_CPU_X86
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
|
||||
loads.repatch(ic->load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
|
||||
loads.repatch(ic->load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
|
||||
#elif defined JS_CPU_ARM
|
||||
// mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// ic->load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// knows how to dereference it to find the integer value.
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(0), slot);
|
||||
loads.repatch(ic->load.dataLabel32AtOffset(0), slot);
|
||||
#elif defined JS_PUNBOX64
|
||||
loads.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
|
||||
loads.repatch(ic->load.dataLabel32AtOffset(ic->patchValueOffset), slot);
|
||||
#endif
|
||||
|
||||
/* Do load anyway... this time. */
|
||||
|
@ -140,11 +139,11 @@ SetGlobalNameSlow(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
static void
|
||||
PatchSetFallback(VMFrame &f, ic::MICInfo &mic)
|
||||
PatchSetFallback(VMFrame &f, ic::MICInfo *ic)
|
||||
{
|
||||
JSC::RepatchBuffer repatch(mic.stubEntry.executableAddress(), 64);
|
||||
JSC::RepatchBuffer repatch(ic->stubEntry.executableAddress(), 64);
|
||||
JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, SetGlobalNameSlow));
|
||||
repatch.relink(mic.stubCall, fptr);
|
||||
repatch.relink(ic->stubCall, fptr);
|
||||
}
|
||||
|
||||
static VoidStubAtom
|
||||
|
@ -159,14 +158,13 @@ GetStubForSetGlobalName(VMFrame &f)
|
|||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::SetGlobalName(VMFrame &f, uint32 index)
|
||||
ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
|
||||
{
|
||||
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||
ic::MICInfo &mic = f.fp()->script()->mics[index];
|
||||
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
JS_ASSERT(mic.kind == ic::MICInfo::SET);
|
||||
JS_ASSERT(ic->kind == ic::MICInfo::SET);
|
||||
|
||||
JS_LOCK_OBJ(f.cx, obj);
|
||||
const Shape *shape = obj->nativeLookup(id);
|
||||
|
@ -177,40 +175,40 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
|||
{
|
||||
JS_UNLOCK_OBJ(f.cx, obj);
|
||||
if (shape)
|
||||
PatchSetFallback(f, mic);
|
||||
PatchSetFallback(f, ic);
|
||||
GetStubForSetGlobalName(f)(f, atom);
|
||||
return;
|
||||
}
|
||||
uint32 slot = shape->slot;
|
||||
JS_UNLOCK_OBJ(f.cx, obj);
|
||||
|
||||
mic.u.name.touched = true;
|
||||
ic->u.name.touched = true;
|
||||
|
||||
/* Patch shape guard. */
|
||||
JSC::RepatchBuffer repatch(mic.entry.executableAddress(), 50);
|
||||
repatch.repatch(mic.shape, obj->shape());
|
||||
JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
|
||||
repatch.repatch(ic->shape, obj->shape());
|
||||
|
||||
/* Patch loads. */
|
||||
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
|
||||
slot -= JS_INITIAL_NSLOTS;
|
||||
slot *= sizeof(Value);
|
||||
|
||||
JSC::RepatchBuffer stores(mic.load.executableAddress(), 32, false);
|
||||
JSC::RepatchBuffer stores(ic->load.executableAddress(), 32, false);
|
||||
#if defined JS_CPU_X86
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
|
||||
stores.repatch(ic->load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
|
||||
|
||||
uint32 dataOffset;
|
||||
if (mic.u.name.typeConst)
|
||||
if (ic->u.name.typeConst)
|
||||
dataOffset = MICInfo::SET_DATA_CONST_TYPE_OFFSET;
|
||||
else
|
||||
dataOffset = MICInfo::SET_DATA_TYPE_OFFSET;
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(dataOffset), slot);
|
||||
stores.repatch(ic->load.dataLabel32AtOffset(dataOffset), slot);
|
||||
#elif defined JS_CPU_ARM
|
||||
// mic.load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// ic->load actually points to the LDR instruction which fetches the offset, but 'repatch'
|
||||
// knows how to dereference it to find the integer value.
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(0), slot);
|
||||
stores.repatch(ic->load.dataLabel32AtOffset(0), slot);
|
||||
#elif defined JS_PUNBOX64
|
||||
stores.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
|
||||
stores.repatch(ic->load.dataLabel32AtOffset(ic->patchValueOffset), slot);
|
||||
#endif
|
||||
|
||||
// Actually implement the op the slow way.
|
||||
|
@ -218,24 +216,16 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
static void * JS_FASTCALL
|
||||
SlowCallFromIC(VMFrame &f, uint32 index)
|
||||
SlowCallFromIC(VMFrame &f, ic::CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic= oldscript->callICs[index];
|
||||
|
||||
stubs::SlowCall(f, ic.argc);
|
||||
|
||||
stubs::SlowCall(f, ic->argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void * JS_FASTCALL
|
||||
SlowNewFromIC(VMFrame &f, uint32 index)
|
||||
SlowNewFromIC(VMFrame &f, ic::CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic = oldscript->callICs[index];
|
||||
|
||||
stubs::SlowNew(f, ic.argc);
|
||||
|
||||
stubs::SlowNew(f, ic->argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -325,8 +315,11 @@ class CallCompiler : public BaseCompiler
|
|||
* here since ncode has two failure modes and we need to load out of
|
||||
* nmap anyway.
|
||||
*/
|
||||
masm.loadPtr(Address(t0, offsetof(JSScript, jit)), t0);
|
||||
Jump hasCode = masm.branchTestPtr(Assembler::NonZero, t0, t0);
|
||||
size_t offset = callingNew
|
||||
? offsetof(JSScript, jitArityCheckCtor)
|
||||
: offsetof(JSScript, jitArityCheckNormal);
|
||||
masm.loadPtr(Address(t0, offset), t0);
|
||||
Jump hasCode = masm.branchPtr(Assembler::Above, t0, ImmPtr(JS_UNJITTABLE_SCRIPT));
|
||||
|
||||
/* Try and compile. On success we get back the nmap pointer. */
|
||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||
|
@ -345,7 +338,6 @@ class CallCompiler : public BaseCompiler
|
|||
|
||||
/* Get nmap[ARITY], set argc, call. */
|
||||
masm.move(Imm32(ic.argc), JSParamReg_Argc);
|
||||
masm.loadPtr(Address(t0, offsetof(JITScript, arityCheck)), t0);
|
||||
masm.jump(t0);
|
||||
|
||||
JSC::ExecutablePool *ep = poolForSize(masm.size(), CallICInfo::Pool_ScriptStub);
|
||||
|
@ -377,9 +369,11 @@ class CallCompiler : public BaseCompiler
|
|||
|
||||
ic.fastGuardedObject = obj;
|
||||
|
||||
JITScript *jit = script->getJIT(callingNew);
|
||||
|
||||
repatch.repatch(ic.funGuard, obj);
|
||||
repatch.relink(ic.funGuard.jumpAtOffset(ic.hotJumpOffset),
|
||||
JSC::CodeLocationLabel(script->ncode));
|
||||
JSC::CodeLocationLabel(jit->fastEntry));
|
||||
|
||||
JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %p)\n", start, ic.fastGuardedObject);
|
||||
}
|
||||
|
@ -649,52 +643,40 @@ class CallCompiler : public BaseCompiler
|
|||
};
|
||||
|
||||
void * JS_FASTCALL
|
||||
ic::Call(VMFrame &f, uint32 index)
|
||||
ic::Call(VMFrame &f, CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic = oldscript->callICs[index];
|
||||
CallCompiler cc(f, ic, false);
|
||||
CallCompiler cc(f, *ic, false);
|
||||
return cc.update();
|
||||
}
|
||||
|
||||
void * JS_FASTCALL
|
||||
ic::New(VMFrame &f, uint32 index)
|
||||
ic::New(VMFrame &f, CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic = oldscript->callICs[index];
|
||||
CallCompiler cc(f, ic, true);
|
||||
CallCompiler cc(f, *ic, true);
|
||||
return cc.update();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::NativeCall(VMFrame &f, uint32 index)
|
||||
ic::NativeCall(VMFrame &f, CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic = oldscript->callICs[index];
|
||||
CallCompiler cc(f, ic, false);
|
||||
CallCompiler cc(f, *ic, false);
|
||||
if (!cc.generateNativeStub())
|
||||
stubs::SlowCall(f, ic.argc);
|
||||
stubs::SlowCall(f, ic->argc);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::NativeNew(VMFrame &f, uint32 index)
|
||||
ic::NativeNew(VMFrame &f, CallICInfo *ic)
|
||||
{
|
||||
JSScript *oldscript = f.fp()->script();
|
||||
CallICInfo &ic = oldscript->callICs[index];
|
||||
CallCompiler cc(f, ic, true);
|
||||
CallCompiler cc(f, *ic, true);
|
||||
if (!cc.generateNativeStub())
|
||||
stubs::SlowNew(f, ic.argc);
|
||||
stubs::SlowNew(f, ic->argc);
|
||||
}
|
||||
|
||||
void
|
||||
ic::PurgeMICs(JSContext *cx, JSScript *script)
|
||||
JITScript::purgeMICs()
|
||||
{
|
||||
/* MICs are purged during GC to handle changing shapes. */
|
||||
JS_ASSERT(cx->runtime->gcRegenShapes);
|
||||
|
||||
uint32 nmics = script->jit->nMICs;
|
||||
for (uint32 i = 0; i < nmics; i++) {
|
||||
ic::MICInfo &mic = script->mics[i];
|
||||
for (uint32 i = 0; i < nMICs; i++) {
|
||||
ic::MICInfo &mic = mics[i];
|
||||
switch (mic.kind) {
|
||||
case ic::MICInfo::SET:
|
||||
case ic::MICInfo::GET:
|
||||
|
@ -720,10 +702,22 @@ ic::PurgeMICs(JSContext *cx, JSScript *script)
|
|||
}
|
||||
|
||||
void
|
||||
ic::SweepCallICs(JSScript *script)
|
||||
ic::PurgeMICs(JSContext *cx, JSScript *script)
|
||||
{
|
||||
for (uint32 i = 0; i < script->jit->nCallICs; i++) {
|
||||
ic::CallICInfo &ic = script->callICs[i];
|
||||
/* MICs are purged during GC to handle changing shapes. */
|
||||
JS_ASSERT(cx->runtime->gcRegenShapes);
|
||||
|
||||
if (script->jitNormal)
|
||||
script->jitNormal->purgeMICs();
|
||||
if (script->jitCtor)
|
||||
script->jitCtor->purgeMICs();
|
||||
}
|
||||
|
||||
void
|
||||
JITScript::sweepCallICs()
|
||||
{
|
||||
for (uint32 i = 0; i < nCallICs; i++) {
|
||||
ic::CallICInfo &ic = callICs[i];
|
||||
|
||||
/*
|
||||
* If the object is unreachable, we're guaranteed not to be currently
|
||||
|
@ -757,5 +751,14 @@ ic::SweepCallICs(JSScript *script)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ic::SweepCallICs(JSScript *script)
|
||||
{
|
||||
if (script->jitNormal)
|
||||
script->jitNormal->sweepCallICs();
|
||||
if (script->jitCtor)
|
||||
script->jitCtor->sweepCallICs();
|
||||
}
|
||||
|
||||
#endif /* JS_MONOIC */
|
||||
|
||||
|
|
|
@ -109,8 +109,8 @@ struct MICInfo {
|
|||
} u;
|
||||
};
|
||||
|
||||
void JS_FASTCALL GetGlobalName(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL SetGlobalName(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL GetGlobalName(VMFrame &f, ic::MICInfo *ic);
|
||||
void JS_FASTCALL SetGlobalName(VMFrame &f, ic::MICInfo *ic);
|
||||
|
||||
/* See MonoIC.cpp, CallCompiler for more information on call ICs. */
|
||||
struct CallICInfo {
|
||||
|
@ -187,10 +187,10 @@ struct CallICInfo {
|
|||
}
|
||||
};
|
||||
|
||||
void * JS_FASTCALL New(VMFrame &f, uint32 index);
|
||||
void * JS_FASTCALL Call(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL NativeNew(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL NativeCall(VMFrame &f, uint32 index);
|
||||
void * JS_FASTCALL New(VMFrame &f, ic::CallICInfo *ic);
|
||||
void * JS_FASTCALL Call(VMFrame &f, ic::CallICInfo *ic);
|
||||
void JS_FASTCALL NativeNew(VMFrame &f, ic::CallICInfo *ic);
|
||||
void JS_FASTCALL NativeCall(VMFrame &f, ic::CallICInfo *ic);
|
||||
|
||||
void PurgeMICs(JSContext *cx, JSScript *script);
|
||||
void SweepCallICs(JSScript *script);
|
||||
|
|
|
@ -111,8 +111,7 @@ class PICStubCompiler : public BaseCompiler
|
|||
return disable(reason, JS_FUNC_TO_DATA_PTR(void *, stub));
|
||||
}
|
||||
|
||||
bool disable(const char *reason, VoidStubUInt32 stub)
|
||||
{
|
||||
bool disable(const char *reason, VoidStubPIC stub) {
|
||||
return disable(reason, JS_FUNC_TO_DATA_PTR(void *, stub));
|
||||
}
|
||||
|
||||
|
@ -159,7 +158,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
{
|
||||
JSObject *obj;
|
||||
JSAtom *atom;
|
||||
VoidStubUInt32 stub;
|
||||
VoidStubPIC stub;
|
||||
int lastStubSecondShapeGuard;
|
||||
|
||||
static int32 dslotsLoadOffset(ic::PICInfo &pic) {
|
||||
|
@ -224,7 +223,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
|
||||
public:
|
||||
SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
|
||||
VoidStubUInt32 stub)
|
||||
VoidStubPIC stub)
|
||||
: PICStubCompiler("setprop", f, script, pic), obj(obj), atom(atom), stub(stub),
|
||||
lastStubSecondShapeGuard(pic.secondShapeGuard)
|
||||
{ }
|
||||
|
@ -746,7 +745,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
{ }
|
||||
|
||||
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
|
||||
VoidStubUInt32 stub)
|
||||
VoidStubPIC stub)
|
||||
: PICStubCompiler("callprop", f, script, pic), obj(obj), atom(atom),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
|
||||
lastStubSecondShapeGuard(pic.secondShapeGuard)
|
||||
|
@ -770,7 +769,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
RepatchBuffer repatcher2(pic.slowPathStart.executableAddress(), INLINE_PATH_LENGTH);
|
||||
ReturnAddressPtr retPtr(pic.slowPathStart.callAtOffset(pic.callReturn).executableAddress());
|
||||
|
||||
VoidStubUInt32 stub;
|
||||
VoidStubPIC stub;
|
||||
switch (pic.kind) {
|
||||
case ic::PICInfo::GET:
|
||||
stub = ic::GetProp;
|
||||
|
@ -1573,7 +1572,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
|
||||
public:
|
||||
ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
|
||||
JSAtom *atom, VoidStubUInt32 stub)
|
||||
JSAtom *atom, VoidStubPIC stub)
|
||||
: PICStubCompiler("name", f, script, pic), scopeChain(scopeChain), atom(atom),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub)), obj(NULL), holder(NULL), prop(NULL)
|
||||
{ }
|
||||
|
@ -1591,7 +1590,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
|
||||
RepatchBuffer repatcher2(pic.slowPathStart.executableAddress(), INLINE_PATH_LENGTH);
|
||||
ReturnAddressPtr retPtr(pic.slowPathStart.callAtOffset(pic.callReturn).executableAddress());
|
||||
VoidStubUInt32 stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
|
||||
VoidStubPIC stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
|
||||
MacroAssemblerCodePtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
|
||||
repatcher.relinkCallerToTrampoline(retPtr, target);
|
||||
}
|
||||
|
@ -1912,7 +1911,7 @@ class BindNameCompiler : public PICStubCompiler
|
|||
|
||||
public:
|
||||
BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
|
||||
JSAtom *atom, VoidStubUInt32 stub)
|
||||
JSAtom *atom, VoidStubPIC stub)
|
||||
: PICStubCompiler("bind", f, script, pic), scopeChain(scopeChain), atom(atom),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub))
|
||||
{ }
|
||||
|
@ -2020,15 +2019,14 @@ class BindNameCompiler : public PICStubCompiler
|
|||
};
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetProp(VMFrame &f, uint32 index)
|
||||
ic::GetProp(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
PICInfo &pic = script->pics[index];
|
||||
|
||||
JSAtom *atom = pic.atom;
|
||||
JSAtom *atom = pic->atom;
|
||||
if (atom == f.cx->runtime->atomState.lengthAtom) {
|
||||
if (f.regs.sp[-1].isString()) {
|
||||
GetPropCompiler cc(f, script, NULL, pic, NULL, stubs::Length);
|
||||
GetPropCompiler cc(f, script, NULL, *pic, NULL, stubs::Length);
|
||||
if (!cc.generateStringLengthStub()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
|
@ -2039,7 +2037,7 @@ ic::GetProp(VMFrame &f, uint32 index)
|
|||
} 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, stubs::Length);
|
||||
GetPropCompiler cc(f, script, obj, *pic, NULL, stubs::Length);
|
||||
if (obj->isArray()) {
|
||||
if (!cc.generateArrayLengthStub()) {
|
||||
cc.disable("error");
|
||||
|
@ -2063,8 +2061,8 @@ ic::GetProp(VMFrame &f, uint32 index)
|
|||
if (!obj)
|
||||
THROW();
|
||||
|
||||
if (pic.shouldGenerate()) {
|
||||
GetPropCompiler cc(f, script, obj, pic, atom, stubs::GetProp);
|
||||
if (pic->shouldGenerate()) {
|
||||
GetPropCompiler cc(f, script, obj, *pic, atom, stubs::GetProp);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
|
@ -2078,10 +2076,9 @@ ic::GetProp(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetElem(VMFrame &f, uint32 picIndex)
|
||||
ic::GetElem(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
PICInfo &pic = script->pics[picIndex];
|
||||
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||
if (!obj)
|
||||
|
@ -2090,8 +2087,8 @@ ic::GetElem(VMFrame &f, uint32 picIndex)
|
|||
Value idval = f.regs.sp[-1];
|
||||
JS_ASSERT(idval.isString());
|
||||
JSString *id = idval.toString();
|
||||
if (pic.shouldGenerate()) {
|
||||
GetElemCompiler cc(f, script, obj, pic, id, stubs::GetElem);
|
||||
if (pic->shouldGenerate()) {
|
||||
GetElemCompiler cc(f, script, obj, *pic, id, stubs::GetElem);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
|
@ -2107,46 +2104,29 @@ ic::GetElem(VMFrame &f, uint32 picIndex)
|
|||
f.regs.sp[-2] = v;
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::SetPropDumb(VMFrame &f, uint32 index)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JS_ASSERT(pic.isSet());
|
||||
JSAtom *atom = pic.atom;
|
||||
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||
if (!obj)
|
||||
THROW();
|
||||
Value rval = f.regs.sp[-1];
|
||||
if (!obj->setProperty(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1],
|
||||
script->strictModeCode))
|
||||
THROW();
|
||||
f.regs.sp[-2] = rval;
|
||||
}
|
||||
|
||||
template <JSBool strict>
|
||||
static void JS_FASTCALL
|
||||
SetPropSlow(VMFrame &f, uint32 index)
|
||||
SetPropDumb(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JS_ASSERT(pic.isSet());
|
||||
stubs::SetPropNoCache<strict>(f, pic->atom);
|
||||
}
|
||||
|
||||
JSAtom *atom = pic.atom;
|
||||
STRICT_VARIANT(stubs::SetName)(f, atom);
|
||||
template <JSBool strict>
|
||||
static void JS_FASTCALL
|
||||
SetPropSlow(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::SetName<strict>(f, pic->atom);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::SetProp(VMFrame &f, uint32 index)
|
||||
ic::SetProp(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||
if (!obj)
|
||||
THROW();
|
||||
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JSAtom *atom = pic.atom;
|
||||
JS_ASSERT(pic.isSet());
|
||||
JS_ASSERT(pic->isSet());
|
||||
|
||||
//
|
||||
// Important: We update the PIC before looking up the property so that the
|
||||
|
@ -2157,7 +2137,7 @@ ic::SetProp(VMFrame &f, uint32 index)
|
|||
// cache can't handle a GET and SET from the same scripted PC.
|
||||
//
|
||||
|
||||
VoidStubUInt32 stub;
|
||||
VoidStubPIC stub;
|
||||
switch (JSOp(*f.regs.pc)) {
|
||||
case JSOP_PROPINC:
|
||||
case JSOP_PROPDEC:
|
||||
|
@ -2167,40 +2147,36 @@ ic::SetProp(VMFrame &f, uint32 index)
|
|||
case JSOP_NAMEDEC:
|
||||
case JSOP_INCNAME:
|
||||
case JSOP_DECNAME:
|
||||
stub = SetPropDumb;
|
||||
stub = STRICT_VARIANT(SetPropDumb);
|
||||
break;
|
||||
default:
|
||||
stub = SetPropSlow;
|
||||
stub = STRICT_VARIANT(SetPropSlow);
|
||||
break;
|
||||
}
|
||||
|
||||
SetPropCompiler cc(f, script, obj, pic, atom, stub);
|
||||
SetPropCompiler cc(f, script, obj, *pic, pic->atom, stub);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
}
|
||||
|
||||
Value rval = f.regs.sp[-1];
|
||||
stub(f, index);
|
||||
stub(f, pic);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
CallPropSlow(VMFrame &f, uint32 index)
|
||||
CallPropSlow(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
stubs::CallProp(f, pic.atom);
|
||||
stubs::CallProp(f, pic->atom);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::CallProp(VMFrame &f, uint32 index)
|
||||
ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSFrameRegs ®s = f.regs;
|
||||
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JSAtom *origAtom = pic.atom;
|
||||
|
||||
Value lval;
|
||||
lval = regs.sp[-1];
|
||||
|
@ -2260,7 +2236,7 @@ ic::CallProp(VMFrame &f, uint32 index)
|
|||
* PropertyCache::test.
|
||||
*/
|
||||
jsid id;
|
||||
id = ATOM_TO_JSID(origAtom);
|
||||
id = ATOM_TO_JSID(pic->atom);
|
||||
|
||||
regs.sp++;
|
||||
regs.sp[-1].setNull();
|
||||
|
@ -2298,7 +2274,7 @@ ic::CallProp(VMFrame &f, uint32 index)
|
|||
}
|
||||
}
|
||||
|
||||
GetPropCompiler cc(f, script, &objv.toObject(), pic, origAtom, CallPropSlow);
|
||||
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, CallPropSlow);
|
||||
if (usePIC) {
|
||||
if (lval.isObject()) {
|
||||
if (!cc.update()) {
|
||||
|
@ -2319,7 +2295,7 @@ ic::CallProp(VMFrame &f, uint32 index)
|
|||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (JS_UNLIKELY(rval.isUndefined())) {
|
||||
regs.sp[-2].setString(ATOM_TO_STRING(origAtom));
|
||||
regs.sp[-2].setString(ATOM_TO_STRING(pic->atom));
|
||||
if (!js_OnUnknownMethod(cx, regs.sp - 2))
|
||||
THROW();
|
||||
}
|
||||
|
@ -2327,28 +2303,26 @@ ic::CallProp(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
SlowName(VMFrame &f, uint32 index)
|
||||
SlowName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::Name(f);
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
SlowXName(VMFrame &f, uint32 index)
|
||||
SlowXName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::GetProp(f);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::XName(VMFrame &f, uint32 index)
|
||||
ic::XName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JSAtom *atom = pic.atom;
|
||||
|
||||
/* GETXPROP is guaranteed to have an object. */
|
||||
JSObject *obj = &f.regs.sp[-1].toObject();
|
||||
|
||||
ScopeNameCompiler cc(f, script, obj, pic, atom, SlowXName);
|
||||
ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, SlowXName);
|
||||
|
||||
if (!cc.updateForXName()) {
|
||||
cc.disable("error");
|
||||
|
@ -2362,13 +2336,11 @@ ic::XName(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::Name(VMFrame &f, uint32 index)
|
||||
ic::Name(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JSAtom *atom = pic.atom;
|
||||
|
||||
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowName);
|
||||
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowName);
|
||||
|
||||
if (!cc.updateForName()) {
|
||||
cc.disable("error");
|
||||
|
@ -2382,19 +2354,17 @@ ic::Name(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
SlowBindName(VMFrame &f, uint32 index)
|
||||
SlowBindName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
stubs::BindName(f);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::BindName(VMFrame &f, uint32 index)
|
||||
ic::BindName(VMFrame &f, ic::PICInfo *pic)
|
||||
{
|
||||
JSScript *script = f.fp()->script();
|
||||
ic::PICInfo &pic = script->pics[index];
|
||||
JSAtom *atom = pic.atom;
|
||||
|
||||
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowBindName);
|
||||
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowBindName);
|
||||
|
||||
JSObject *obj = cc.update();
|
||||
if (!obj) {
|
||||
|
@ -2406,11 +2376,10 @@ ic::BindName(VMFrame &f, uint32 index)
|
|||
}
|
||||
|
||||
void
|
||||
ic::PurgePICs(JSContext *cx, JSScript *script)
|
||||
JITScript::purgePICs()
|
||||
{
|
||||
uint32 npics = script->jit->nPICs;
|
||||
for (uint32 i = 0; i < npics; i++) {
|
||||
ic::PICInfo &pic = script->pics[i];
|
||||
for (uint32 i = 0; i < nPICs; i++) {
|
||||
ic::PICInfo &pic = pics[i];
|
||||
switch (pic.kind) {
|
||||
case ic::PICInfo::SET:
|
||||
case ic::PICInfo::SETMETHOD:
|
||||
|
@ -2438,5 +2407,14 @@ ic::PurgePICs(JSContext *cx, JSScript *script)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ic::PurgePICs(JSContext *cx, JSScript *script)
|
||||
{
|
||||
if (script->jitNormal)
|
||||
script->jitNormal->purgePICs();
|
||||
if (script->jitCtor)
|
||||
script->jitCtor->purgePICs();
|
||||
}
|
||||
|
||||
#endif /* JS_POLYIC */
|
||||
|
||||
|
|
|
@ -352,14 +352,13 @@ struct PICInfo {
|
|||
};
|
||||
|
||||
void PurgePICs(JSContext *cx, JSScript *script);
|
||||
void JS_FASTCALL GetProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL GetElem(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL SetProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL CallProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL Name(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL XName(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL BindName(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL SetPropDumb(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL GetElem(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL SetProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL CallProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL Name(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL XName(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL BindName(VMFrame &f, ic::PICInfo *);
|
||||
|
||||
} /* namespace ic */
|
||||
} /* namespace mjit */
|
||||
|
|
|
@ -73,13 +73,14 @@ AutoScriptRetrapper::untrap(jsbytecode *pc)
|
|||
}
|
||||
|
||||
Recompiler::PatchableAddress
|
||||
Recompiler::findPatch(void **location)
|
||||
Recompiler::findPatch(JITScript *jit, void **location)
|
||||
{
|
||||
for (uint32 i = 0; i < script->jit->nCallSites; i++) {
|
||||
if (script->jit->callSites[i].codeOffset + (uint8*)script->jit->invoke == *location) {
|
||||
uint8* codeStart = (uint8 *)jit->code.m_code.executableAddress();
|
||||
for (uint32 i = 0; i < jit->nCallSites; i++) {
|
||||
if (jit->callSites[i].codeOffset + codeStart == *location) {
|
||||
PatchableAddress result;
|
||||
result.location = location;
|
||||
result.callSite = script->jit->callSites[i];
|
||||
result.callSite = jit->callSites[i];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -116,17 +117,27 @@ Recompiler::Recompiler(JSContext *cx, JSScript *script)
|
|||
bool
|
||||
Recompiler::recompile()
|
||||
{
|
||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||
JS_ASSERT(script->hasJITCode());
|
||||
|
||||
Vector<PatchableAddress> toPatch(cx);
|
||||
Vector<PatchableAddress> normalPatches(cx);
|
||||
Vector<PatchableAddress> ctorPatches(cx);
|
||||
|
||||
/* Scan the stack, saving the ncode elements of the frames. */
|
||||
JSStackFrame *firstFrame = NULL;
|
||||
JSStackFrame *firstCtorFrame = NULL;
|
||||
JSStackFrame *firstNormalFrame = NULL;
|
||||
for (AllFramesIter i(cx); !i.done(); ++i) {
|
||||
if (!firstFrame && i.fp()->maybeScript() == script)
|
||||
firstFrame = i.fp();
|
||||
if (script->isValidJitCode(i.fp()->nativeReturnAddress())) {
|
||||
if (!toPatch.append(findPatch(i.fp()->addressOfNativeReturnAddress())))
|
||||
if (!firstCtorFrame && i.fp()->maybeScript() == script && i.fp()->isConstructing())
|
||||
firstCtorFrame = i.fp();
|
||||
else if (!firstNormalFrame && i.fp()->maybeScript() == script && !i.fp()->isConstructing())
|
||||
firstNormalFrame = i.fp();
|
||||
void **addr = i.fp()->addressOfNativeReturnAddress();
|
||||
if (!*addr)
|
||||
continue;
|
||||
if (script->jitCtor && script->jitCtor->isValidCode(*addr)) {
|
||||
if (!ctorPatches.append(findPatch(script->jitCtor, addr)))
|
||||
return false;
|
||||
} else if (script->jitNormal && script->jitNormal->isValidCode(*addr)) {
|
||||
if (!normalPatches.append(findPatch(script->jitNormal, addr)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -136,29 +147,41 @@ Recompiler::recompile()
|
|||
f != NULL;
|
||||
f = f->previous) {
|
||||
|
||||
void **machineReturn = f->returnAddressLocation();
|
||||
if (script->isValidJitCode(*machineReturn)) {
|
||||
if (!toPatch.append(findPatch(machineReturn)))
|
||||
void **addr = f->returnAddressLocation();
|
||||
if (script->jitCtor && script->jitCtor->isValidCode(*addr)) {
|
||||
if (!ctorPatches.append(findPatch(script->jitCtor, addr)))
|
||||
return false;
|
||||
} else if (script->jitNormal && script->jitNormal->isValidCode(*addr)) {
|
||||
if (!normalPatches.append(findPatch(script->jitNormal, addr)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseScriptCode(cx, script);
|
||||
|
||||
/* No need to actually compile or fixup if no frames on the stack */
|
||||
if (!firstFrame)
|
||||
return true;
|
||||
if (normalPatches.length() && !recompile(firstNormalFrame, normalPatches))
|
||||
return false;
|
||||
|
||||
if (ctorPatches.length() && !recompile(firstCtorFrame, ctorPatches))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Recompiler::recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches)
|
||||
{
|
||||
/* If we get this far, the script is live, and we better be safe to re-jit. */
|
||||
JS_ASSERT(cx->compartment->debugMode);
|
||||
JS_ASSERT(fp);
|
||||
|
||||
Compiler c(cx, script, firstFrame->maybeFun(), &firstFrame->scopeChain());
|
||||
if (c.Compile() != Compile_Okay)
|
||||
Compiler c(cx, fp);
|
||||
if (c.compile() != Compile_Okay)
|
||||
return false;
|
||||
|
||||
/* Perform the earlier scanned patches */
|
||||
for (uint32 i = 0; i < toPatch.length(); i++)
|
||||
applyPatch(c, toPatch[i]);
|
||||
for (uint32 i = 0; i < patches.length(); i++)
|
||||
applyPatch(c, patches[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -97,8 +97,9 @@ private:
|
|||
JSContext *cx;
|
||||
JSScript *script;
|
||||
|
||||
PatchableAddress findPatch(void **location);
|
||||
PatchableAddress findPatch(JITScript *jit, void **location);
|
||||
void applyPatch(Compiler& c, PatchableAddress& toPatch);
|
||||
bool recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches);
|
||||
};
|
||||
|
||||
} /* namespace mjit */
|
||||
|
|
|
@ -99,7 +99,6 @@ ReportAtomNotDefined(JSContext *cx, JSAtom *atom)
|
|||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* jslogic_h__ */
|
||||
|
|
|
@ -281,6 +281,22 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom)
|
|||
template void JS_FASTCALL stubs::SetName<true>(VMFrame &f, JSAtom *origAtom);
|
||||
template void JS_FASTCALL stubs::SetName<false>(VMFrame &f, JSAtom *origAtom);
|
||||
|
||||
template<JSBool strict>
|
||||
void JS_FASTCALL
|
||||
stubs::SetPropNoCache(VMFrame &f, JSAtom *atom)
|
||||
{
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||
if (!obj)
|
||||
THROW();
|
||||
Value rval = f.regs.sp[-1];
|
||||
if (!obj->setProperty(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1], strict))
|
||||
THROW();
|
||||
f.regs.sp[-2] = rval;
|
||||
}
|
||||
|
||||
template void JS_FASTCALL stubs::SetPropNoCache<true>(VMFrame &f, JSAtom *origAtom);
|
||||
template void JS_FASTCALL stubs::SetPropNoCache<false>(VMFrame &f, JSAtom *origAtom);
|
||||
|
||||
template<JSBool strict>
|
||||
void JS_FASTCALL
|
||||
stubs::SetGlobalNameDumb(VMFrame &f, JSAtom *atom)
|
||||
|
@ -2517,14 +2533,15 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
|||
{
|
||||
jsbytecode *jpc = pc;
|
||||
JSScript *script = f.fp()->script();
|
||||
JITScript *jit = script->getJIT(f.fp()->isConstructing());
|
||||
|
||||
/* This is correct because the compiler adjusts the stack beforehand. */
|
||||
Value lval = f.regs.sp[-1];
|
||||
|
||||
if (!lval.isPrimitive()) {
|
||||
ptrdiff_t offs = (pc + GET_JUMP_OFFSET(pc)) - script->code;
|
||||
JS_ASSERT(script->nmap[offs]);
|
||||
return script->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
|
||||
JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
|
||||
|
@ -2544,8 +2561,8 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
|||
JSString *rhs = rval.toString();
|
||||
if (rhs == str || js_EqualStrings(str, rhs)) {
|
||||
ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
|
||||
JS_ASSERT(script->nmap[offs]);
|
||||
return script->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
}
|
||||
pc += JUMP_OFFSET_LEN;
|
||||
|
@ -2557,8 +2574,8 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
|||
pc += INDEX_LEN;
|
||||
if (rval.isNumber() && d == rval.toNumber()) {
|
||||
ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
|
||||
JS_ASSERT(script->nmap[offs]);
|
||||
return script->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
pc += JUMP_OFFSET_LEN;
|
||||
}
|
||||
|
@ -2568,16 +2585,16 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
|||
pc += INDEX_LEN;
|
||||
if (lval == rval) {
|
||||
ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
|
||||
JS_ASSERT(script->nmap[offs]);
|
||||
return script->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
pc += JUMP_OFFSET_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(jpc)) - script->code;
|
||||
JS_ASSERT(script->nmap[offs]);
|
||||
return script->nmap[offs];
|
||||
JS_ASSERT(jit->nmap[offs]);
|
||||
return jit->nmap[offs];
|
||||
}
|
||||
|
||||
void * JS_FASTCALL
|
||||
|
@ -2586,6 +2603,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
|
|||
jsbytecode * const originalPC = origPc;
|
||||
jsbytecode *pc = originalPC;
|
||||
JSScript *script = f.fp()->script();
|
||||
JITScript *jit = script->getJIT(f.fp()->isConstructing());
|
||||
uint32 jumpOffset = GET_JUMP_OFFSET(pc);
|
||||
pc += JUMP_OFFSET_LEN;
|
||||
|
||||
|
@ -2625,8 +2643,8 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
|
|||
finally:
|
||||
/* Provide the native address. */
|
||||
ptrdiff_t offset = (originalPC + jumpOffset) - script->code;
|
||||
JS_ASSERT(script->nmap[offset]);
|
||||
return script->nmap[offset];
|
||||
JS_ASSERT(jit->nmap[offset]);
|
||||
return jit->nmap[offset];
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
|
|
|
@ -98,14 +98,14 @@ struct UncachedCallResult {
|
|||
void UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
|
||||
void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
|
||||
|
||||
JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
|
||||
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
|
||||
void JS_FASTCALL Throw(VMFrame &f);
|
||||
void JS_FASTCALL PutCallObject(VMFrame &f);
|
||||
void JS_FASTCALL PutActivationObjects(VMFrame &f);
|
||||
void JS_FASTCALL GetCallObject(VMFrame &f);
|
||||
void JS_FASTCALL WrapPrimitiveThis(VMFrame &f);
|
||||
#if JS_MONOIC
|
||||
void * JS_FASTCALL InvokeTracer(VMFrame &f, uint32 index);
|
||||
void * JS_FASTCALL InvokeTracer(VMFrame &f, ic::MICInfo *mic);
|
||||
#else
|
||||
void * JS_FASTCALL InvokeTracer(VMFrame &f);
|
||||
#endif
|
||||
|
@ -116,6 +116,7 @@ void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
|
|||
void JS_FASTCALL BindName(VMFrame &f);
|
||||
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);
|
||||
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);
|
||||
|
@ -226,11 +227,6 @@ inline FuncPtr FunctionTemplateConditional(bool cond, FuncPtr a, FuncPtr b) {
|
|||
return cond ? a : b;
|
||||
}
|
||||
|
||||
/* Return f<true> if the script is strict mode code, f<false> otherwise. */
|
||||
#define STRICT_VARIANT(f) \
|
||||
(FunctionTemplateConditional(script->strictModeCode, \
|
||||
f<true>, f<false>))
|
||||
|
||||
}} /* namespace stubs,mjit,js */
|
||||
|
||||
extern "C" void *
|
||||
|
|
|
@ -125,6 +125,11 @@ class StubCompiler
|
|||
STUB_CALL_TYPE(BoolStub);
|
||||
STUB_CALL_TYPE(VoidStubAtom);
|
||||
STUB_CALL_TYPE(VoidStubPC);
|
||||
STUB_CALL_TYPE(VoidStubMIC);
|
||||
STUB_CALL_TYPE(VoidPtrStubMIC);
|
||||
STUB_CALL_TYPE(VoidStubPIC);
|
||||
STUB_CALL_TYPE(VoidStubCallIC);
|
||||
STUB_CALL_TYPE(VoidPtrStubCallIC);
|
||||
|
||||
#undef STUB_CALL_TYPE
|
||||
|
||||
|
|
|
@ -1196,7 +1196,7 @@ AssertJit(JSContext *cx, uintN argc, jsval *vp)
|
|||
{
|
||||
#ifdef JS_METHODJIT
|
||||
if (JS_GetOptions(cx) & JSOPTION_METHODJIT) {
|
||||
if (cx->fp()->script()->nmap == NULL) {
|
||||
if (!cx->fp()->script()->getJIT(cx->fp()->isConstructing())) {
|
||||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_JIT_FAILED);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ function main() { x = "failure"; }
|
|||
function success() { x = "success"; }
|
||||
|
||||
/* The JSOP_STOP in a. */
|
||||
trap(main, 6, "success()");
|
||||
trap(main, 7, "success()");
|
||||
main();
|
||||
|
||||
assertEq(x, "success");
|
||||
|
|
|
@ -3,5 +3,5 @@ function main() {
|
|||
return "failure";
|
||||
}
|
||||
/* JSOP_RETURN in main. */
|
||||
trap(main, 3, "'success'");
|
||||
trap(main, 4, "'success'");
|
||||
assertEq(main(), "success");
|
||||
|
|
|
@ -3,7 +3,7 @@ x = "notset";
|
|||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* myparent call in myparent. */
|
||||
trap(myparent, 37, "failure()");
|
||||
trap(myparent, 38, "failure()");
|
||||
} else {
|
||||
x = "success";
|
||||
myparent(true);
|
||||
|
|
|
@ -4,7 +4,7 @@ x = "notset";
|
|||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* noop call in myparent */
|
||||
trap(myparent, 48, "success()");
|
||||
trap(myparent, 49, "success()");
|
||||
} else {
|
||||
myparent(true);
|
||||
x = "failure";
|
||||
|
|
|
@ -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, 34, "myparent(true)");
|
||||
trap(myparent, 35, "myparent(true)");
|
||||
|
||||
function success() {
|
||||
x = "success";
|
||||
|
|
Загрузка…
Ссылка в новой задаче