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]; unsigned i = GET_SLOTNO(f.pc()); Value *var = (JOF_TYPE(cs->format) == JOF_LOCAL) ? f.fp()->slots() + i : &f.fp()->formalArg(i); if (rejoin == REJOIN_POS) { double d = ov.toNumber(); double N = (cs->format & JOF_INC) ? 1 : -1; if (!nv.setNumber(d + N)) types::TypeScript::MonitorOverflow(cx, f.script(), f.pc()); } *var = nv; *vp = (cs->format & JOF_POST) ? ov : nv; }
void stubs::UncachedCallHelper(VMFrame &f, uint32_t argc, bool lowered, UncachedCallResult &ucr) { ucr.init(); JSContext *cx = f.cx; CallArgs args = CallArgsFromSp(argc, f.regs.sp); if (IsFunctionObject(args.calleev(), ucr.fun.address())) { if (ucr.fun->isInterpreted()) { InitialFrameFlags initial = lowered ? INITIAL_LOWERED : INITIAL_NONE; if (!UncachedInlineCall(f, initial, &ucr.codeAddr, &ucr.unjittable, argc)) THROW(); return; } if (ucr.fun->isNative()) { if (!CallJSNative(cx, ucr.fun->native(), args)) THROW(); RootedScript fscript(cx, f.script()); types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval()); return; } } if (!InvokeKernel(f.cx, args)) THROW(); RootedScript fscript(cx, f.script()); types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval()); return; }
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; }
void JS_FASTCALL stubs::SlowNew(VMFrame &f, uint32_t argc) { CallArgs args = CallArgsFromSp(argc, f.regs.sp); RootedScript fscript(f.cx, f.script()); if (!MaybeCloneAndPatchCallee(f.cx, args, fscript, f.pc())) THROW(); if (!InvokeConstructorKernel(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval()); }
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 JS_FASTCALL DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic) { AssertCanGC(); RootedPropertyName name(f.cx, f.script()->getName(GET_UINT32_INDEX(f.pc()))); stubs::SetName(f, name); }
void JS_FASTCALL ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic) { JSObject *obj = f.fp()->scopeChain().getGlobal(); JSAtom *atom = f.script()->getAtom(GET_INDEX(f.pc())); jsid id = ATOM_TO_JSID(atom); const Shape *shape = obj->nativeLookup(f.cx, id); if (!shape || !shape->hasDefaultGetterOrIsMethod() || !shape->hasSlot()) { if (shape) PatchGetFallback(f, ic); stubs::GetGlobalName(f); return; } uint32 slot = shape->slot; /* Patch shape guard. */ Repatcher repatcher(f.jit()); repatcher.repatch(ic->fastPathStart.dataLabel32AtOffset(ic->shapeOffset), obj->shape()); /* Patch loads. */ uint32 index = obj->dynamicSlotIndex(slot); JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value)); /* Do load anyway... this time. */ stubs::GetGlobalName(f); }
static void JS_FASTCALL DisabledSetGlobalNoCache(VMFrame &f, ic::SetGlobalNameIC *ic) { JSScript *script = f.script(); JSAtom *atom = script->getAtom(GET_INDEX(f.pc())); stubs::SetGlobalNameNoCache<strict>(f, atom); }
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::SlowCall(VMFrame &f, uint32_t argc) { CallArgs args = CallArgsFromSp(argc, f.regs.sp); if (!InvokeKernel(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); }
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 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(); }
void JS_FASTCALL stubs::GetElem(VMFrame &f) { MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]); HandleValue rval = HandleValue::fromMarkedLocation(&f.regs.sp[-1]); MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]); if (!GetElementOperation(f.cx, JSOp(*f.pc()), lval, rval, res)) THROW(); }
void JS_FASTCALL stubs::Eval(VMFrame &f, uint32_t argc) { CallArgs args = CallArgsFromSp(argc, f.regs.sp); if (!IsBuiltinEvalForScope(f.fp()->scopeChain(), args.calleev())) { if (!InvokeKernel(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); return; } JS_ASSERT(f.fp() == f.cx->fp()); if (!DirectEval(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); }
void stubs::UncachedNewHelper(VMFrame &f, uint32_t argc, UncachedCallResult &ucr) { ucr.init(); JSContext *cx = f.cx; CallArgs args = CallArgsFromSp(argc, f.regs.sp); RootedScript fscript(cx, f.script()); if (!ucr.setFunction(cx, args, fscript, f.pc())) THROW(); /* Try to do a fast inline call before the general Invoke path. */ if (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, fscript, f.pc(), args.rval()); } }
void JS_FASTCALL stubs::SetName(VMFrame &f, PropertyName *name) { JSContext *cx = f.cx; const Value &rval = f.regs.sp[-1]; const Value &lval = f.regs.sp[-2]; if (!SetPropertyOperation(cx, f.pc(), lval, rval)) THROW(); f.regs.sp[-2] = f.regs.sp[-1]; }
void JS_FASTCALL stubs::CrossChunkShim(VMFrame &f, void *edge_) { DebugOnly<CrossChunkEdge*> edge = (CrossChunkEdge *) edge_; mjit::ExpandInlineFrames(f.cx->compartment); JSScript *script = f.script(); JS_ASSERT(edge->target < script->length); JS_ASSERT(script->code + edge->target == f.pc()); CompileStatus status = CanMethodJIT(f.cx, script, f.pc(), f.fp()->isConstructing(), CompileRequest_Interpreter); if (status == Compile_Error) THROW(); void **addr = f.returnAddressLocation(); *addr = JS_FUNC_TO_DATA_PTR(void *, JaegerInterpoline); f.fp()->setRejoin(StubRejoin(REJOIN_RESUME)); }
void JS_FASTCALL stubs::SlowCall(VMFrame &f, uint32_t argc) { if (*f.regs.pc == JSOP_FUNAPPLY && !GuardFunApplySpeculation(f.cx, f.regs)) THROW(); CallArgs args = CallArgsFromSp(argc, f.regs.sp); if (!InvokeKernel(f.cx, args)) THROW(); types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); }
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]; RootedValue rval(cx, regs.sp[-1]); RootedId id(cx); Rooted<JSObject*> obj(cx, ValueToObject(cx, objval)); if (!obj) THROW(); if (!FetchElementId(f.cx, obj, idval, id.address(), MutableHandleValue::fromMarkedLocation(®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, obj, 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) { 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]; }
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()); }
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 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 stubs::UncachedNewHelper(VMFrame &f, uint32 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 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 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 ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic) { AssertCanGC(); RootedObject obj(f.cx, &f.fp()->global()); PropertyName *name = f.script()->getName(GET_UINT32_INDEX(f.pc())); RecompilationMonitor monitor(f.cx); uint32_t slot; { RootedShape shape(f.cx, obj->nativeLookup(f.cx, NameToId(name))); if (monitor.recompiled()) { stubs::Name(f); return; } if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) { if (shape) PatchGetFallback(f, ic); stubs::Name(f); return; } slot = shape->slot(); /* Patch shape guard. */ Repatcher repatcher(f.chunk()); repatcher.repatch(ic->fastPathStart.dataLabelPtrAtOffset(ic->shapeOffset), obj->lastProperty()); /* Patch loads. */ uint32_t index = obj->dynamicSlotIndex(slot); JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value)); } /* Do load anyway... this time. */ stubs::Name(f); }
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 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::SetElem(VMFrame &f) { JSContext *cx = f.cx; FrameRegs ®s = f.regs; HandleValue objval = HandleValue::fromMarkedLocation(®s.sp[-3]); Value &idval = regs.sp[-2]; RootedValue rval(cx, regs.sp[-1]); RootedId id(cx); RootedObject obj(cx, ToObjectFromStack(cx, objval)); if (!obj) THROW(); if (!FetchElementId(f.cx, obj, idval, &id, MutableHandleValue::fromMarkedLocation(®s.sp[-2]))) { THROW(); } TypeScript::MonitorAssign(cx, obj, id); if (obj->isArray() && JSID_IS_INT(id)) { uint32_t length = obj->getDenseInitializedLength(); int32_t i = JSID_TO_INT(id); if ((uint32_t)i >= length) { if (f.script()->hasAnalysis()) f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true; } } if (!JSObject::setGeneric(cx, obj, obj, id, &rval, strict)) THROW(); /* :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]; }