Beispiel #1
0
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;
}
Beispiel #4
0
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());
}
Beispiel #5
0
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
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);
}
Beispiel #9
0
void JS_FASTCALL
stubs::Name(VMFrame &f)
{
    Value rval;
    if (!NameOperation(f.cx, f.pc(), &rval))
        THROW();
    f.regs.sp[0] = rval;
}
Beispiel #10
0
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());
}
Beispiel #11
0
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();
}
Beispiel #12
0
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();
}
Beispiel #14
0
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());
}
Beispiel #15
0
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());
    }
}
Beispiel #16
0
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];
}
Beispiel #17
0
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));
}
Beispiel #18
0
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());
}
Beispiel #19
0
void JS_FASTCALL
stubs::SetElem(VMFrame &f)
{
    JSContext *cx = f.cx;
    FrameRegs &regs = 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(&regs.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];
}
Beispiel #20
0
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];
}
Beispiel #21
0
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());
}
Beispiel #22
0
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());
}
Beispiel #23
0
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());
    }
}
Beispiel #25
0
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());
}
Beispiel #26
0
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);
}
Beispiel #27
0
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());
    }
}
Beispiel #29
0
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 &regs = f.regs;

    HandleValue objval = HandleValue::fromMarkedLocation(&regs.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(&regs.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];
}