Example #1
0
void JS_FASTCALL
ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
{
    JSObject &obj = f.fp()->scopeChain().global();
    PropertyName *name = f.script()->getName(GET_UINT32_INDEX(f.pc()));

    RecompilationMonitor monitor(f.cx);

    const Shape *shape = obj.nativeLookup(f.cx, js_CheckForStringIndex(ATOM_TO_JSID(name)));

    if (monitor.recompiled()) {
        stubs::Name(f);
        return;
    }

    if (!shape ||
        !shape->hasDefaultGetter() ||
        !shape->hasSlot())
    {
        if (shape)
            PatchGetFallback(f, ic);
        stubs::Name(f);
        return;
    }
    uint32_t 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);
}
Example #2
0
void JS_FASTCALL
stubs::CrossChunkShim(VMFrame &f, void *edge_)
{
    AssertCanGC();
    DebugOnly<CrossChunkEdge*> edge = (CrossChunkEdge *) edge_;

    mjit::ExpandInlineFrames(f.cx->compartment);

    RootedScript script(f.cx, 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, f.fp());
    if (status == Compile_Error)
        THROW();

    void **addr = f.returnAddressLocation();
    *addr = JS_FUNC_TO_DATA_PTR(void *, JaegerInterpoline);

    f.fp()->setRejoin(StubRejoin(REJOIN_RESUME));
}
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());
    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;
}
Example #4
0
static void JS_FASTCALL
DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic)
{
    stubs::SetGlobalName<strict>(f, f.script()->getName(GET_UINT32_INDEX(f.pc())));
}
Example #5
0
void JS_FASTCALL
stubs::DefFun(VMFrame &f, JSFunction *fun_)
{
    /*
     * A top-level function defined in Global or Eval code (see ECMA-262
     * Ed. 3), or else a SpiderMonkey extension: a named function statement in
     * a compound statement (not at the top statement level of global code, or
     * at the top level of a function body).
     */
    JSContext *cx = f.cx;
    StackFrame *fp = f.fp();
    RootedFunction fun(f.cx, fun_);

    /*
     * If static link is not current scope, clone fun's object to link to the
     * current scope via parent. We do this to enable sharing of compiled
     * functions among multiple equivalent scopes, amortizing the cost of
     * compilation over a number of executions.  Examples include XUL scripts
     * and event handlers shared among Firefox or other Mozilla app chrome
     * windows, and user-defined JS functions precompiled and then shared among
     * requests in server-side JS.
     */
    HandleObject scopeChain = f.fp()->scopeChain();
    if (fun->environment() != scopeChain) {
        fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain);
        if (!fun)
            THROW();
    } else {
        JS_ASSERT(f.script()->compileAndGo);
        JS_ASSERT(f.fp()->isGlobalFrame() || f.fp()->isEvalInFunction());
    }

    /*
     * ECMA requires functions defined when entering Eval code to be
     * impermanent.
     */
    unsigned attrs = fp->isEvalFrame()
                  ? JSPROP_ENUMERATE
                  : JSPROP_ENUMERATE | JSPROP_PERMANENT;

    /*
     * We define the function as a property of the variable object and not the
     * current scope chain even for the case of function expression statements
     * and functions defined by eval inside let or with blocks.
     */
    JSObject *parent = &fp->varObj();

    /* ES5 10.5 (NB: with subsequent errata). */
    PropertyName *name = fun->atom->asPropertyName();
    JSProperty *prop = NULL;
    JSObject *pobj;
    if (!parent->lookupProperty(cx, name, &pobj, &prop))
        THROW();

    Value rval = ObjectValue(*fun);

    do {
        /* Steps 5d, 5f. */
        if (!prop || pobj != parent) {
            if (!parent->defineProperty(cx, name, rval,
                                        JS_PropertyStub, JS_StrictPropertyStub, attrs))
            {
                THROW();
            }
            break;
        }

        /* Step 5e. */
        JS_ASSERT(parent->isNative());
        Shape *shape = reinterpret_cast<Shape *>(prop);
        if (parent->isGlobal()) {
            if (shape->configurable()) {
                if (!parent->defineProperty(cx, name, rval,
                                            JS_PropertyStub, JS_StrictPropertyStub, attrs))
                {
                    THROW();
                }
                break;
            }

            if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
                JSAutoByteString bytes;
                if (js_AtomToPrintableString(cx, name, &bytes)) {
                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                         JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
                }
                THROW();
            }
        }

        /*
         * Non-global properties, and global properties which we aren't simply
         * redefining, must be set.  First, this preserves their attributes.
         * Second, this will produce warnings and/or errors as necessary if the
         * specified Call object property is not writable (const).
         */

        /* Step 5f. */
        if (!parent->setProperty(cx, name, &rval, strict))
            THROW();
    } while (false);
}
Example #6
0
void JS_FASTCALL
stubs::ScriptProbeOnlyEpilogue(VMFrame &f)
{
    AutoAssertNoGC nogc;
    Probes::exitScript(f.cx, f.script(), f.script()->function(), f.fp());
}
Example #7
0
static inline bool
UncachedInlineCall(VMFrame &f, InitialFrameFlags initial,
                   void **pret, bool *unjittable, uint32_t argc)
{
    AssertCanGC();
    JSContext *cx = f.cx;
    CallArgs args = CallArgsFromSp(argc, f.regs.sp);
    RootedFunction newfun(cx, args.callee().toFunction());

    RootedScript newscript(cx, newfun->getOrCreateScript(cx));
    if (!newscript)
        return false;

    bool construct = InitialFrameFlagsAreConstructing(initial);

    RootedScript fscript(cx, f.script());
    bool newType = construct && cx->typeInferenceEnabled() &&
        types::UseNewType(cx, fscript, f.pc());

    if (!types::TypeMonitorCall(cx, args, construct))
        return false;

    /* Try to compile if not already compiled. */
    if (ShouldJaegerCompileCallee(cx, f.script(), newscript, f.jit())) {
        CompileStatus status = CanMethodJIT(cx, newscript, newscript->code, construct,
                                            CompileRequest_JIT, f.fp());
        if (status == Compile_Error) {
            /* A runtime exception was thrown, get out. */
            return false;
        }
        if (status == Compile_Abort)
            *unjittable = true;
    }

    /*
     * Make sure we are not calling from an inline frame if we need to make a
     * call object for the callee, as doing so could trigger GC and cause
     * jitcode discarding / frame expansion.
     */
    if (f.regs.inlined() && newfun->isHeavyweight()) {
        ExpandInlineFrames(cx->compartment);
        JS_ASSERT(!f.regs.inlined());
    }

    /*
     * Preserve f.regs.fp while pushing the new frame, for the invariant that
     * f.regs reflects the state when we entered the stub call. This handoff is
     * tricky: we need to make sure that f.regs is not updated to the new
     * frame, and we also need to ensure that cx->regs still points to f.regs
     * when space is reserved, in case doing so throws an exception.
     */
    FrameRegs regs = f.regs;

    /* Get pointer to new frame/slots, prepare arguments. */
    if (!cx->stack.pushInlineFrame(cx, regs, args, *newfun, newscript, initial, &f.stackLimit))
        return false;

    /* Finish the handoff to the new frame regs. */
    PreserveRegsGuard regsGuard(cx, regs);

    /*
     * If newscript was successfully compiled, run it. Skip for calls which
     * will be constructing a new type object for 'this'.
     */
    if (!newType) {
        if (JITScript *jit = newscript->getJIT(regs.fp()->isConstructing(), cx->compartment->compileBarriers())) {
            if (jit->invokeEntry) {
                *pret = jit->invokeEntry;

                /* Restore the old fp around and let the JIT code repush the new fp. */
                regs.popFrame((Value *) regs.fp());
                return true;
            }
        }
    }

    /*
     * Otherwise, run newscript in the interpreter. Expand any inlined frame we
     * are calling from, as the new frame is not associated with the VMFrame
     * and will not have its prevpc info updated if frame expansion is
     * triggered while interpreting.
     */
    if (f.regs.inlined()) {
        ExpandInlineFrames(cx->compartment);
        JS_ASSERT(!f.regs.inlined());
        regs.fp()->resetInlinePrev(f.fp(), f.regs.pc);
    }

    JS_CHECK_RECURSION(cx, return false);

    RootedScript script(cx, newscript);
    bool ok = RunScript(cx, script, cx->fp());
    f.cx->stack.popInlineFrame(regs);

    if (ok) {
        RootedScript fscript(cx, f.script());
        types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
    }

    *pret = NULL;
    return ok;
}
Example #8
0
void JS_FASTCALL
stubs::ScriptProbeOnlyPrologue(VMFrame &f)
{
    Probes::enterScript(f.cx, f.script(), f.script()->function(), f.fp());
}