Backed out changeset de5d1b528b9a

This commit is contained in:
David Anderson 2010-10-04 15:12:00 -07:00
Родитель 8ab67f850c
Коммит 1f9978e7e9
40 изменённых файлов: 710 добавлений и 988 удалений

Просмотреть файл

@ -2990,7 +2990,7 @@ JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
CHECK_REQUEST(cx);
assertSameCompartment(cx, *vp);
return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
return js_NewInstance(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_CreateThisFromTrace)
JS_DECLARE_CALLINFO(js_NewInstanceFromTrace)
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->hasJITCode())
if (script->jit)
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->hasJITCode()) {
if (script->jit) {
# if defined JS_POLYIC
mjit::ic::PurgePICs(cx, script);
# endif

Просмотреть файл

@ -116,7 +116,8 @@ js_SetDebugMode(JSContext *cx, JSBool debug)
&script->links != &cx->compartment->scripts;
script = (JSScript *)script->links.next) {
if (script->debugMode != debug &&
script->hasJITCode() &&
script->ncode &&
script->ncode != JS_UNJITTABLE_METHOD &&
!IsScriptLive(cx, script)) {
/*
* In the event that this fails, debug mode is left partially on,
@ -235,10 +236,6 @@ 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;
@ -277,7 +274,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
cx->free(junk);
#ifdef JS_METHODJIT
if (script->hasJITCode()) {
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
mjit::Recompiler recompiler(cx, script);
if (!recompiler.recompile())
return JS_FALSE;
@ -330,7 +327,7 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
DBG_UNLOCK(cx->runtime);
#ifdef JS_METHODJIT
if (script->hasJITCode()) {
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
mjit::Recompiler recompiler(cx, script);
recompiler.recompile();
}

Просмотреть файл

@ -3678,15 +3678,10 @@ 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 real instruction. */
/* JSOP_GENERATOR must be the first 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,13 +134,12 @@ 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 = jit->nCallICs;
size_t high = script->jit->nCallICs;
while (high > low + 1) {
/* Could overflow here on a script with 2 billion calls. Oh well. */
size_t mid = (high + low) / 2;
void *entry = jit->callICs[mid].funGuard.executableAddress();
void *entry = script->callICs[mid].funGuard.executableAddress();
/*
* Use >= here as the return address of the call is likely to be
@ -152,7 +151,7 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
low = mid;
}
js::mjit::ic::CallICInfo &callIC = jit->callICs[low];
js::mjit::ic::CallICInfo &callIC = script->callICs[low];
JS_ASSERT((uint8*)callIC.funGuard.executableAddress() + callIC.joinPointOffset == next->ncode_);
return callIC.pc;
@ -617,7 +616,7 @@ struct AutoInterpPreparer {
};
JS_REQUIRES_STACK bool
RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain)
{
JS_ASSERT(script);
@ -627,11 +626,8 @@ RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
AutoInterpPreparer prepareInterp(cx, script);
JS_ASSERT(fp == cx->fp());
JS_ASSERT(fp->script() == script);
#ifdef JS_METHODJIT
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fp);
mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, fun, &scopeChain);
if (status == mjit::Compile_Error)
return JS_FALSE;
@ -639,7 +635,7 @@ RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
return mjit::JaegerShot(cx);
#endif
return Interpret(cx, fp);
return Interpret(cx, cx->fp());
}
/*
@ -690,10 +686,8 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
/* Handle the empty-script special case. */
if (JS_UNLIKELY(script->isEmpty())) {
if (flags & JSINVOKE_CONSTRUCT) {
JSObject *obj = js_CreateThisForFunction(cx, &callee);
if (!obj)
return false;
args.rval().setObject(*obj);
JS_ASSERT(args.thisv().isObject());
args.rval() = args.thisv();
} else {
args.rval().setUndefined();
}
@ -724,20 +718,19 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
* and fp->scopeChain is correct because the thisObject hook may call
* JS_GetScopeChain.
*/
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);
}
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);
}
JSInterpreterHook hook = cx->debugHooks->callHook;
@ -750,7 +743,7 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
{
AutoPreserveEnumerators preserve(cx);
Probes::enterJSFun(cx, fun);
ok = RunScript(cx, script, fp);
ok = RunScript(cx, script, fun, fp->scopeChain());
Probes::exitJSFun(cx, fun);
}
@ -763,8 +756,6 @@ 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;
}
@ -909,7 +900,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
/* Run script until JSOP_STOP or error. */
AutoPreserveEnumerators preserve(cx);
JSBool ok = RunScript(cx, script, frame.fp());
JSBool ok = RunScript(cx, script, NULL, frame.fp()->scopeChain());
if (result)
*result = frame.fp()->returnValue();
@ -1162,9 +1153,8 @@ 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) {
fun = callee->getFunctionPrivate();
JSFunction *fun = callee->getFunctionPrivate();
if (fun->isConstructor()) {
args.thisv().setMagicWithObjectOrNullPayload(NULL);
return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base());
@ -1174,30 +1164,25 @@ InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base());
}
/* 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);
}
/* Construct 'this'. */
JSObject *obj = js_NewInstance(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 (clasp != &js_FunctionClass) {
if (callee->getClass() != &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;
}
/* The interpreter fixes rval for us. */
JS_ASSERT(!fun->isInterpreted());
args.rval() = args.thisv();
args.rval().setObject(*obj);
}
JS_RUNTIME_METER(cx->runtime, constructs);
@ -2305,7 +2290,7 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN
do { \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \
if (leaveOnSafePoint && !regs.fp->hasImacropc() && \
script->hasNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
script->nmap && script->nmap[regs.pc - script->code]) { \
JS_ASSERT(!TRACE_RECORDER(cx)); \
interpReturnOK = true; \
goto stop_recording; \
@ -4492,41 +4477,6 @@ BEGIN_CASE(JSOP_ENUMELEM)
}
END_CASE(JSOP_ENUMELEM)
BEGIN_CASE(JSOP_BEGIN)
{
if (regs.fp->isConstructing()) {
JSObject *obj2 = js_CreateThisForFunction(cx, &regs.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;
@ -4548,15 +4498,24 @@ 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;
}
@ -4625,13 +4584,38 @@ 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 = &regs.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, JSStackFrame *fp);
RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject &scopeChain);
#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);
ok = RunScript(cx, stackfp->script(), stackfp->fun(), stackfp->scopeChain());
gen->enumerators = cx->enumerators;
cx->enumerators = enumerators;

Просмотреть файл

@ -2770,7 +2770,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
}
JSObject*
js_CreateThis(JSContext *cx, JSObject *callee)
js_NewInstance(JSContext *cx, JSObject *callee)
{
Class *clasp = callee->getClass();
@ -2790,25 +2790,6 @@ js_CreateThis(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*
@ -2859,7 +2840,7 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, ST
nanojit::ACCSET_STORE_ANY)
JSObject* FASTCALL
js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
js_NewInstanceFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
{
JS_ASSERT(JS_ON_TRACE(cx));
JS_ASSERT(ctor->isFunction());
@ -2910,7 +2891,7 @@ js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
}
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0,
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstanceFromTrace, CONTEXT, CLASS, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
#else /* !JS_TRACER */

Просмотреть файл

@ -1407,18 +1407,8 @@ 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_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);
js_NewInstance(JSContext *cx, JSObject *callee);
extern jsid
js_CheckForStringIndex(jsid id);

Просмотреть файл

@ -620,6 +620,3 @@ 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_CreateThis(cx, &JS_CALLEE(cx, vp).toObject());
JSObject *thisobj = js_NewInstance(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 = 0, nClosedVars = 0;
uint16 nClosedArgs, nClosedVars;
JSPrincipals *principals;
uint32 encodeable;
JSBool filenameWasSaved;
@ -1641,6 +1641,16 @@ 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,20 +169,21 @@ 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
@ -284,35 +285,20 @@ struct JSScript {
public:
#ifdef JS_METHODJIT
// 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;
// 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
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;
}
bool isValidJitCode(void *jcode);
#endif
/* Script notes are allocated right after the code. */
@ -407,6 +393,17 @@ 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,20 +11051,6 @@ 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)
{
@ -11374,7 +11360,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
clasp = &js_ObjectClass;
JS_ASSERT(((jsuword) clasp & 3) == 0);
// Abort on |new Function|. js_CreateThis would allocate a regular-
// Abort on |new Function|. js_NewInstance 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)
@ -11393,7 +11379,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_CreateThisFromTrace_ci, args);
newobj_ins = lir->insCall(&js_NewInstanceFromTrace_ci, args);
guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT);
/*
@ -11518,8 +11504,15 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
}
#endif
if (FUN_INTERPRETED(fun))
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);
}
return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW);
}
Native native = fun->maybeNative();
Value* argv = &tval + 1;
@ -13313,15 +13306,7 @@ 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;
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();
}
LIns* rval_ins = constructing ? stack(-1 - argc) : 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_CreateThis to record_NativeCallComplete. */
/* Carry the return value of js_NewInstance to record_NativeCallComplete. */
nanojit::LIns* newobj_ins;
/* Carry the JSSpecializedNative used to generate a call to record_NativeCallComplete. */

Просмотреть файл

@ -342,11 +342,6 @@ 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,16 +74,12 @@ static const char *OpcodeNames[] = {
};
#endif
mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
: BaseCompiler(cx),
fp(fp),
script(fp->script()),
scopeChain(&fp->scopeChain()),
script(script),
scopeChain(scopeChain),
globalObj(scopeChain->getGlobal()),
fun(fp->isFunctionFrame() && !fp->isEvalFrame()
? fp->fun()
: NULL),
isConstructing(fp->isConstructing()),
fun(fun),
analysis(cx, script), jumpMap(NULL), frame(cx, script, masm),
branchPatches(ContextAllocPolicy(cx)),
#if defined JS_MONOIC
@ -103,34 +99,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
{
}
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); \
@ -139,8 +107,10 @@ mjit::Compiler::compile()
JS_END_MACRO
CompileStatus
mjit::Compiler::performCompilation(JITScript **jitp)
mjit::Compiler::Compile()
{
JS_ASSERT(!script->ncode);
JaegerSpew(JSpew_Scripts, "compiling script (file \"%s\") (line \"%d\") (length \"%d\")\n",
script->filename, script->lineno, script->length);
@ -182,7 +152,7 @@ mjit::Compiler::performCompilation(JITScript **jitp)
CHECK_STATUS(generatePrologue());
CHECK_STATUS(generateMethod());
CHECK_STATUS(generateEpilogue());
CHECK_STATUS(finishThisUp(jitp));
CHECK_STATUS(finishThisUp());
#ifdef JS_METHODJIT_SPEW
prof.stop();
@ -190,7 +160,7 @@ mjit::Compiler::performCompilation(JITScript **jitp)
#endif
JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
(*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
(void*)script->ncode, masm.size() + stubcc.size());
return Compile_Okay;
}
@ -203,13 +173,18 @@ mjit::Compiler::~Compiler()
}
CompileStatus JS_NEVER_INLINE
mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
mjit::TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
{
JS_ASSERT(cx->fp() == fp);
Compiler cc(cx, script, fun, scopeChain);
Compiler cc(cx, fp);
JS_ASSERT(!script->ncode);
JS_ASSERT(!script->isEmpty());
return cc.compile();
CompileStatus status = cc.Compile();
if (status != Compile_Okay)
script->ncode = JS_UNJITTABLE_METHOD;
return status;
}
CompileStatus
@ -315,7 +290,7 @@ mjit::Compiler::generateEpilogue()
}
CompileStatus
mjit::Compiler::finishThisUp(JITScript **jitp)
mjit::Compiler::finishThisUp()
{
for (size_t i = 0; i < branchPatches.length(); i++) {
Label label = labelOf(branchPatches[i].pc);
@ -361,16 +336,18 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
return Compile_Error;
}
JITScript *jit = (JITScript *)cursor;
script->jit = (JITScript *)cursor;
cursor += sizeof(JITScript);
jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
jit->nCallSites = callSites.length();
jit->invokeEntry = result;
script->jit->execPool = execPool;
script->jit->inlineLength = masm.size();
script->jit->outOfLineLength = stubcc.size();
script->jit->nCallSites = callSites.length();
script->jit->invoke = result;
/* Build the pc -> ncode mapping. */
void **nmap = (void **)cursor;
jit->nmap = nmap;
script->nmap = nmap;
cursor += sizeof(void *) * script->length;
for (size_t i = 0; i < script->length; i++) {
@ -381,116 +358,107 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
}
}
if (fun) {
jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
}
if (fun)
script->jit->arityCheck = stubCode.locationOf(arityLabel).executableAddress();
#if defined JS_MONOIC
jit->nMICs = mics.length();
script->jit->nMICs = mics.length();
if (mics.length()) {
jit->mics = (ic::MICInfo *)cursor;
script->mics = (ic::MICInfo *)cursor;
cursor += sizeof(ic::MICInfo) * mics.length();
} else {
jit->mics = NULL;
script->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;
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_PUNBOX64
scriptMICs[i].patchValueOffset = mics[i].patchValueOffset;
script->mics[i].patchValueOffset = mics[i].patchValueOffset;
#endif
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]);
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");
}
}
jit->nCallICs = callICs.length();
script->jit->nCallICs = callICs.length();
if (callICs.length()) {
jit->callICs = (ic::CallICInfo *)cursor;
script->callICs = (ic::CallICInfo *)cursor;
cursor += sizeof(ic::CallICInfo) * callICs.length();
} else {
jit->callICs = NULL;
script->callICs = NULL;
}
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);
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);
/* 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 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 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 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 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 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 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 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 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);
/* 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);
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]);
}
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;
}
#endif /* JS_MONOIC */
@ -503,47 +471,44 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
}
#if defined JS_POLYIC
jit->nPICs = pics.length();
script->jit->nPICs = pics.length();
if (pics.length()) {
jit->pics = (ic::PICInfo *)cursor;
script->pics = (ic::PICInfo *)cursor;
cursor += sizeof(ic::PICInfo) * pics.length();
} else {
jit->pics = NULL;
script->pics = NULL;
}
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;
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 defined JS_CPU_X64
memcpy(&scriptPICs[i].labels, &pics[i].labels, sizeof(PICLabels));
memcpy(&script->pics[i].labels, &pics[i].labels, sizeof(PICLabels));
# endif
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;
}
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;
}
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 */
@ -569,8 +534,10 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
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. */
jit->nCallSites = callSites.length();
script->jit->nCallSites = callSites.length();
if (callSites.length()) {
CallSite *callSiteList = (CallSite *)cursor;
cursor += sizeof(CallSite) * callSites.length();
@ -583,14 +550,12 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
callSiteList[i].pcOffset = callSites[i].pc - script->code;
callSiteList[i].id = callSites[i].id;
}
jit->callSites = callSiteList;
script->jit->callSites = callSiteList;
} else {
jit->callSites = NULL;
script->jit->callSites = NULL;
}
JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes);
*jitp = jit;
JS_ASSERT(size_t(cursor - (uint8*)script->jit) == totalBytes);
return Compile_Okay;
}
@ -1697,11 +1662,6 @@ 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
@ -1757,17 +1717,15 @@ 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 oolPath + stubcc.masm.distanceOf(callSites[i].location);
return (uint8*)script->jit->invoke + masm.size() +
stubcc.masm.distanceOf(callSites[i].location);
}
return ilPath + masm.distanceOf(callSites[i].location);
return (uint8*)script->jit->invoke +
stubcc.masm.distanceOf(callSites[i].location);
}
}
@ -1823,100 +1781,24 @@ 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, FrameEntry *fe)
mjit::Compiler::loadReturnValue(Assembler &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);
}
/*
* 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);
}
}
// 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)
{
@ -1941,7 +1823,8 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
stubCall(stubs::PutActivationObjects);
if (fe) {
emitReturnValue(&masm, fe);
masm.loadValueAsComponents(frame.addressOf(fe),
JSReturnReg_Type, JSReturnReg_Data);
emitFinalReturn(masm);
frame.discardFrame();
return;
@ -1956,12 +1839,22 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
stubcc.leave();
stubcc.call(stubs::PutActivationObjects);
emitReturnValue(&stubcc.masm, fe);
if (fe) {
stubcc.masm.loadValueAsComponents(frame.addressOf(fe),
JSReturnReg_Type, JSReturnReg_Data);
} else {
loadReturnValue(stubcc.masm);
}
emitFinalReturn(stubcc.masm);
}
}
emitReturnValue(&masm, fe);
if (fe)
frame.storeTo(fe, JSReturnReg_Data, JSReturnReg_Type, Registers::ReturnReg);
else
loadReturnValue(masm);
emitFinalReturn(masm);
frame.discardFrame();
}
@ -2036,6 +1929,18 @@ 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)
{
@ -2068,6 +1973,9 @@ 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);
@ -2085,10 +1993,6 @@ 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. */
@ -2098,7 +2002,12 @@ 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;
/*
@ -2135,6 +2044,16 @@ 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();
@ -2164,6 +2083,28 @@ 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
@ -2174,7 +2115,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
callIC.oolJump = toPatch;
/* At this point the function is definitely scripted. Call the link routine. */
callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
callIC.oolCall = stubcc.call(callingNew ? ic::New : ic::Call);
callIC.funObjReg = dataReg;
@ -2204,7 +2145,7 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
notFunction.linkTo(stubcc.masm.label(), &stubcc.masm);
isNative.linkTo(stubcc.masm.label(), &stubcc.masm);
callIC.addrLabel2 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
stubcc.call(callingNew ? ic::NativeNew : ic::NativeCall);
rejoin2 = stubcc.masm.jump();
@ -2216,6 +2157,13 @@ 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;
@ -2227,6 +2175,13 @@ 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);
@ -2420,19 +2375,6 @@ 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)
{
@ -2503,7 +2445,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::GetProp);
/* Load dslots. */
@ -2604,7 +2546,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj
pic.slowPathStart = stubcc.linkExit(jmpShapeGuard, Uses(2));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::GetElem);
/* Load dslots. */
@ -2730,7 +2672,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
/* Slow path. */
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::CallProp);
/* Adjust the frame. None of this will generate code. */
@ -2894,7 +2836,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::CallProp);
/* Load dslots. */
@ -3016,12 +2958,13 @@ 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.call(STRICT_VARIANT(stubs::SetPropNoCache));
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
stubcc.call(ic::SetPropDumb);
}
typeCheck = stubcc.masm.jump();
@ -3061,7 +3004,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
pic.slowPathStart = stubcc.linkExit(j, Uses(2));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::SetProp);
}
@ -3141,7 +3084,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
{
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::Name);
}
@ -3184,7 +3127,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
{
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::XName);
}
@ -3226,7 +3169,7 @@ mjit::Compiler::jsop_bindname(uint32 index)
{
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
stubcc.leave();
passPICAddress(pic);
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
pic.callReturn = stubcc.call(ic::BindName);
}
@ -3933,7 +3876,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
stubcc.linkExit(shapeGuard, Uses(0));
stubcc.leave();
passMICAddress(mic);
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
mic.stubEntry = stubcc.masm.label();
mic.call = stubcc.call(ic::GetGlobalName);
@ -4032,7 +3975,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
stubcc.linkExit(shapeGuard, Uses(2));
stubcc.leave();
passMICAddress(mic);
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
mic.stubEntry = stubcc.masm.label();
mic.call = stubcc.call(ic::SetGlobalName);
@ -4283,7 +4226,7 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slowOne, Jump *sl
if (slowTwo)
slowTwo->linkTo(traceStart, &stubcc.masm);
# if JS_MONOIC
passMICAddress(mic);
stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
# endif
/* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
@ -4353,45 +4296,3 @@ 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,7 +72,6 @@ class Compiler : public BaseCompiler
Label entry;
Label stubEntry;
DataLabel32 shape;
DataLabelPtr addrLabel;
#if defined JS_PUNBOX64
uint32 patchValueOffset;
#endif
@ -115,8 +114,6 @@ class Compiler : public BaseCompiler
Label slowJoinPoint;
Label slowPathStart;
Label hotPathLabel;
DataLabelPtr addrLabel1;
DataLabelPtr addrLabel2;
Jump oolJump;
RegisterID funObjReg;
RegisterID funPtrReg;
@ -146,7 +143,6 @@ class Compiler : public BaseCompiler
Label storeBack;
Label typeCheck;
Label slowPathStart;
DataLabelPtr addrLabel;
RegisterID shapeReg;
RegisterID objReg;
RegisterID idReg;
@ -200,12 +196,10 @@ class Compiler : public BaseCompiler
bool ool;
};
JSStackFrame *fp;
JSScript *script;
JSObject *scopeChain;
JSObject *globalObj;
JSFunction *fun;
bool isConstructing;
BytecodeAnalyzer analysis;
Label *jumpMap;
jsbytecode *PC;
@ -217,7 +211,7 @@ class Compiler : public BaseCompiler
js::Vector<CallGenInfo, 64> callICs;
#endif
#if defined JS_POLYIC
js::Vector<PICGenInfo, 16> pics;
js::Vector<PICGenInfo, 64> pics;
#endif
js::Vector<CallPatchInfo, 64> callPatches;
js::Vector<InternalCallSite, 64> callSites;
@ -232,10 +226,10 @@ class Compiler : public BaseCompiler
// follows interpreter usage in JSOP_LENGTH.
enum { LengthAtomIndex = uint32(-2) };
Compiler(JSContext *cx, JSStackFrame *fp);
Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
~Compiler();
CompileStatus compile();
CompileStatus Compile();
jsbytecode *getPC() { return PC; }
Label getLabel() { return masm.label(); }
@ -244,11 +238,10 @@ class Compiler : public BaseCompiler
void *findCallSite(const CallSite &callSite);
private:
CompileStatus performCompilation(JITScript **jitp);
CompileStatus generatePrologue();
CompileStatus generateMethod();
CompileStatus generateEpilogue();
CompileStatus finishThisUp(JITScript **jitp);
CompileStatus finishThisUp();
/* Non-emitting helpers. */
uint32 fullAtomIndex(jsbytecode *pc);
@ -264,9 +257,6 @@ 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);
@ -278,13 +268,12 @@ class Compiler : public BaseCompiler
void jsop_this();
void emitReturn(FrameEntry *fe);
void emitFinalReturn(Assembler &masm);
void loadReturnValue(Assembler *masm, FrameEntry *fe);
void emitReturnValue(Assembler *masm, FrameEntry *fe);
void loadReturnValue(Assembler &masm);
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::loadTo(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
void FrameState::storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg, RegisterID tempReg)
{
JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
@ -347,15 +347,6 @@ void FrameState::loadTo(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg,
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) {
@ -902,14 +893,6 @@ 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 loadTo(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
void storeTo(FrameEntry *fe, RegisterID dataReg, RegisterID typeReg, RegisterID tempReg);
/*
* Stores the top stack slot back to a slot.
@ -654,11 +654,6 @@ 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,6 +219,29 @@ 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)
{
@ -338,8 +361,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)
@ -366,9 +389,9 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
THROWV(NULL);
CompileStatus status = CanMethodJIT(cx, script, fp);
CompileStatus status = CanMethodJIT(cx, script, fun, &fp->scopeChain());
if (status == Compile_Okay)
return script->getJIT(callingNew)->invokeEntry;
return script->jit->invoke;
/* Function did not compile... interpret it. */
JSBool ok = Interpret(cx, fp);
@ -418,8 +441,8 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
}
/* Try to compile if not already compiled. */
if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
if (mjit::TryCompile(cx, newfp) == Compile_Error) {
if (!newscript->ncode) {
if (mjit::TryCompile(cx, newscript, newfp->fun(), &newfp->scopeChain()) == Compile_Error) {
/* A runtime exception was thrown, get out. */
InlineReturn(f, JS_FALSE);
return false;
@ -427,8 +450,9 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
}
/* If newscript was successfully compiled, run it. */
if (JITScript *jit = newscript->getJIT(newfp->isConstructing())) {
*pret = jit->invokeEntry;
JS_ASSERT(newscript->ncode);
if (newscript->ncode != JS_UNJITTABLE_METHOD) {
*pret = newscript->jit->invoke;
return true;
}
@ -460,6 +484,9 @@ 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();
@ -585,10 +612,7 @@ js_InternalThrow(VMFrame &f)
if (!pc)
return NULL;
JSStackFrame *fp = cx->fp();
JSScript *script = fp->script();
JITScript *jit = script->getJIT(fp->isConstructing());
return jit->nmap[pc - script->code];
return cx->fp()->script()->pcToNative(pc);
}
void JS_FASTCALL
@ -599,18 +623,6 @@ 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)
{
@ -684,12 +696,11 @@ AtSafePoint(JSContext *cx)
return false;
JSScript *script = fp->script();
JITScript *jit = script->getJIT(fp->isConstructing());
if (!jit->nmap)
if (!script->nmap)
return false;
JS_ASSERT(cx->regs->pc >= script->code && cx->regs->pc < script->code + script->length);
return !!jit->nmap[cx->regs->pc - script->code];
return !!script->nmap[cx->regs->pc - script->code];
}
static inline JSBool
@ -698,11 +709,8 @@ PartialInterpret(VMFrame &f)
JSContext *cx = f.cx;
JSStackFrame *fp = cx->fp();
#ifdef DEBUG
JITScript *jit = fp->script()->getJIT(fp->isConstructing());
JS_ASSERT(fp->hasImacropc() || !jit->nmap ||
!jit->nmap[cx->regs->pc - fp->script()->code]);
#endif
JS_ASSERT(fp->hasImacropc() || !fp->script()->nmap ||
!fp->script()->nmap[cx->regs->pc - fp->script()->code]);
JSBool ok = JS_TRUE;
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
@ -732,8 +740,7 @@ FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
if (AtSafePoint(cx)) {
JSScript *script = fp->script();
JITScript *jit = script->getJIT(fp->isConstructing());
if (!JaegerShotAtSafePoint(cx, jit->nmap[cx->regs->pc - script->code])) {
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
if (!HandleErrorInExcessFrames(f, entryFrame))
return false;
@ -887,10 +894,9 @@ 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(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(entryFrame->script()->nmap[offs]);
return entryFrame->script()->nmap[offs];
}
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
@ -924,10 +930,14 @@ RunTracer(VMFrame &f)
#if defined JS_TRACER
# if defined JS_MONOIC
void *JS_FASTCALL
stubs::InvokeTracer(VMFrame &f, ic::MICInfo *mic)
stubs::InvokeTracer(VMFrame &f, uint32 index)
{
JS_ASSERT(mic->kind == ic::MICInfo::TRACER);
return RunTracer(f, *mic);
JSScript *script = f.fp()->script();
ic::MICInfo &mic = script->mics[index];
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)
{
JSStackFrame *fp = cx->fp();
JSScript *script = fp->script();
JITScript *jit = script->getJIT(fp->isConstructing());
JSScript *script = cx->fp()->script();
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
#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(), jit->invokeEntry);
return EnterMethodJIT(cx, cx->fp(), script->jit->invoke);
}
JSBool
@ -795,47 +795,37 @@ static inline void Destroy(T &t)
}
void
mjit::JITScript::release()
mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
{
if (script->jit) {
#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64)
void *addr = code.m_code.executableAddress();
memset(addr, 0xcc, code.m_size);
memset(script->jit->invoke, 0xcc, script->jit->inlineLength +
script->jit->outOfLineLength);
#endif
script->jit->execPool->release();
script->jit->execPool = NULL;
code.m_executablePool->release();
// Releasing the execPool takes care of releasing the code.
script->ncode = NULL;
#if defined JS_POLYIC
for (uint32 i = 0; i < nPICs; i++) {
pics[i].releasePools();
Destroy(pics[i].execPools);
}
for (uint32 i = 0; i < script->jit->nPICs; i++) {
script->pics[i].releasePools();
Destroy(script->pics[i].execPools);
}
#endif
#if defined JS_MONOIC
for (uint32 i = 0; i < nCallICs; i++)
callICs[i].releasePools();
for (uint32 i = 0; i < script->jit->nCallICs; i++)
script->callICs[i].releasePools();
#endif
}
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.
cx->free(script->jit);
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;
// 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;
}
}

Просмотреть файл

@ -139,18 +139,6 @@ 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);
@ -170,47 +158,26 @@ 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);
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 *);
#define JS_UNJITTABLE_METHOD (reinterpret_cast<void*>(1))
namespace mjit {
struct CallSite;
struct JITScript {
typedef JSC::MacroAssemblerCodeRef CodeRef;
CodeRef code; /* pool & code addresses */
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 */
js::mjit::CallSite *callSites;
uint32 nCallSites;
void **nmap; /* scripted pc to native code map. */
#ifdef JS_MONOIC
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 */
uint32 nMICs; /* number of MonoICs */
uint32 nCallICs; /* number of call ICs */
#endif
#ifdef JS_POLYIC
ic::PICInfo *pics; /* PICs in this script */
uint32 nPICs; /* number of PolyICs */
uint32 nPICs; /* number of PolyICs */
#endif
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();
void *invoke; /* invoke address */
void *arityCheck; /* arity check address */
};
/* Execute a method that has been JIT compiled. */
@ -230,21 +197,18 @@ void JS_FASTCALL
ProfileStubCall(VMFrame &f);
CompileStatus JS_NEVER_INLINE
TryCompile(JSContext *cx, JSStackFrame *fp);
TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
void
ReleaseScriptCode(JSContext *cx, JSScript *script);
static inline CompileStatus
CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp)
CanMethodJIT(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
{
if (!cx->methodJitEnabled)
if (!cx->methodJitEnabled || script->ncode == JS_UNJITTABLE_METHOD)
return Compile_Abort;
JITScriptStatus status = script->getJITStatus(fp->isConstructing());
if (status == JITScript_Invalid)
return Compile_Abort;
if (status == JITScript_None)
return TryCompile(cx, fp);
if (script->ncode == NULL)
return TryCompile(cx, script, fun, scopeChain);
return Compile_Okay;
}
@ -259,25 +223,6 @@ 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,21 +70,22 @@ typedef JSC::MacroAssembler::Call Call;
#if defined JS_MONOIC
static void
PatchGetFallback(VMFrame &f, ic::MICInfo *ic)
PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
{
JSC::RepatchBuffer repatch(ic->stubEntry.executableAddress(), 64);
JSC::RepatchBuffer repatch(mic.stubEntry.executableAddress(), 64);
JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::GetGlobalName));
repatch.relink(ic->stubCall, fptr);
repatch.relink(mic.stubCall, fptr);
}
void JS_FASTCALL
ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
ic::GetGlobalName(VMFrame &f, uint32 index)
{
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(ic->kind == ic::MICInfo::GET);
JS_ASSERT(mic.kind == ic::MICInfo::GET);
JS_LOCK_OBJ(f.cx, obj);
const Shape *shape = obj->nativeLookup(id);
@ -94,33 +95,33 @@ ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
{
JS_UNLOCK_OBJ(f.cx, obj);
if (shape)
PatchGetFallback(f, ic);
PatchGetFallback(f, mic);
stubs::GetGlobalName(f);
return;
}
uint32 slot = shape->slot;
JS_UNLOCK_OBJ(f.cx, obj);
ic->u.name.touched = true;
mic.u.name.touched = true;
/* Patch shape guard. */
JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
repatch.repatch(ic->shape, obj->shape());
JSC::RepatchBuffer repatch(mic.entry.executableAddress(), 50);
repatch.repatch(mic.shape, obj->shape());
/* Patch loads. */
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
slot -= JS_INITIAL_NSLOTS;
slot *= sizeof(Value);
JSC::RepatchBuffer loads(ic->load.executableAddress(), 32, false);
JSC::RepatchBuffer loads(mic.load.executableAddress(), 32, false);
#if defined JS_CPU_X86
loads.repatch(ic->load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
loads.repatch(ic->load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_DATA_OFFSET), slot);
loads.repatch(mic.load.dataLabel32AtOffset(MICInfo::GET_TYPE_OFFSET), slot + 4);
#elif defined JS_CPU_ARM
// ic->load actually points to the LDR instruction which fetches the offset, but 'repatch'
// mic.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(ic->load.dataLabel32AtOffset(0), slot);
loads.repatch(mic.load.dataLabel32AtOffset(0), slot);
#elif defined JS_PUNBOX64
loads.repatch(ic->load.dataLabel32AtOffset(ic->patchValueOffset), slot);
loads.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
#endif
/* Do load anyway... this time. */
@ -139,11 +140,11 @@ SetGlobalNameSlow(VMFrame &f, uint32 index)
}
static void
PatchSetFallback(VMFrame &f, ic::MICInfo *ic)
PatchSetFallback(VMFrame &f, ic::MICInfo &mic)
{
JSC::RepatchBuffer repatch(ic->stubEntry.executableAddress(), 64);
JSC::RepatchBuffer repatch(mic.stubEntry.executableAddress(), 64);
JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, SetGlobalNameSlow));
repatch.relink(ic->stubCall, fptr);
repatch.relink(mic.stubCall, fptr);
}
static VoidStubAtom
@ -158,13 +159,14 @@ GetStubForSetGlobalName(VMFrame &f)
}
void JS_FASTCALL
ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
ic::SetGlobalName(VMFrame &f, uint32 index)
{
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(ic->kind == ic::MICInfo::SET);
JS_ASSERT(mic.kind == ic::MICInfo::SET);
JS_LOCK_OBJ(f.cx, obj);
const Shape *shape = obj->nativeLookup(id);
@ -175,40 +177,40 @@ ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
{
JS_UNLOCK_OBJ(f.cx, obj);
if (shape)
PatchSetFallback(f, ic);
PatchSetFallback(f, mic);
GetStubForSetGlobalName(f)(f, atom);
return;
}
uint32 slot = shape->slot;
JS_UNLOCK_OBJ(f.cx, obj);
ic->u.name.touched = true;
mic.u.name.touched = true;
/* Patch shape guard. */
JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
repatch.repatch(ic->shape, obj->shape());
JSC::RepatchBuffer repatch(mic.entry.executableAddress(), 50);
repatch.repatch(mic.shape, obj->shape());
/* Patch loads. */
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
slot -= JS_INITIAL_NSLOTS;
slot *= sizeof(Value);
JSC::RepatchBuffer stores(ic->load.executableAddress(), 32, false);
JSC::RepatchBuffer stores(mic.load.executableAddress(), 32, false);
#if defined JS_CPU_X86
stores.repatch(ic->load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
stores.repatch(mic.load.dataLabel32AtOffset(MICInfo::SET_TYPE_OFFSET), slot + 4);
uint32 dataOffset;
if (ic->u.name.typeConst)
if (mic.u.name.typeConst)
dataOffset = MICInfo::SET_DATA_CONST_TYPE_OFFSET;
else
dataOffset = MICInfo::SET_DATA_TYPE_OFFSET;
stores.repatch(ic->load.dataLabel32AtOffset(dataOffset), slot);
stores.repatch(mic.load.dataLabel32AtOffset(dataOffset), slot);
#elif defined JS_CPU_ARM
// ic->load actually points to the LDR instruction which fetches the offset, but 'repatch'
// mic.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(ic->load.dataLabel32AtOffset(0), slot);
stores.repatch(mic.load.dataLabel32AtOffset(0), slot);
#elif defined JS_PUNBOX64
stores.repatch(ic->load.dataLabel32AtOffset(ic->patchValueOffset), slot);
stores.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
#endif
// Actually implement the op the slow way.
@ -216,16 +218,24 @@ ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
}
static void * JS_FASTCALL
SlowCallFromIC(VMFrame &f, ic::CallICInfo *ic)
SlowCallFromIC(VMFrame &f, uint32 index)
{
stubs::SlowCall(f, ic->argc);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic= oldscript->callICs[index];
stubs::SlowCall(f, ic.argc);
return NULL;
}
static void * JS_FASTCALL
SlowNewFromIC(VMFrame &f, ic::CallICInfo *ic)
SlowNewFromIC(VMFrame &f, uint32 index)
{
stubs::SlowNew(f, ic->argc);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
stubs::SlowNew(f, ic.argc);
return NULL;
}
@ -315,11 +325,8 @@ class CallCompiler : public BaseCompiler
* here since ncode has two failure modes and we need to load out of
* nmap anyway.
*/
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));
masm.loadPtr(Address(t0, offsetof(JSScript, jit)), t0);
Jump hasCode = masm.branchTestPtr(Assembler::NonZero, t0, t0);
/* Try and compile. On success we get back the nmap pointer. */
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
@ -338,6 +345,7 @@ 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);
@ -369,11 +377,9 @@ 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(jit->fastEntry));
JSC::CodeLocationLabel(script->ncode));
JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %p)\n", start, ic.fastGuardedObject);
}
@ -643,40 +649,52 @@ class CallCompiler : public BaseCompiler
};
void * JS_FASTCALL
ic::Call(VMFrame &f, CallICInfo *ic)
ic::Call(VMFrame &f, uint32 index)
{
CallCompiler cc(f, *ic, false);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, false);
return cc.update();
}
void * JS_FASTCALL
ic::New(VMFrame &f, CallICInfo *ic)
ic::New(VMFrame &f, uint32 index)
{
CallCompiler cc(f, *ic, true);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true);
return cc.update();
}
void JS_FASTCALL
ic::NativeCall(VMFrame &f, CallICInfo *ic)
ic::NativeCall(VMFrame &f, uint32 index)
{
CallCompiler cc(f, *ic, false);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
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, CallICInfo *ic)
ic::NativeNew(VMFrame &f, uint32 index)
{
CallCompiler cc(f, *ic, true);
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true);
if (!cc.generateNativeStub())
stubs::SlowNew(f, ic->argc);
stubs::SlowNew(f, ic.argc);
}
void
JITScript::purgeMICs()
ic::PurgeMICs(JSContext *cx, JSScript *script)
{
for (uint32 i = 0; i < nMICs; i++) {
ic::MICInfo &mic = mics[i];
/* 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];
switch (mic.kind) {
case ic::MICInfo::SET:
case ic::MICInfo::GET:
@ -702,22 +720,10 @@ JITScript::purgeMICs()
}
void
ic::PurgeMICs(JSContext *cx, JSScript *script)
ic::SweepCallICs(JSScript *script)
{
/* 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];
for (uint32 i = 0; i < script->jit->nCallICs; i++) {
ic::CallICInfo &ic = script->callICs[i];
/*
* If the object is unreachable, we're guaranteed not to be currently
@ -751,14 +757,5 @@ JITScript::sweepCallICs()
}
}
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, ic::MICInfo *ic);
void JS_FASTCALL SetGlobalName(VMFrame &f, ic::MICInfo *ic);
void JS_FASTCALL GetGlobalName(VMFrame &f, uint32 index);
void JS_FASTCALL SetGlobalName(VMFrame &f, uint32 index);
/* See MonoIC.cpp, CallCompiler for more information on call ICs. */
struct CallICInfo {
@ -187,10 +187,10 @@ struct CallICInfo {
}
};
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 * 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 PurgeMICs(JSContext *cx, JSScript *script);
void SweepCallICs(JSScript *script);

Просмотреть файл

@ -111,7 +111,8 @@ class PICStubCompiler : public BaseCompiler
return disable(reason, JS_FUNC_TO_DATA_PTR(void *, stub));
}
bool disable(const char *reason, VoidStubPIC stub) {
bool disable(const char *reason, VoidStubUInt32 stub)
{
return disable(reason, JS_FUNC_TO_DATA_PTR(void *, stub));
}
@ -158,7 +159,7 @@ class SetPropCompiler : public PICStubCompiler
{
JSObject *obj;
JSAtom *atom;
VoidStubPIC stub;
VoidStubUInt32 stub;
int lastStubSecondShapeGuard;
static int32 dslotsLoadOffset(ic::PICInfo &pic) {
@ -223,7 +224,7 @@ class SetPropCompiler : public PICStubCompiler
public:
SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
VoidStubPIC stub)
VoidStubUInt32 stub)
: PICStubCompiler("setprop", f, script, pic), obj(obj), atom(atom), stub(stub),
lastStubSecondShapeGuard(pic.secondShapeGuard)
{ }
@ -745,7 +746,7 @@ class GetPropCompiler : public PICStubCompiler
{ }
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
VoidStubPIC stub)
VoidStubUInt32 stub)
: PICStubCompiler("callprop", f, script, pic), obj(obj), atom(atom),
stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
lastStubSecondShapeGuard(pic.secondShapeGuard)
@ -769,7 +770,7 @@ class GetPropCompiler : public PICStubCompiler
RepatchBuffer repatcher2(pic.slowPathStart.executableAddress(), INLINE_PATH_LENGTH);
ReturnAddressPtr retPtr(pic.slowPathStart.callAtOffset(pic.callReturn).executableAddress());
VoidStubPIC stub;
VoidStubUInt32 stub;
switch (pic.kind) {
case ic::PICInfo::GET:
stub = ic::GetProp;
@ -1572,7 +1573,7 @@ class ScopeNameCompiler : public PICStubCompiler
public:
ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
JSAtom *atom, VoidStubPIC stub)
JSAtom *atom, VoidStubUInt32 stub)
: PICStubCompiler("name", f, script, pic), scopeChain(scopeChain), atom(atom),
stub(JS_FUNC_TO_DATA_PTR(void *, stub)), obj(NULL), holder(NULL), prop(NULL)
{ }
@ -1590,7 +1591,7 @@ class ScopeNameCompiler : public PICStubCompiler
RepatchBuffer repatcher2(pic.slowPathStart.executableAddress(), INLINE_PATH_LENGTH);
ReturnAddressPtr retPtr(pic.slowPathStart.callAtOffset(pic.callReturn).executableAddress());
VoidStubPIC stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
VoidStubUInt32 stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
MacroAssemblerCodePtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
repatcher.relinkCallerToTrampoline(retPtr, target);
}
@ -1911,7 +1912,7 @@ class BindNameCompiler : public PICStubCompiler
public:
BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
JSAtom *atom, VoidStubPIC stub)
JSAtom *atom, VoidStubUInt32 stub)
: PICStubCompiler("bind", f, script, pic), scopeChain(scopeChain), atom(atom),
stub(JS_FUNC_TO_DATA_PTR(void *, stub))
{ }
@ -2019,14 +2020,15 @@ class BindNameCompiler : public PICStubCompiler
};
void JS_FASTCALL
ic::GetProp(VMFrame &f, ic::PICInfo *pic)
ic::GetProp(VMFrame &f, uint32 index)
{
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();
@ -2037,7 +2039,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
} else if (!f.regs.sp[-1].isPrimitive()) {
JSObject *obj = &f.regs.sp[-1].toObject();
if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden())) {
GetPropCompiler cc(f, script, obj, *pic, NULL, stubs::Length);
GetPropCompiler cc(f, script, obj, pic, NULL, stubs::Length);
if (obj->isArray()) {
if (!cc.generateArrayLengthStub()) {
cc.disable("error");
@ -2061,8 +2063,8 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
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();
@ -2076,9 +2078,10 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
}
void JS_FASTCALL
ic::GetElem(VMFrame &f, ic::PICInfo *pic)
ic::GetElem(VMFrame &f, uint32 picIndex)
{
JSScript *script = f.fp()->script();
PICInfo &pic = script->pics[picIndex];
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
if (!obj)
@ -2087,8 +2090,8 @@ ic::GetElem(VMFrame &f, ic::PICInfo *pic)
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();
@ -2104,29 +2107,46 @@ ic::GetElem(VMFrame &f, ic::PICInfo *pic)
f.regs.sp[-2] = v;
}
template <JSBool strict>
static void JS_FASTCALL
SetPropDumb(VMFrame &f, ic::PICInfo *pic)
void JS_FASTCALL
ic::SetPropDumb(VMFrame &f, uint32 index)
{
stubs::SetPropNoCache<strict>(f, pic->atom);
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, ic::PICInfo *pic)
SetPropSlow(VMFrame &f, uint32 index)
{
stubs::SetName<strict>(f, pic->atom);
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JS_ASSERT(pic.isSet());
JSAtom *atom = pic.atom;
STRICT_VARIANT(stubs::SetName)(f, atom);
}
void JS_FASTCALL
ic::SetProp(VMFrame &f, ic::PICInfo *pic)
ic::SetProp(VMFrame &f, uint32 index)
{
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
if (!obj)
THROW();
JSScript *script = f.fp()->script();
JS_ASSERT(pic->isSet());
ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom;
JS_ASSERT(pic.isSet());
//
// Important: We update the PIC before looking up the property so that the
@ -2137,7 +2157,7 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic)
// cache can't handle a GET and SET from the same scripted PC.
//
VoidStubPIC stub;
VoidStubUInt32 stub;
switch (JSOp(*f.regs.pc)) {
case JSOP_PROPINC:
case JSOP_PROPDEC:
@ -2147,36 +2167,40 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic)
case JSOP_NAMEDEC:
case JSOP_INCNAME:
case JSOP_DECNAME:
stub = STRICT_VARIANT(SetPropDumb);
stub = SetPropDumb;
break;
default:
stub = STRICT_VARIANT(SetPropSlow);
stub = SetPropSlow;
break;
}
SetPropCompiler cc(f, script, obj, *pic, pic->atom, stub);
SetPropCompiler cc(f, script, obj, pic, atom, stub);
if (!cc.update()) {
cc.disable("error");
THROW();
}
Value rval = f.regs.sp[-1];
stub(f, pic);
stub(f, index);
}
static void JS_FASTCALL
CallPropSlow(VMFrame &f, ic::PICInfo *pic)
CallPropSlow(VMFrame &f, uint32 index)
{
stubs::CallProp(f, pic->atom);
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
stubs::CallProp(f, pic.atom);
}
void JS_FASTCALL
ic::CallProp(VMFrame &f, ic::PICInfo *pic)
ic::CallProp(VMFrame &f, uint32 index)
{
JSContext *cx = f.cx;
JSFrameRegs &regs = f.regs;
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JSAtom *origAtom = pic.atom;
Value lval;
lval = regs.sp[-1];
@ -2236,7 +2260,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
* PropertyCache::test.
*/
jsid id;
id = ATOM_TO_JSID(pic->atom);
id = ATOM_TO_JSID(origAtom);
regs.sp++;
regs.sp[-1].setNull();
@ -2274,7 +2298,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
}
}
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, CallPropSlow);
GetPropCompiler cc(f, script, &objv.toObject(), pic, origAtom, CallPropSlow);
if (usePIC) {
if (lval.isObject()) {
if (!cc.update()) {
@ -2295,7 +2319,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
#if JS_HAS_NO_SUCH_METHOD
if (JS_UNLIKELY(rval.isUndefined())) {
regs.sp[-2].setString(ATOM_TO_STRING(pic->atom));
regs.sp[-2].setString(ATOM_TO_STRING(origAtom));
if (!js_OnUnknownMethod(cx, regs.sp - 2))
THROW();
}
@ -2303,26 +2327,28 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
}
static void JS_FASTCALL
SlowName(VMFrame &f, ic::PICInfo *pic)
SlowName(VMFrame &f, uint32 index)
{
stubs::Name(f);
}
static void JS_FASTCALL
SlowXName(VMFrame &f, ic::PICInfo *pic)
SlowXName(VMFrame &f, uint32 index)
{
stubs::GetProp(f);
}
void JS_FASTCALL
ic::XName(VMFrame &f, ic::PICInfo *pic)
ic::XName(VMFrame &f, uint32 index)
{
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, pic->atom, SlowXName);
ScopeNameCompiler cc(f, script, obj, pic, atom, SlowXName);
if (!cc.updateForXName()) {
cc.disable("error");
@ -2336,11 +2362,13 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
}
void JS_FASTCALL
ic::Name(VMFrame &f, ic::PICInfo *pic)
ic::Name(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom;
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowName);
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowName);
if (!cc.updateForName()) {
cc.disable("error");
@ -2354,17 +2382,19 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
}
static void JS_FASTCALL
SlowBindName(VMFrame &f, ic::PICInfo *pic)
SlowBindName(VMFrame &f, uint32 index)
{
stubs::BindName(f);
}
void JS_FASTCALL
ic::BindName(VMFrame &f, ic::PICInfo *pic)
ic::BindName(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom;
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowBindName);
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowBindName);
JSObject *obj = cc.update();
if (!obj) {
@ -2376,10 +2406,11 @@ ic::BindName(VMFrame &f, ic::PICInfo *pic)
}
void
JITScript::purgePICs()
ic::PurgePICs(JSContext *cx, JSScript *script)
{
for (uint32 i = 0; i < nPICs; i++) {
ic::PICInfo &pic = pics[i];
uint32 npics = script->jit->nPICs;
for (uint32 i = 0; i < npics; i++) {
ic::PICInfo &pic = script->pics[i];
switch (pic.kind) {
case ic::PICInfo::SET:
case ic::PICInfo::SETMETHOD:
@ -2407,14 +2438,5 @@ JITScript::purgePICs()
}
}
void
ic::PurgePICs(JSContext *cx, JSScript *script)
{
if (script->jitNormal)
script->jitNormal->purgePICs();
if (script->jitCtor)
script->jitCtor->purgePICs();
}
#endif /* JS_POLYIC */

Просмотреть файл

@ -352,13 +352,14 @@ struct PICInfo {
};
void PurgePICs(JSContext *cx, JSScript *script);
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 *);
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);
} /* namespace ic */
} /* namespace mjit */

Просмотреть файл

@ -73,14 +73,13 @@ AutoScriptRetrapper::untrap(jsbytecode *pc)
}
Recompiler::PatchableAddress
Recompiler::findPatch(JITScript *jit, void **location)
Recompiler::findPatch(void **location)
{
uint8* codeStart = (uint8 *)jit->code.m_code.executableAddress();
for (uint32 i = 0; i < jit->nCallSites; i++) {
if (jit->callSites[i].codeOffset + codeStart == *location) {
for (uint32 i = 0; i < script->jit->nCallSites; i++) {
if (script->jit->callSites[i].codeOffset + (uint8*)script->jit->invoke == *location) {
PatchableAddress result;
result.location = location;
result.callSite = jit->callSites[i];
result.callSite = script->jit->callSites[i];
return result;
}
}
@ -117,27 +116,17 @@ Recompiler::Recompiler(JSContext *cx, JSScript *script)
bool
Recompiler::recompile()
{
JS_ASSERT(script->hasJITCode());
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
Vector<PatchableAddress> normalPatches(cx);
Vector<PatchableAddress> ctorPatches(cx);
Vector<PatchableAddress> toPatch(cx);
/* Scan the stack, saving the ncode elements of the frames. */
JSStackFrame *firstCtorFrame = NULL;
JSStackFrame *firstNormalFrame = NULL;
JSStackFrame *firstFrame = NULL;
for (AllFramesIter i(cx); !i.done(); ++i) {
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)))
if (!firstFrame && i.fp()->maybeScript() == script)
firstFrame = i.fp();
if (script->isValidJitCode(i.fp()->nativeReturnAddress())) {
if (!toPatch.append(findPatch(i.fp()->addressOfNativeReturnAddress())))
return false;
}
}
@ -147,41 +136,29 @@ Recompiler::recompile()
f != NULL;
f = f->previous) {
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)))
void **machineReturn = f->returnAddressLocation();
if (script->isValidJitCode(*machineReturn)) {
if (!toPatch.append(findPatch(machineReturn)))
return false;
}
}
ReleaseScriptCode(cx, script);
if (normalPatches.length() && !recompile(firstNormalFrame, normalPatches))
return false;
/* No need to actually compile or fixup if no frames on the stack */
if (!firstFrame)
return true;
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, fp);
if (c.compile() != Compile_Okay)
Compiler c(cx, script, firstFrame->maybeFun(), &firstFrame->scopeChain());
if (c.Compile() != Compile_Okay)
return false;
/* Perform the earlier scanned patches */
for (uint32 i = 0; i < patches.length(); i++)
applyPatch(c, patches[i]);
for (uint32 i = 0; i < toPatch.length(); i++)
applyPatch(c, toPatch[i]);
return true;
}

Просмотреть файл

@ -97,9 +97,8 @@ private:
JSContext *cx;
JSScript *script;
PatchableAddress findPatch(JITScript *jit, void **location);
PatchableAddress findPatch(void **location);
void applyPatch(Compiler& c, PatchableAddress& toPatch);
bool recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches);
};
} /* namespace mjit */

Просмотреть файл

@ -99,6 +99,7 @@ ReportAtomNotDefined(JSContext *cx, JSAtom *atom)
} \
JS_END_MACRO
}}
#endif /* jslogic_h__ */

Просмотреть файл

@ -281,22 +281,6 @@ 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)
@ -2533,15 +2517,14 @@ 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(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(script->nmap[offs]);
return script->nmap[offs];
}
JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
@ -2561,8 +2544,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(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(script->nmap[offs]);
return script->nmap[offs];
}
}
pc += JUMP_OFFSET_LEN;
@ -2574,8 +2557,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(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(script->nmap[offs]);
return script->nmap[offs];
}
pc += JUMP_OFFSET_LEN;
}
@ -2585,16 +2568,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(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(script->nmap[offs]);
return script->nmap[offs];
}
pc += JUMP_OFFSET_LEN;
}
}
ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(jpc)) - script->code;
JS_ASSERT(jit->nmap[offs]);
return jit->nmap[offs];
JS_ASSERT(script->nmap[offs]);
return script->nmap[offs];
}
void * JS_FASTCALL
@ -2603,7 +2586,6 @@ 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;
@ -2643,8 +2625,8 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
finally:
/* Provide the native address. */
ptrdiff_t offset = (originalPC + jumpOffset) - script->code;
JS_ASSERT(jit->nmap[offset]);
return jit->nmap[offset];
JS_ASSERT(script->nmap[offset]);
return script->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);
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
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, ic::MICInfo *mic);
void * JS_FASTCALL InvokeTracer(VMFrame &f, uint32 index);
#else
void * JS_FASTCALL InvokeTracer(VMFrame &f);
#endif
@ -116,7 +116,6 @@ 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);
@ -227,6 +226,11 @@ 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,11 +125,6 @@ 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()->getJIT(cx->fp()->isConstructing())) {
if (cx->fp()->script()->nmap == NULL) {
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, 7, "success()");
trap(main, 6, "success()");
main();
assertEq(x, "success");

Просмотреть файл

@ -3,5 +3,5 @@ function main() {
return "failure";
}
/* JSOP_RETURN in main. */
trap(main, 4, "'success'");
trap(main, 3, "'success'");
assertEq(main(), "success");

Просмотреть файл

@ -3,7 +3,7 @@ x = "notset";
function myparent(nested) {
if (nested) {
/* myparent call in myparent. */
trap(myparent, 38, "failure()");
trap(myparent, 37, "failure()");
} else {
x = "success";
myparent(true);

Просмотреть файл

@ -4,7 +4,7 @@ x = "notset";
function myparent(nested) {
if (nested) {
/* noop call in myparent */
trap(myparent, 49, "success()");
trap(myparent, 48, "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, 25, "success()");
trap(myparent, 24, "success()");
doNothing();
} else {
doNothing();
}
}
/* JSOP_CALL to doNothing in myparent with nested = false. */
trap(myparent, 35, "myparent(true)");
trap(myparent, 34, "myparent(true)");
function success() {
x = "success";