Example #1
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];
    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(), &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, 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];
}
Example #2
0
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];
}
Example #3
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];

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