void JS_FASTCALL stubs::SetElem(VMFrame &f) { JSContext *cx = f.cx; FrameRegs ®s = f.regs; Value &objval = regs.sp[-3]; Value &idval = regs.sp[-2]; Value rval = regs.sp[-1]; JSObject *obj; RootedId id(cx); obj = ValueToObject(cx, objval); if (!obj) THROW(); if (!FetchElementId(f.cx, obj, idval, id.address(), ®s.sp[-2])) THROW(); TypeScript::MonitorAssign(cx, obj, id); do { if (obj->isDenseArray() && JSID_IS_INT(id)) { uint32_t length = obj->getDenseArrayInitializedLength(); int32_t i = JSID_TO_INT(id); if ((uint32_t)i < length) { if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { if (js_PrototypeHasIndexedProperties(cx, obj)) break; if ((uint32_t)i >= obj->getArrayLength()) obj->setArrayLength(cx, i + 1); } obj->setDenseArrayElementWithType(cx, i, rval); goto end_setelem; } else { if (f.script()->hasAnalysis()) f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true; } } } while (0); if (!obj->setGeneric(cx, id, &rval, strict)) THROW(); end_setelem: /* :FIXME: Moving the assigned object into the lowest stack slot * is a temporary hack. What we actually want is an implementation * of popAfterSet() that allows popping more than one value; * this logic can then be handled in Compiler.cpp. */ regs.sp[-3] = regs.sp[-1]; }
void JS_FASTCALL stubs::SetName(VMFrame &f, PropertyName *name) { AssertCanGC(); JSContext *cx = f.cx; RootedObject scope(cx, &f.regs.sp[-2].toObject()); HandleValue value = HandleValue::fromMarkedLocation(&f.regs.sp[-1]); RootedScript fscript(cx, f.script()); if (!SetNameOperation(cx, fscript, f.pc(), scope, value)) THROW(); f.regs.sp[-2] = f.regs.sp[-1]; }
static void FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp) { /* Finish an increment operation on a LOCAL or ARG. These do not involve property accesses. */ JS_ASSERT(rejoin == REJOIN_POS || rejoin == REJOIN_BINARY); JSContext *cx = f.cx; JSOp op = JSOp(*f.pc()); JS_ASSERT(op == JSOP_LOCALINC || op == JSOP_INCLOCAL || op == JSOP_LOCALDEC || op == JSOP_DECLOCAL || op == JSOP_ARGINC || op == JSOP_INCARG || op == JSOP_ARGDEC || op == JSOP_DECARG); const JSCodeSpec *cs = &js_CodeSpec[op]; if (rejoin == REJOIN_POS) { double d = ov.toNumber(); double N = (cs->format & JOF_INC) ? 1 : -1; if (!nv.setNumber(d + N)) { RootedScript fscript(cx, f.script()); types::TypeScript::MonitorOverflow(cx, fscript, f.pc()); } } unsigned i = GET_SLOTNO(f.pc()); if (JOF_TYPE(cs->format) == JOF_LOCAL) f.fp()->unaliasedLocal(i) = nv; else if (f.fp()->script()->argsObjAliasesFormals()) f.fp()->argsObj().setArg(i, nv); else f.fp()->unaliasedFormal(i) = nv; *vp = (cs->format & JOF_POST) ? ov : nv; }
/* * Clean up a frame and return. */ static void InlineReturn(VMFrame &f) { JS_ASSERT(f.fp() != f.entryfp); JS_ASSERT(!js_IsActiveWithOrBlock(f.cx, &f.fp()->scopeChain(), 0)); f.cx->stack.popInlineFrame(f.regs); JS_ASSERT(*f.regs.pc == JSOP_CALL || *f.regs.pc == JSOP_NEW || *f.regs.pc == JSOP_EVAL || *f.regs.pc == JSOP_FUNCALL || *f.regs.pc == JSOP_FUNAPPLY); f.regs.pc += JSOP_CALL_LENGTH; }
/* * HitStackQuota is called after the early prologue pushing the new frame would * overflow f.stackLimit. */ void JS_FASTCALL stubs::HitStackQuota(VMFrame &f) { /* Include space to push another frame. */ uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME; JS_ASSERT(f.regs.sp == f.fp()->base()); if (f.cx->stack().bumpCommitAndLimit(f.entryfp, f.regs.sp, nvals, &f.stackLimit)) return; /* Remove the current partially-constructed frame before throwing. */ RemovePartialFrame(f.cx, f.fp()); js_ReportOverRecursed(f.cx); THROW(); }
VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) { int size = VMFrame::FrameSize(func->NumRegD, func->NumRegF, func->NumRegS, func->NumRegA, func->MaxParam, func->ExtraSpace); VMFrame *frame = Alloc(size); frame->Func = func; frame->NumRegD = func->NumRegD; frame->NumRegF = func->NumRegF; frame->NumRegS = func->NumRegS; frame->NumRegA = func->NumRegA; frame->MaxParam = func->MaxParam; frame->Func = func; frame->InitRegS(); return frame; }
void JS_FASTCALL stubs::Ursh(VMFrame &f) { uint32_t u; if (!ToUint32(f.cx, f.regs.sp[-2], &u)) THROW(); int32_t j; if (!ToInt32(f.cx, f.regs.sp[-1], &j)) THROW(); u >>= (j & 31); if (!f.regs.sp[-2].setNumber(uint32_t(u))) TypeScript::MonitorOverflow(f.cx, f.script(), f.pc()); }
/* * Clean up a frame and return. */ static void InlineReturn(VMFrame &f) { JS_ASSERT(f.fp() != f.entryfp); JS_ASSERT(!IsActiveWithOrBlock(f.cx, f.fp()->scopeChain(), 0)); JS_ASSERT(!f.fp()->hasBlockChain()); f.cx->stack.popInlineFrame(f.regs); DebugOnly<JSOp> op = JSOp(*f.regs.pc); JS_ASSERT(op == JSOP_CALL || op == JSOP_NEW || op == JSOP_EVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY); f.regs.pc += JSOP_CALL_LENGTH; }
/* * Clean up a frame and return. */ static void InlineReturn(VMFrame &f) { JS_ASSERT(f.fp() != f.entryfp); AssertValidFunctionScopeChainAtExit(f.fp()); f.cx->stack.popInlineFrame(f.regs); DebugOnly<JSOp> op = JSOp(*f.regs.pc); JS_ASSERT(op == JSOP_CALL || op == JSOP_NEW || op == JSOP_EVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY); f.regs.pc += JSOP_CALL_LENGTH; }
static LookupStatus UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, Shape *shape) { /* Give globals a chance to appear. */ if (!shape) return Lookup_Uncacheable; if (!shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot() || obj->watched()) { /* Disable the IC for weird shape attributes and watchpoints. */ PatchSetFallback(f, ic); return Lookup_Uncacheable; } /* Object is not branded, so we can use the inline path. */ Repatcher repatcher(f.chunk()); ic->patchInlineShapeGuard(repatcher, obj->lastProperty()); uint32_t index = obj->dynamicSlotIndex(shape->slot()); JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); repatcher.patchAddressOffsetForValueStore(label, index * sizeof(Value), ic->vr.isTypeKnown()); return Lookup_Cacheable; }
void JS_FASTCALL stubs::SlowCall(VMFrame &f, uint32_t argc) { if (*f.regs.pc == JSOP_FUNAPPLY && !GuardFunApplyArgumentsOptimization(f.cx)) THROW(); CallArgs args = CallArgsFromSp(argc, f.regs.sp); RootedScript fscript(f.cx, f.script()); if (!MaybeCloneAndPatchCallee(f.cx, args, fscript, f.pc())) THROW(); if (!InvokeKernel(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval()); }
static void PatchGetFallback(VMFrame &f, ic::GetGlobalNameIC *ic) { Repatcher repatch(f.chunk()); JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::Name)); repatch.relink(ic->slowPathCall, fptr); }
void JS_FASTCALL ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) { JSObject *obj = f.fp()->scopeChain().getGlobal(); JSScript *script = f.script(); JSAtom *atom = script->getAtom(GET_INDEX(f.pc())); const Shape *shape = obj->nativeLookup(f.cx, ATOM_TO_JSID(atom)); LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape); if (status == Lookup_Error) THROW(); if (ic->usePropertyCache) STRICT_VARIANT(stubs::SetGlobalName)(f, atom); else STRICT_VARIANT(stubs::SetGlobalNameNoCache)(f, atom); }
void JS_FASTCALL stubs::Eval(VMFrame &f, uint32 argc) { CallArgs args = CallArgsFromSp(argc, f.regs.sp); if (!IsBuiltinEvalForScope(&f.fp()->scopeChain(), args.calleev())) { if (!Invoke(f.cx, args)) THROW(); return; } JS_ASSERT(f.fp() == f.cx->fp()); if (!DirectEval(f.cx, args)) THROW(); f.regs.sp = args.spAfterCall(); }
static void PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic) { Repatcher repatch(f.chunk()); VoidStubSetGlobal stub = DisabledSetGlobal; JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stub)); repatch.relink(ic->slowPathCall, fptr); }
VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) { VMFrame *frame = Alloc(func->StackSize); frame->Func = func; frame->NumRegD = func->NumRegD; frame->NumRegF = func->NumRegF; frame->NumRegS = func->NumRegS; frame->NumRegA = func->NumRegA; frame->MaxParam = func->MaxParam; frame->Func = func; frame->InitRegS(); if (func->SpecialInits.Size()) { func->InitExtra(frame->GetExtra()); } return frame; }
void JS_FASTCALL stubs::BindName(VMFrame &f, PropertyName *name) { JSObject *obj = FindIdentifierBase(f.cx, &f.fp()->scopeChain(), name); if (!obj) THROW(); f.regs.sp[0].setObject(*obj); }
void JS_FASTCALL stubs::Name(VMFrame &f) { Value rval; if (!NameOperation(f.cx, f.pc(), &rval)) THROW(); f.regs.sp[0] = rval; }
void JS_FASTCALL stubs::ToId(VMFrame &f) { Value &objval = f.regs.sp[-2]; Value &idval = f.regs.sp[-1]; JSObject *obj = ValueToObject(f.cx, objval); if (!obj) THROW(); RootedId id(f.cx); if (!FetchElementId(f.cx, obj, idval, id.address(), &idval)) THROW(); if (!idval.isInt32()) TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); }
void JS_FASTCALL stubs::ToId(VMFrame &f) { Value &objval = f.regs.sp[-2]; MutableHandleValue idval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]); JSObject *obj = ValueToObject(f.cx, objval); if (!obj) THROW(); RootedId id(f.cx); if (!FetchElementId(f.cx, obj, idval, id.address(), idval)) THROW(); if (!idval.isInt32()) TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); }
void stubs::UncachedNewHelper(VMFrame &f, uint32_t argc, UncachedCallResult *ucr) { ucr->init(); JSContext *cx = f.cx; CallArgs args = CallArgsFromSp(argc, f.regs.sp); /* Try to do a fast inline call before the general Invoke path. */ if (IsFunctionObject(args.calleev(), &ucr->fun) && ucr->fun->isInterpretedConstructor()) { if (!UncachedInlineCall(f, INITIAL_CONSTRUCT, &ucr->codeAddr, &ucr->unjittable, argc)) THROW(); } else { if (!InvokeConstructorKernel(cx, args)) THROW(); types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); } }
void JS_FASTCALL ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) { RootedObject obj(f.cx, &f.fp()->global()); RootedPropertyName name(f.cx, f.script()->getName(GET_UINT32_INDEX(f.pc()))); RecompilationMonitor monitor(f.cx); Shape *shape = obj->nativeLookup(f.cx, NameToId(name)); if (!monitor.recompiled()) { LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape); if (status == Lookup_Error) THROW(); } STRICT_VARIANT(f.script(), stubs::SetGlobalName)(f, name); }
void JS_FASTCALL stubs::BindName(VMFrame &f, PropertyName *name_) { RootedPropertyName name(f.cx, name_); RootedObject scope(f.cx); if (!LookupNameWithGlobalDefault(f.cx, name, f.fp()->scopeChain(), &scope)) THROW(); f.regs.sp[0].setObject(*scope); }
void JS_FASTCALL stubs::ScriptDebugPrologue(VMFrame &f) { Probes::enterJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script()); JSTrapStatus status = js::ScriptDebugPrologue(f.cx, f.fp()); switch (status) { case JSTRAP_CONTINUE: break; case JSTRAP_RETURN: *f.returnAddressLocation() = f.cx->jaegerRuntime().forceReturnFromFastCall(); return; case JSTRAP_ERROR: case JSTRAP_THROW: THROW(); default: JS_NOT_REACHED("bad ScriptDebugPrologue status"); } }
/* * This function must only be called after the early prologue, since it depends * on fp->exec.fun. */ void * JS_FASTCALL stubs::FixupArity(VMFrame &f, uint32 nactual) { JSContext *cx = f.cx; JSStackFrame *oldfp = f.fp(); JS_ASSERT(nactual != oldfp->numFormalArgs()); /* * Grossssss! *move* the stack frame. If this ends up being perf-critical, * we can figure out how to spot-optimize it. Be careful to touch only the * members that have been initialized by initCallFrameCallerHalf and the * early prologue. */ uint32 flags = oldfp->isConstructingFlag(); JSFunction *fun = oldfp->fun(); void *ncode = oldfp->nativeReturnAddress(); /* Pop the inline frame. */ f.fp() = oldfp->prev(); f.regs.sp = (Value*) oldfp; /* Reserve enough space for a callee frame. */ JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual, fun, fun->script(), &flags, f.entryfp, &f.stackLimit); if (!newfp) { /* * The PC is not coherent with the current frame, so fix it up for * exception handling. */ f.regs.pc = f.jit()->nativeToPC(ncode); THROWV(NULL); } /* Reset the part of the stack frame set by the caller. */ newfp->initCallFrameCallerHalf(cx, flags, ncode); /* Reset the part of the stack frame set by the prologue up to now. */ newfp->initCallFrameEarlyPrologue(fun, nactual); /* The caller takes care of assigning fp to regs. */ return newfp; }
void JS_FASTCALL stubs::ToId(VMFrame &f) { HandleValue objval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]); MutableHandleValue idval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]); JSObject *obj = ToObjectFromStack(f.cx, objval); if (!obj) THROW(); RootedId id(f.cx); if (!FetchElementId(f.cx, obj, idval, &id, idval)) THROW(); if (!idval.isInt32()) { RootedScript fscript(f.cx, f.script()); TypeScript::MonitorUnknown(f.cx, fscript, f.pc()); } }
void JS_FASTCALL stubs::GetElem(VMFrame &f) { Value &lref = f.regs.sp[-2]; Value &rref = f.regs.sp[-1]; Value &rval = f.regs.sp[-2]; if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval)) THROW(); }
void JS_FASTCALL ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) { JSObject &obj = f.fp()->global(); JSScript *script = f.script(); PropertyName *name = script->getName(GET_UINT32_INDEX(f.pc())); RecompilationMonitor monitor(f.cx); const Shape *shape = obj.nativeLookup(f.cx, NameToId(name)); if (!monitor.recompiled()) { LookupStatus status = UpdateSetGlobalName(f, ic, &obj, shape); if (status == Lookup_Error) THROW(); } STRICT_VARIANT(stubs::SetGlobalName)(f, name); }
void JS_FASTCALL stubs::GetElem(VMFrame &f) { Value &lref = f.regs.sp[-2]; Value &rref = f.regs.sp[-1]; MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]); if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, res)) THROW(); }
VMFrame *VMFrameStack::AllocFrame(int numregd, int numregf, int numregs, int numrega) { assert((unsigned)numregd < 255); assert((unsigned)numregf < 255); assert((unsigned)numregs < 255); assert((unsigned)numrega < 255); // To keep the arguments to this function simpler, it assumes that every // register might be used as a parameter for a single call. int numparam = numregd + numregf + numregs + numrega; int size = VMFrame::FrameSize(numregd, numregf, numregs, numrega, numparam, 0); VMFrame *frame = Alloc(size); frame->NumRegD = numregd; frame->NumRegF = numregf; frame->NumRegS = numregs; frame->NumRegA = numrega; frame->MaxParam = numparam; frame->InitRegS(); return frame; }