static void
MaybeInvalidateScriptUsedWithNew(JSRuntime *rt, types::TypeObject *type)
{
    types::TypeNewScript *newScript = type->newScript();
    if (!newScript)
        return;

    JSScript *script = newScript->fun->nonLazyScript();
    if (script && script->hasIonScript()) {
        for (ContextIter cx(rt); !cx.done(); cx.next())
            jit::Invalidate(cx, script);
    }
}
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObject* obj,
                                          ArgumentsData* data)
{
    JSScript* script = frame.script();
    if (frame.callee()->needsCallObject() && script->argumentsAliasesFormals()) {
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
        for (PositionalFormalParameterIter fi(script); fi; fi++) {
            if (fi.closedOver())
                data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
        }
    }
}
Beispiel #3
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout *frame, HandleObject callObj,
                                          ArgumentsObject *obj, ArgumentsData *data)
{
    JSFunction *callee = jit::CalleeTokenToFunction(frame->calleeToken());
    JSScript *script = callee->nonLazyScript();
    if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
        MOZ_ASSERT(callObj && callObj->is<CallObject>());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicScopeSlotValue(fi.scopeSlot());
    }
}
Beispiel #4
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj,
                                          JSObject *obj, ArgumentsData *data)
{
    JSFunction *callee = ion::CalleeTokenToFunction(frame->calleeToken());
    JSScript *script = callee->nonLazyScript();
    if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
        JS_ASSERT(callObj && callObj->isCall());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
    }
}
uint32
ion::ForceInvalidation()
{
    JSContext *cx = GetIonContext()->cx;
    JSScript *script = GetBailedJSScript(cx);

    JS_ASSERT(script->hasIonScript());
    JS_ASSERT(!script->ion->invalidated());

    IonSpew(IonSpew_Invalidate, "Forced invalidation bailout");

    return Invalidate(cx, script);
}
bool
GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
                        HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind)
{
    Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
    MOZ_ASSERT(genObj->isSuspended());

    RootedFunction callee(cx, &genObj->callee());
    RootedValue thisv(cx, genObj->thisValue());
    RootedValue newTarget(cx, genObj->newTarget());
    RootedObject scopeChain(cx, &genObj->scopeChain());
    if (!activation.resumeGeneratorFrame(callee, thisv, newTarget, scopeChain))
        return false;
    activation.regs().fp()->setResumedGenerator();

    if (genObj->hasArgsObj())
        activation.regs().fp()->initArgsObj(genObj->argsObj());

    if (genObj->hasExpressionStack()) {
        uint32_t len = genObj->expressionStack().length();
        MOZ_ASSERT(activation.regs().spForStackDepth(len));
        const Value* src = genObj->expressionStack().getDenseElements();
        mozilla::PodCopy(activation.regs().sp, src, len);
        activation.regs().sp += len;
        genObj->clearExpressionStack();
    }

    JSScript* script = callee->nonLazyScript();
    uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
    activation.regs().pc = script->offsetToPC(offset);

    // Always push on a value, even if we are raising an exception. In the
    // exception case, the stack needs to have something on it so that exception
    // handling doesn't skip the catch blocks. See TryNoteIter::settle.
    activation.regs().sp++;
    MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth()));
    activation.regs().sp[-1] = arg;

    switch (resumeKind) {
      case NEXT:
        genObj->setRunning();
        return true;

      case THROW:
      case CLOSE:
        return GeneratorThrowOrClose(cx, activation.regs().fp(), genObj, arg, resumeKind);

      default:
        MOZ_CRASH("bad resumeKind");
    }
}
Beispiel #7
0
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
                                   BailoutStack* bailout)
    : machine_(bailout->machineState())
{
    uint8_t* sp = bailout->parentStackPointer();
    framePointer_ = sp + bailout->frameSize();
    topFrameSize_ = framePointer_ - sp;

    JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken());
    topIonScript_ = script->ionScript();

    attachOnJitActivation(activations);
    snapshotOffset_ = bailout->snapshotOffset();
}
void * JS_FASTCALL
stubs::CompileFunction(VMFrame &f, uint32 nactual)
{
    /*
     * We have a partially constructed frame. That's not really good enough to
     * compile though because we could throw, so get a full, adjusted frame.
     */
    JSContext *cx = f.cx;
    StackFrame *fp = f.fp();

    /*
     * Since we can only use members set by initJitFrameCallerHalf,
     * we must carefully extract the callee from the nactual.
     */
    JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject();
    JSFunction *fun = callee.getFunctionPrivate();
    JSScript *script = fun->script();

    /* FixupArity expect to be called after the early prologue. */
    fp->initJitFrameEarlyPrologue(fun, nactual);

    if (nactual != fp->numFormalArgs()) {
        fp = (StackFrame *)FixupArity(f, nactual);
        if (!fp)
            return NULL;
    }

    /* Finish frame initialization. */
    if (!fp->initJitFrameLatePrologue(cx, &f.stackLimit))
        THROWV(NULL);

    /* These would have been initialized by the prologue. */
    f.regs.prepareToRun(*fp, script);

    if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp))
        THROWV(NULL);

    CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT);
    if (status == Compile_Okay)
        return script->getJIT(fp->isConstructing())->invokeEntry;

    /* Function did not compile... interpret it. */
    JSBool ok = Interpret(cx, fp);
    InlineReturn(f);

    if (!ok)
        THROWV(NULL);

    return NULL;
}
Beispiel #9
0
uint32_t
ion::ShapeGuardFailure()
{
    JSContext *cx = GetIonContext()->cx;
    JSScript *script = GetBailedJSScript(cx);

    JS_ASSERT(!script->ionScript()->invalidated());

    script->failedShapeGuard = true;

    IonSpew(IonSpew_Invalidate, "Invalidating due to shape guard failure");

    return Invalidate(cx, script);
}
Beispiel #10
0
 bool init(JSContext *cx) {
     JSC::ExecutablePool *pool = LinkerHelper::init(cx);
     if (!pool)
         return false;
     JS_ASSERT(!f.regs.inlined());
     JSScript *script = f.fp()->script();
     JITScript *jit = script->getJIT(f.fp()->isConstructing());
     if (!jit->execPools.append(pool)) {
         pool->release();
         js_ReportOutOfMemory(cx);
         return false;
     }
     return true;
 }
Beispiel #11
0
bool
TraceLoggerThread::enable(JSContext* cx)
{
    if (!enable())
        return fail(cx, "internal error");

    if (enabled_ == 1) {
        // Get the top Activation to log the top script/pc (No inlined frames).
        ActivationIterator iter(cx->runtime());
        Activation* act = iter.activation();

        if (!act)
            return fail(cx, "internal error");

        JSScript* script = nullptr;
        int32_t engine = 0;

        if (act->isJit()) {
            JitFrameIterator it(iter);

            while (!it.isScripted() && !it.done())
                ++it;

            MOZ_ASSERT(!it.done());
            MOZ_ASSERT(it.isIonJS() || it.isBaselineJS());

            script = it.script();
            engine = it.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
        } else if (act->isWasm()) {
            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL,
                                 "not yet supported in wasm code");
            return false;
        } else {
            MOZ_ASSERT(act->isInterpreter());
            InterpreterFrame* fp = act->asInterpreter()->current();
            MOZ_ASSERT(!fp->runningInJit());

            script = fp->script();
            engine = TraceLogger_Interpreter;
            if (script->compartment() != cx->compartment())
                return fail(cx, "compartment mismatch");
        }

        TraceLoggerEvent event(this, TraceLogger_Scripts, script);
        startEvent(event);
        startEvent(engine);
    }

    return true;
}
Beispiel #12
0
void
StackSpace::markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc)
{
    Value *slotsBegin = fp->slots();

    if (!fp->isScriptFrame()) {
        JS_ASSERT(fp->isDummyFrame());
        gc::MarkValueRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
        return;
    }

    /* If it's a scripted frame, we should have a pc. */
    JS_ASSERT(pc);

    JSScript *script = fp->script();
    if (!script->hasAnalysis() || !script->analysis()->ranLifetimes()) {
        gc::MarkValueRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
        return;
    }

    /*
     * If the JIT ran a lifetime analysis, then it may have left garbage in the
     * slots considered not live. We need to avoid marking them. Additionally,
     * in case the analysis information is thrown out later, we overwrite these
     * dead slots with valid values so that future GCs won't crash. Analysis
     * results are thrown away during the sweeping phase, so we always have at
     * least one GC to do this.
     */
    analyze::AutoEnterAnalysis aea(script->compartment());
    analyze::ScriptAnalysis *analysis = script->analysis();
    uint32_t offset = pc - script->code;
    Value *fixedEnd = slotsBegin + script->nfixed;
    for (Value *vp = slotsBegin; vp < fixedEnd; vp++) {
        uint32_t slot = analyze::LocalSlot(script, vp - slotsBegin);

        /*
         * Will this slot be synced by the JIT? If not, replace with a dummy
         * value with the same type tag.
         */
        if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset))
            gc::MarkValueRoot(trc, vp, "vm_stack");
        else if (vp->isObject())
            *vp = ObjectValue(fp->scopeChain()->global());
        else if (vp->isString())
            *vp = StringValue(trc->runtime->atomState.nullAtom);
    }

    gc::MarkValueRootRange(trc, fixedEnd, slotsEnd, "vm_stack");
}
Beispiel #13
0
void
GlobalObject::clear(JSContext *cx)
{
    for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
        setSlot(key, UndefinedValue());

    /* Clear regexp statics. */
    getRegExpStatics()->clear();

    /* Clear the runtime-codegen-enabled cache. */
    setSlot(RUNTIME_CODEGEN_ENABLED, UndefinedValue());

    /*
     * Clear the original-eval and [[ThrowTypeError]] slots, in case throwing
     * trying to execute a script for this global must reinitialize standard
     * classes.  See bug 470150.
     */
    setSlot(EVAL, UndefinedValue());
    setSlot(THROWTYPEERROR, UndefinedValue());

    /*
     * Mark global as cleared. If we try to execute any compile-and-go
     * scripts from here on, we will throw.
     */
    int32_t flags = getSlot(FLAGS).toInt32();
    flags |= FLAGS_CLEARED;
    setSlot(FLAGS, Int32Value(flags));

    /*
     * Reset the new object cache in the compartment, which assumes that
     * prototypes cached on the global object are immutable.
     */
    cx->runtime->newObjectCache.purge();

#ifdef JS_METHODJIT
    /*
     * Destroy compiled code for any scripts parented to this global. Call ICs
     * can directly call scripts which have associated JIT code, and do so
     * without checking whether the script's global has been cleared.
     */
    for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
        JSScript *script = i.get<JSScript>();
        if (script->compileAndGo && script->hasJITInfo() && script->hasClearedGlobal()) {
            mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), script);
            mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script);
        }
    }
#endif
}
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
                                          ArgumentsObject* obj, ArgumentsData* data)
{
    JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
    JSScript* script = callee->nonLazyScript();
    if (callee->needsCallObject() && script->argumentsAliasesFormals()) {
        MOZ_ASSERT(callObj && callObj->is<CallObject>());
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
        for (PositionalFormalParameterIter fi(script); fi; fi++) {
            if (fi.closedOver())
                data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
        }
    }
}
Beispiel #15
0
bool
GeneratorThrowOrClose(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
                      HandleValue arg, uint32_t resumeKind)
{
    // Set the frame's pc to the current resume pc, so that frame iterators
    // work. This function always returns false, so we're guaranteed to enter
    // the exception handler where we will clear the pc.
    JSScript* script = frame->script();
    uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
    frame->setOverridePc(script->offsetToPC(offset));

    MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
    MOZ_ALWAYS_FALSE(js::GeneratorThrowOrClose(cx, frame, genObj, arg, resumeKind));
    return false;
}
Beispiel #16
0
static int
typesCallback(void *passPtr, int argc, char **argv, char **azColName)
{
	unsigned long int *data = (unsigned long int *) passPtr;
	JSContext *context = (JSContext *)data[0];
	JSScript *script = (JSScript *)data[1];

	if (argc != 2)
		return -1;

	js::types::TypeScript::Monitor(context, script, script->offsetToPC(atoi(argv[0])), (js::types::Type)atoi(argv[1]));
	//printf("Updating types %s:%d:%d:%d:%d\n", script->filename(), script->lineno(), script->column(), atoi(argv[0]), atoi(argv[1]));

	return 0;
}
void
JSCompartment::purge(JSContext *cx)
{
    arenas.purge();
    dtoaCache.purge();

    /*
     * Clear the hash and reset all evalHashLink to null before the GC. This
     * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is
     * not null when we have script owned by an object and not from the eval
     * cache.
     */
    for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i) {
        for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
            JSScript *script = *listHeadp;
            JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
            *listHeadp = NULL;
            listHeadp = &script->u.evalHashLink;
        }
    }

    nativeIterCache.purge();
    toSourceCache.destroyIfConstructed();

#ifdef JS_TRACER
    /*
     * If we are about to regenerate shapes, we have to flush the JIT cache,
     * which will eventually abort any current recording.
     */
    if (cx->runtime->gcRegenShapes)
        if (hasTraceMonitor())
            traceMonitor()->needFlush = JS_TRUE;
#endif

#if defined JS_METHODJIT && defined JS_MONOIC
    /*
     * MICs do not refer to data which can be GC'ed and do not generate stubs
     * which might need to be discarded, but are sensitive to shape regeneration.
     */
    if (cx->runtime->gcRegenShapes) {
        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
            JSScript *script = i.get<JSScript>();
            if (script->hasJITCode())
                mjit::ic::PurgeMICs(cx, script);
        }
    }
#endif
}
Beispiel #18
0
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JSContext *cx = GetJSContextFromJitCode();
    JS_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 &&
               size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0,
               "Fake jitTop pointer should be within the first page.");
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
    gc::AutoSuppressGC suppress(cx);

    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations->asJit();

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Bailout);

    IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(),
                           iter.ionScript()->hasSPSInstrumentation());

        EnsureExitFrame(iter.jsFrame());
    }

    return retval;
}
Beispiel #19
0
JS::TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments)
{
    for (js::CompartmentsIter comp(trc->runtime(), SkipAtoms); !comp.done(); comp.next()) {
        if (compartments.has(comp))
            continue;

        for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
            const CrossCompartmentKey& key = e.front().key();
            JSObject* obj;
            JSScript* script;

            switch (key.kind) {
              case CrossCompartmentKey::StringWrapper:
                // StringWrappers are just used to avoid copying strings
                // across zones multiple times, and don't hold a strong
                // reference.
                continue;

              case CrossCompartmentKey::ObjectWrapper:
              case CrossCompartmentKey::DebuggerObject:
              case CrossCompartmentKey::DebuggerSource:
              case CrossCompartmentKey::DebuggerEnvironment:
              case CrossCompartmentKey::DebuggerWasmScript:
              case CrossCompartmentKey::DebuggerWasmSource:
                obj = static_cast<JSObject*>(key.wrapped);
                // Ignore CCWs whose wrapped value doesn't live in our given
                // set of zones.
                if (!compartments.has(obj->compartment()))
                    continue;

                TraceManuallyBarrieredEdge(trc, &obj, "cross-compartment wrapper");
                MOZ_ASSERT(obj == key.wrapped);
                break;

              case CrossCompartmentKey::DebuggerScript:
                script = static_cast<JSScript*>(key.wrapped);
                // Ignore CCWs whose wrapped value doesn't live in our given
                // set of compartments.
                if (!compartments.has(script->compartment()))
                    continue;

                TraceManuallyBarrieredEdge(trc, &script, "cross-compartment wrapper");
                MOZ_ASSERT(script == key.wrapped);
                break;
            }
        }
    }
}
Beispiel #20
0
static JSObject *
FreezeThaw(JSContext *cx, JS::HandleObject funobj)
{
    // freeze
    uint32_t nbytes;
    void *memory = JS_EncodeInterpretedFunction(cx, funobj, &nbytes);
    if (!memory)
        return nullptr;

    // thaw
    JSScript *script = GetScript(cx, funobj);
    JSObject *funobj2 = JS_DecodeInterpretedFunction(cx, memory, nbytes,
                                                     script->originPrincipals());
    js_free(memory);
    return funobj2;
}
Beispiel #21
0
/* static */ bool
EvalCacheHashPolicy::match(const EvalCacheEntry &cacheEntry, const EvalCacheLookup &l)
{
    JSScript *script = cacheEntry.script;

    JS_ASSERT(IsEvalCacheCandidate(script));

    // Get the source string passed for safekeeping in the atom map
    // by the prior eval to frontend::CompileScript.
    JSAtom *keyStr = script->atoms[0];

    return EqualStrings(keyStr, l.str) &&
           cacheEntry.callerScript == l.callerScript &&
           script->getVersion() == l.version &&
           cacheEntry.pc == l.pc;
}
Beispiel #22
0
void
ion::HandleException(ResumeFromException *rfe)
{
    JSContext *cx = GetIonContext()->cx;

    IonSpew(IonSpew_Invalidate, "handling exception");

    // Immediately remove any bailout frame guard that might be left over from
    // an error in between ConvertFrames and ThunkToInterpreter.
    js_delete(cx->runtime->ionActivation->maybeTakeBailout());

    IonFrameIterator iter(cx->runtime->ionTop);
    while (!iter.isEntry()) {
        if (iter.isScripted()) {
            // Search each inlined frame for live iterator objects, and close
            // them.
            InlineFrameIterator frames(&iter);
            for (;;) {
                CloseLiveIterators(cx, frames);

                // When profiling, each frame popped needs a notification that
                // the function has exited, so invoke the probe that a function
                // is exiting.
                JSScript *script = frames.script();
                Probes::exitScript(cx, script, script->function(), NULL);
                if (!frames.more())
                    break;
                ++frames;
            }

            IonScript *ionScript;
            if (iter.checkInvalidation(&ionScript))
                ionScript->decref(cx->runtime->defaultFreeOp());
        }

        ++iter;
    }

    // Clear any Ion return override that's been set.
    // This may happen if a callVM function causes an invalidation (setting the
    // override), and then fails, bypassing the bailout handlers that would
    // otherwise clear the return override.
    if (cx->runtime->hasIonReturnOverride())
        cx->runtime->takeIonReturnOverride();

    rfe->stackPointer = iter.fp();
}
Beispiel #23
0
void
InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
{
    MOZ_ASSERT(sp >= slots());

    JSScript *script = this->script();
    size_t nfixed = script->nfixed();
    size_t nlivefixed = script->nbodyfixed();

    if (nfixed != nlivefixed) {
        NestedScopeObject *staticScope = script->getStaticScope(pc);
        while (staticScope && !staticScope->is<StaticBlockObject>())
            staticScope = staticScope->enclosingNestedScope();

        if (staticScope) {
            StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
            nlivefixed = blockObj.localOffset() + blockObj.numVariables();
        }
    }

    MOZ_ASSERT(nlivefixed <= nfixed);
    MOZ_ASSERT(nlivefixed >= script->nbodyfixed());

    if (nfixed == nlivefixed) {
        // All locals are live.
        markValues(trc, 0, sp - slots());
    } else {
        // Mark operand stack.
        markValues(trc, nfixed, sp - slots());

        // Clear dead block-scoped locals.
        while (nfixed > nlivefixed)
            unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL);

        // Mark live locals.
        markValues(trc, 0, nlivefixed);
    }

    if (hasArgs()) {
        // Mark callee, |this| and arguments.
        unsigned argc = Max(numActualArgs(), numFormalArgs());
        gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv");
    } else {
        // Mark callee and |this|
        gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
    }
}
Beispiel #24
0
bool
CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
{
    rval.set(MagicValue(JS_IS_CONSTRUCTING));

    if (callee->isFunction()) {
        JSFunction *fun = callee->toFunction();
        if (fun->isInterpreted()) {
            JSScript *script = fun->getOrCreateScript(cx);
            if (!script || !script->ensureHasTypes(cx))
                return false;
            rval.set(ObjectValue(*CreateThisForFunction(cx, callee, false)));
        }
    }

    return true;
}
Beispiel #25
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);
}
Beispiel #26
0
    virtual bool parallel(ForkJoinSlice &slice) {
#ifndef JS_ION
        JS_NOT_REACHED("Parallel execution without ion");
        return false;
#else
        Spew(SpewOps, "Up");

        // Make a new IonContext for the slice, which is needed if we need to
        // re-enter the VM.
        IonContext icx(cx_, NULL);

        JS_ASSERT(pendingInvalidations[slice.sliceId] == NULL);

        JS_ASSERT(fun_->isFunction());
        RootedFunction callee(cx_, fun_->toFunction());
        if (!callee->nonLazyScript()->hasParallelIonScript()) {
            // Sometimes, particularly with GCZeal, the parallel ion
            // script can be collected between starting the parallel
            // op and reaching this point.  In that case, we just fail
            // and fallback.
            Spew(SpewOps, "Down (Script no longer present)");
            return false;
        }

        ParallelIonInvoke<3> fii(cx_, callee, 3);

        fii.args[0] = Int32Value(slice.sliceId);
        fii.args[1] = Int32Value(slice.numSlices);
        fii.args[2] = BooleanValue(false);

        bool ok = fii.invoke(cx_);
        JS_ASSERT(ok == !slice.abortedScript);
        if (!ok) {
            JSScript *script = slice.abortedScript;
            Spew(SpewBailouts, "Aborted script: %p (hasParallelIonScript? %d)",
                 script, script->hasParallelIonScript());
            JS_ASSERT(script->hasParallelIonScript());
            pendingInvalidations[slice.sliceId] = script;
        }

        Spew(SpewOps, "Down");

        return ok;
#endif // JS_ION
    }
Beispiel #27
0
uint32
ion::CachedShapeGuardFailure()
{
    JSContext *cx = GetIonContext()->cx;
    JSScript *script = GetBailedJSScript(cx);

    JS_ASSERT(script->hasIonScript());
    JS_ASSERT(!script->ion->invalidated());

    // Purge JM caches in the script and all inlined script, to avoid baking in
    // the same shape guard next time.
    for (size_t i = 0; i < script->ion->scriptEntries(); i++)
        mjit::PurgeCaches(script->ion->getScript(i));

    IonSpew(IonSpew_Invalidate, "Invalidating due to shape guard failure");

    return Invalidate(cx, script);
}
/*
 * Interprets until either a safe point is reached that has method JIT'd
 * code, or the current frame tries to return.
 */
static inline JSBool
PartialInterpret(VMFrame &f)
{
    JSContext *cx = f.cx;
    JSStackFrame *fp = cx->fp();

#ifdef DEBUG
    JSScript *script = fp->script();
    JS_ASSERT(!fp->finishedInInterpreter());
    JS_ASSERT(fp->hasImacropc() ||
              !script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc));
#endif

    JSBool ok = JS_TRUE;
    ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);

    return ok;
}
uint32
ion::RecompileForInlining()
{
    JSContext *cx = GetIonContext()->cx;
    JSScript *script = cx->fp()->script();

    IonSpew(IonSpew_Inlining, "Recompiling script to inline calls %s:%d", script->filename,
            script->lineno);

    // Invalidate the script to force a recompile.
    if (!Invalidate(cx, script, /* resetUses */ false))
        return BAILOUT_RETURN_FATAL_ERROR;

    // Invalidation should not reset the use count.
    JS_ASSERT(script->getUseCount() >= js_IonOptions.usesBeforeInlining);

    return true;
}
Beispiel #30
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);
}