BaselineFrame.cpp (5877B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/BaselineFrame-inl.h" 8 9 #include <algorithm> 10 11 #include "debugger/DebugAPI.h" 12 #include "vm/EnvironmentObject.h" 13 #include "vm/JSContext.h" 14 15 #include "jit/JSJitFrameIter-inl.h" 16 #include "vm/Stack-inl.h" 17 18 using namespace js; 19 using namespace js::jit; 20 21 static void TraceLocals(BaselineFrame* frame, JSTracer* trc, unsigned start, 22 unsigned end) { 23 if (start < end) { 24 // Stack grows down. 25 Value* last = frame->valueSlot(end - 1); 26 TraceRootRange(trc, end - start, last, "baseline-stack"); 27 } 28 } 29 30 void BaselineFrame::trace(JSTracer* trc, const JSJitFrameIter& frameIterator) { 31 replaceCalleeToken(TraceCalleeToken(trc, calleeToken())); 32 33 // Trace |this|, actual and formal args. 34 if (isFunctionFrame()) { 35 TraceRoot(trc, &thisArgument(), "baseline-this"); 36 37 unsigned numArgs = std::max(numActualArgs(), numFormalArgs()); 38 TraceRootRange(trc, numArgs + isConstructing(), argv(), "baseline-args"); 39 } 40 41 // Trace environment chain, if it exists. 42 if (envChain_) { 43 TraceRoot(trc, &envChain_, "baseline-envchain"); 44 } 45 46 // Trace return value. 47 if (hasReturnValue()) { 48 TraceRoot(trc, returnValue().address(), "baseline-rval"); 49 } 50 51 if (hasArgsObj()) { 52 TraceRoot(trc, &argsObj_, "baseline-args-obj"); 53 } 54 55 mozilla::DebugOnly<bool> isBaselineSelfHosted = 56 this->script()->selfHosted() && !runningInInterpreter(); 57 MOZ_ASSERT_IF( 58 JS::Prefs::experimental_self_hosted_cache() && isBaselineSelfHosted, 59 isRealmIndependent()); 60 if (runningInInterpreter() || isRealmIndependent()) { 61 TraceRoot(trc, &interpreterScript_, "baseline-interpreterScript"); 62 } 63 64 // Trace locals and stack values. 65 JSScript* script = this->script(); 66 size_t nfixed = script->nfixed(); 67 jsbytecode* pc; 68 frameIterator.baselineScriptAndPc(nullptr, &pc); 69 size_t nlivefixed = script->calculateLiveFixed(pc); 70 71 uint32_t numValueSlots = frameIterator.baselineFrameNumValueSlots(); 72 73 // NB: It is possible that numValueSlots could be zero, even if nfixed is 74 // nonzero. This is the case when we're initializing the environment chain or 75 // failed the prologue stack check. 76 if (numValueSlots > 0) { 77 MOZ_ASSERT(nfixed <= numValueSlots); 78 79 if (nfixed == nlivefixed) { 80 // All locals are live. 81 TraceLocals(this, trc, 0, numValueSlots); 82 } else { 83 // Trace operand stack. 84 TraceLocals(this, trc, nfixed, numValueSlots); 85 86 // Clear dead block-scoped locals. 87 while (nfixed > nlivefixed) { 88 unaliasedLocal(--nfixed).setUndefined(); 89 } 90 91 // Trace live locals. 92 TraceLocals(this, trc, 0, nlivefixed); 93 } 94 } 95 96 if (auto* debugEnvs = script->realm()->debugEnvs()) { 97 debugEnvs->traceLiveFrame(trc, this); 98 } 99 } 100 101 bool BaselineFrame::uninlineIsProfilerSamplingEnabled(JSContext* cx) { 102 return cx->isProfilerSamplingEnabled(); 103 } 104 105 bool BaselineFrame::initFunctionEnvironmentObjects(JSContext* cx) { 106 return js::InitFunctionEnvironmentObjects(cx, this); 107 } 108 109 bool BaselineFrame::pushVarEnvironment(JSContext* cx, Handle<Scope*> scope) { 110 return js::PushVarEnvironmentObject(cx, scope, this); 111 } 112 113 void BaselineFrame::setInterpreterFields(JSScript* script, jsbytecode* pc) { 114 uint32_t pcOffset = script->pcToOffset(pc); 115 interpreterScript_ = script; 116 interpreterPC_ = pc; 117 MOZ_ASSERT(icScript_); 118 interpreterICEntry_ = icScript_->interpreterICEntryFromPCOffset(pcOffset); 119 } 120 121 void BaselineFrame::setInterpreterFieldsForPrologue(JSScript* script) { 122 interpreterScript_ = script; 123 interpreterPC_ = script->code(); 124 if (icScript_->numICEntries() > 0) { 125 interpreterICEntry_ = &icScript_->icEntry(0); 126 } else { 127 // If the script does not have any ICEntries (possible for non-function 128 // scripts) the interpreterICEntry_ field won't be used. Just set it to 129 // nullptr. 130 interpreterICEntry_ = nullptr; 131 } 132 } 133 134 bool BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues) { 135 mozilla::PodZero(this); 136 137 envChain_ = fp->environmentChain(); 138 139 if (fp->hasInitialEnvironmentUnchecked()) { 140 flags_ |= BaselineFrame::HAS_INITIAL_ENV; 141 } 142 143 if (fp->script()->needsArgsObj() && fp->hasArgsObj()) { 144 flags_ |= BaselineFrame::HAS_ARGS_OBJ; 145 argsObj_ = &fp->argsObj(); 146 } 147 148 if (fp->hasReturnValue()) { 149 setReturnValue(fp->returnValue()); 150 } 151 152 icScript_ = fp->script()->jitScript()->icScript(); 153 154 JSContext* cx = 155 fp->script()->runtimeFromMainThread()->mainContextFromOwnThread(); 156 157 Activation* interpActivation = cx->activation()->prev(); 158 jsbytecode* pc = interpActivation->asInterpreter()->regs().pc; 159 MOZ_ASSERT(fp->script()->containsPC(pc)); 160 161 // We are doing OSR into the Baseline Interpreter. We can get the pc from the 162 // C++ interpreter's activation, we just have to skip the JitActivation. 163 flags_ |= BaselineFrame::RUNNING_IN_INTERPRETER; 164 setInterpreterFields(pc); 165 166 #ifdef DEBUG 167 debugFrameSize_ = frameSizeForNumValueSlots(numStackValues); 168 MOZ_ASSERT(debugNumValueSlots() == numStackValues); 169 #endif 170 171 for (uint32_t i = 0; i < numStackValues; i++) { 172 *valueSlot(i) = fp->slots()[i]; 173 } 174 175 // The InterpreterFrame won't be used anymore, but a GC might still trace it. 176 // Clear its stack slots to avoid keeping GC things alive. 177 std::fill_n(fp->slots(), numStackValues, UndefinedValue()); 178 179 if (fp->isDebuggee()) { 180 // For debuggee frames, update any Debugger.Frame objects for the 181 // InterpreterFrame to point to the BaselineFrame. 182 if (!DebugAPI::handleBaselineOsr(cx, fp, this)) { 183 return false; 184 } 185 setIsDebuggee(); 186 } 187 188 return true; 189 }