static inline uintptr_t ReadAllocation(const IonFrameIterator &frame, const LAllocation *a) { if (a->isGeneralReg()) { Register reg = a->toGeneralReg()->reg(); return frame.machineState().read(reg); } if (a->isStackSlot()) { uint32 slot = a->toStackSlot()->slot(); return *frame.jsFrame()->slotRef(slot); } uint32 index = a->toArgument()->index(); uint8 *argv = reinterpret_cast<uint8 *>(frame.jsFrame()->argv()); return *reinterpret_cast<uintptr_t *>(argv + index); }
SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter) : SnapshotReader(iter.ionScript()->snapshots() + iter.osiIndex()->snapshotOffset(), iter.ionScript()->snapshots() + iter.ionScript()->snapshotsSize()), fp_(iter.jsFrame()), machine_(iter.machineState()), ionScript_(iter.ionScript()) { }
IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, const IonFrameIterator &frame) : IonFrameIterator(activations), machine_(frame.machineState()) { returnAddressToFp_ = frame.returnAddressToFp(); topIonScript_ = frame.ionScript(); const OsiIndex *osiIndex = frame.osiIndex(); current_ = (uint8_t *) frame.fp(); type_ = IonFrame_OptimizedJS; topFrameSize_ = frame.frameSize(); snapshotOffset_ = osiIndex->snapshotOffset(); }
static void MarkIonExitFrame(JSTracer *trc, const IonFrameIterator &frame) { IonExitFooterFrame *footer = frame.exitFrame()->footer(); // Mark the code of the code handling the exit path. This is needed because // invalidated script are no longer marked because data are erased by the // invalidation and relocation data are no longer reliable. So the VM // wrapper or the invalidation code may be GC if no IonCode keep reference // on them. JS_ASSERT(uintptr_t(footer->ionCode()) != uintptr_t(-1)); // This correspond to the case where we have build a fake exit frame in // CodeGenerator.cpp which handle the case of a native function call. We // need to mark the argument vector of the function call. if (frame.isNative()) { IonNativeExitFrameLayout *native = frame.exitFrame()->nativeExit(); size_t len = native->argc() + 2; Value *vp = native->vp(); gc::MarkValueRootRange(trc, len, vp, "ion-native-args"); return; } if (frame.isOOLNativeGetter()) { IonOOLNativeGetterExitFrameLayout *oolgetter = frame.exitFrame()->oolNativeGetterExit(); gc::MarkIonCodeRoot(trc, oolgetter->stubCode(), "ion-ool-getter-code"); gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-getter-callee"); gc::MarkValueRoot(trc, oolgetter->thisp(), "ion-ool-getter-this"); return; } if (frame.isOOLPropertyOp()) { IonOOLPropertyOpExitFrameLayout *oolgetter = frame.exitFrame()->oolPropertyOpExit(); gc::MarkIonCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code"); gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp"); gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id"); gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj"); return; } if (frame.isDOMExit()) { IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit(); gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args"); if (dom->isSetterFrame()) { gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args"); } else if (dom->isMethodFrame()) { IonDOMMethodExitFrameLayout *method = reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom); size_t len = method->argc() + 2; Value *vp = method->vp(); gc::MarkValueRootRange(trc, len, vp, "ion-dom-args"); } return; } MarkIonCodeRoot(trc, footer->addressOfIonCode(), "ion-exit-code"); const VMFunction *f = footer->function(); if (f == NULL || f->explicitArgs == 0) return; // Mark arguments of the VM wrapper. uint8 *argBase = frame.exitFrame()->argBase(); for (uint32 explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) { switch (f->argRootType(explicitArg)) { case VMFunction::RootNone: break; case VMFunction::RootObject: { // Sometimes we can bake in HandleObjects to NULL. JSObject **pobj = reinterpret_cast<JSObject **>(argBase); if (*pobj) gc::MarkObjectRoot(trc, pobj, "ion-vm-args"); break; } case VMFunction::RootString: case VMFunction::RootPropertyName: gc::MarkStringRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args"); break; case VMFunction::RootFunction: gc::MarkObjectRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args"); break; case VMFunction::RootValue: gc::MarkValueRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args"); break; case VMFunction::RootCell: gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(argBase), "ion-vm-args"); break; } switch (f->argProperties(explicitArg)) { case VMFunction::WordByValue: case VMFunction::WordByRef: argBase += sizeof(void *); break; case VMFunction::DoubleByValue: case VMFunction::DoubleByRef: argBase += 2 * sizeof(void *); break; } } if (f->outParam == Type_Handle) gc::MarkValueRoot(trc, footer->outVp(), "ion-vm-outvp"); }
static void MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame) { // Currently, this code only executes in sequential execution. CompileMode compileMode = COMPILE_MODE_SEQ; IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp(); MarkCalleeToken(trc, layout->calleeToken()); IonScript *ionScript; if (frame.checkInvalidation(&ionScript)) { // This frame has been invalidated, meaning that its IonScript is no // longer reachable through the callee token (JSFunction/JSScript->ion // is now NULL or recompiled). Manually trace it here. IonScript::Trace(trc, ionScript); } else if (CalleeTokenIsFunction(layout->calleeToken())) { ionScript = CalleeTokenToFunction(layout->calleeToken())->script()->ions[compileMode]; } else { ionScript = CalleeTokenToScript(layout->calleeToken())->ions[compileMode]; } if (CalleeTokenIsFunction(layout->calleeToken())) { // (NBP) We do not need to mark formal arguments since they are covered // by the safepoint. size_t nargs = frame.numActualArgs(); // Trace function arguments. Note + 1 for thisv. Value *argv = layout->argv(); for (size_t i = 0; i < nargs + 1; i++) gc::MarkValueRoot(trc, &argv[i], "ion-argv"); } const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp()); SafepointReader safepoint(ionScript, si); // Scan through slots which contain pointers (or on punboxing systems, // actual values). uint32 slot; while (safepoint.getGcSlot(&slot)) { uintptr_t *ref = layout->slotRef(slot); gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(ref), "ion-gc-slot"); } while (safepoint.getValueSlot(&slot)) { Value *v = (Value *)layout->slotRef(slot); gc::MarkValueRoot(trc, v, "ion-gc-slot"); } uintptr_t *spill = frame.spillBase(); GeneralRegisterSet gcRegs = safepoint.gcSpills(); GeneralRegisterSet valueRegs = safepoint.valueSpills(); for (GeneralRegisterIterator iter(safepoint.allSpills()); iter.more(); iter++) { --spill; if (gcRegs.has(*iter)) gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill"); else if (valueRegs.has(*iter)) gc::MarkValueRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill"); } #ifdef JS_NUNBOX32 LAllocation type, payload; while (safepoint.getNunboxSlot(&type, &payload)) { jsval_layout layout; layout.s.tag = (JSValueTag)ReadAllocation(frame, &type); layout.s.payload.uintptr = ReadAllocation(frame, &payload); Value v = IMPL_TO_JSVAL(layout); gc::MarkValueRoot(trc, &v, "ion-torn-value"); JS_ASSERT(v == IMPL_TO_JSVAL(layout)); } #endif }
void BaselineFrame::trace(JSTracer *trc, IonFrameIterator &frameIterator) { replaceCalleeToken(MarkCalleeToken(trc, calleeToken())); gc::MarkValueRoot(trc, &thisValue(), "baseline-this"); // Mark actual and formal args. if (isNonEvalFunctionFrame()) { unsigned numArgs = js::Max(numActualArgs(), numFormalArgs()); gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args"); } // Mark scope chain, if it exists. if (scopeChain_) gc::MarkObjectRoot(trc, &scopeChain_, "baseline-scopechain"); // Mark return value. if (hasReturnValue()) gc::MarkValueRoot(trc, returnValue().address(), "baseline-rval"); if (isEvalFrame()) gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript"); if (hasArgsObj()) gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj"); // Mark locals and stack values. JSScript *script = this->script(); size_t nfixed = script->nfixed(); size_t nlivefixed = script->nfixedvars(); if (nfixed != nlivefixed) { jsbytecode *pc; NestedScopeObject *staticScope; frameIterator.baselineScriptAndPc(nullptr, &pc); staticScope = script->getStaticScope(pc); while (staticScope && !staticScope->is<StaticBlockObject>()) staticScope = staticScope->enclosingNestedScope(); if (staticScope) { StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } } JS_ASSERT(nlivefixed <= nfixed); JS_ASSERT(nlivefixed >= script->nfixedvars()); // NB: It is possible that numValueSlots() could be zero, even if nfixed is // nonzero. This is the case if the function has an early stack check. if (numValueSlots() == 0) return; JS_ASSERT(nfixed <= numValueSlots()); if (nfixed == nlivefixed) { // All locals are live. MarkLocals(this, trc, 0, numValueSlots()); } else { // Mark operand stack. MarkLocals(this, trc, nfixed, numValueSlots()); // Clear dead locals. while (nfixed > nlivefixed) unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined(); // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); } }