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()); } } }
/* 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()); } }
/* 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"); } }
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; }
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); }
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; }
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; }
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"); }
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()); } } }
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; }
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 }
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; }
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; } } } }
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; }
/* 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; }
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(); }
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"); } }
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; }
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); }
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 }
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; }
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); }