diff options
Diffstat (limited to 'js/src/jit/RematerializedFrame.h')
-rw-r--r-- | js/src/jit/RematerializedFrame.h | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/js/src/jit/RematerializedFrame.h b/js/src/jit/RematerializedFrame.h new file mode 100644 index 0000000000..06f0c475a2 --- /dev/null +++ b/js/src/jit/RematerializedFrame.h @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_RematerializedFrame_h +#define jit_RematerializedFrame_h + +#include "mozilla/Assertions.h" + +#include <algorithm> +#include <stddef.h> +#include <stdint.h> + +#include "jstypes.h" + +#include "jit/JitFrames.h" +#include "jit/ScriptFromCalleeToken.h" +#include "js/GCVector.h" +#include "js/TypeDecls.h" +#include "js/UniquePtr.h" +#include "js/Value.h" +#include "vm/JSFunction.h" +#include "vm/JSScript.h" +#include "vm/Stack.h" + +class JS_PUBLIC_API JSTracer; + +namespace js { + +class ArgumentsObject; +class CallObject; + +namespace jit { + +class InlineFrameIterator; +struct MaybeReadFallback; + +// RematerializedFrame: An optimized frame that has been rematerialized with +// values read out of Snapshots. +// +// If the Debugger API tries to inspect or modify an IonMonkey frame, much of +// the information it expects to find in a frame is missing: function calls may +// have been inlined, variables may have been optimized out, and so on. So when +// this happens, SpiderMonkey builds one or more Rematerialized frames from the +// IonMonkey frame, using the snapshot metadata built by Ion to reconstruct the +// missing parts. The Rematerialized frames are now the authority on the state +// of those frames, and the Ion frame is ignored: stack iterators ignore the Ion +// frame, producing the Rematerialized frames in their stead; and when control +// returns to the Ion frame, we pop it, rebuild Baseline frames from the +// Rematerialized frames, and resume execution in Baseline. +class RematerializedFrame { + // See DebugScopes::updateLiveScopes. + bool prevUpToDate_; + + // Propagated to the Baseline frame once this is popped. + bool isDebuggee_; + + // Has an initial environment has been pushed on the environment chain for + // function frames that need a CallObject or eval frames that need a + // VarEnvironmentObject? + bool hasInitialEnv_; + + // Is this frame constructing? + bool isConstructing_; + + // If true, this frame has been on the stack when + // |js::SavedStacks::saveCurrentStack| was called, and so there is a + // |js::SavedFrame| object cached for this frame. + bool hasCachedSavedFrame_; + + // The fp of the top frame associated with this possibly inlined frame. + uint8_t* top_; + + // The bytecode at the time of rematerialization. + jsbytecode* pc_; + + size_t frameNo_; + unsigned numActualArgs_; + + JSScript* script_; + JSObject* envChain_; + JSFunction* callee_; + ArgumentsObject* argsObj_; + + Value returnValue_; + Value thisArgument_; + Value slots_[1]; + + RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs, + InlineFrameIterator& iter, MaybeReadFallback& fallback); + + public: + static RematerializedFrame* New(JSContext* cx, uint8_t* top, + InlineFrameIterator& iter, + MaybeReadFallback& fallback); + + // RematerializedFrame are allocated on non-GC heap, so use GCVector and + // UniquePtr to ensure they are traced and cleaned up correctly. + using RematerializedFrameVector = GCVector<UniquePtr<RematerializedFrame>>; + + // Rematerialize all remaining frames pointed to by |iter| into |frames| + // in older-to-younger order, e.g., frames[0] is the oldest frame. + [[nodiscard]] static bool RematerializeInlineFrames( + JSContext* cx, uint8_t* top, InlineFrameIterator& iter, + MaybeReadFallback& fallback, RematerializedFrameVector& frames); + + bool prevUpToDate() const { return prevUpToDate_; } + void setPrevUpToDate() { prevUpToDate_ = true; } + void unsetPrevUpToDate() { prevUpToDate_ = false; } + + bool isDebuggee() const { return isDebuggee_; } + void setIsDebuggee() { isDebuggee_ = true; } + inline void unsetIsDebuggee(); + + uint8_t* top() const { return top_; } + JSScript* outerScript() const { + JitFrameLayout* jsFrame = (JitFrameLayout*)top_; + return ScriptFromCalleeToken(jsFrame->calleeToken()); + } + jsbytecode* pc() const { return pc_; } + size_t frameNo() const { return frameNo_; } + bool inlined() const { return frameNo_ > 0; } + + JSObject* environmentChain() const { return envChain_; } + + template <typename SpecificEnvironment> + void pushOnEnvironmentChain(SpecificEnvironment& env) { + MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment()); + envChain_ = &env; + if (IsFrameInitialEnvironment(this, env)) { + hasInitialEnv_ = true; + } + } + + template <typename SpecificEnvironment> + void popOffEnvironmentChain() { + MOZ_ASSERT(envChain_->is<SpecificEnvironment>()); + envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment(); + } + + [[nodiscard]] bool initFunctionEnvironmentObjects(JSContext* cx); + [[nodiscard]] bool pushVarEnvironment(JSContext* cx, Handle<Scope*> scope); + + bool hasInitialEnvironment() const { return hasInitialEnv_; } + CallObject& callObj() const; + + bool hasArgsObj() const { return !!argsObj_; } + ArgumentsObject& argsObj() const { + MOZ_ASSERT(hasArgsObj()); + MOZ_ASSERT(script()->needsArgsObj()); + return *argsObj_; + } + + bool isFunctionFrame() const { return script_->isFunction(); } + bool isGlobalFrame() const { return script_->isGlobalCode(); } + bool isModuleFrame() const { return script_->isModule(); } + + JSScript* script() const { return script_; } + JSFunction* callee() const { + MOZ_ASSERT(isFunctionFrame()); + MOZ_ASSERT(callee_); + return callee_; + } + Value calleev() const { return ObjectValue(*callee()); } + Value& thisArgument() { return thisArgument_; } + + bool isConstructing() const { return isConstructing_; } + + bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; } + + void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; } + + void clearHasCachedSavedFrame() { hasCachedSavedFrame_ = false; } + + unsigned numFormalArgs() const { + return isFunctionFrame() ? callee()->nargs() : 0; + } + unsigned numActualArgs() const { return numActualArgs_; } + unsigned numArgSlots() const { + return (std::max)(numFormalArgs(), numActualArgs()); + } + + Value* argv() { return slots_; } + Value* locals() { return slots_ + numArgSlots(); } + + Value& unaliasedLocal(unsigned i) { + MOZ_ASSERT(i < script()->nfixed()); + return locals()[i]; + } + Value& unaliasedFormal(unsigned i, + MaybeCheckAliasing checkAliasing = CHECK_ALIASING) { + MOZ_ASSERT(i < numFormalArgs()); + MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() && + !script()->formalIsAliased(i)); + return argv()[i]; + } + Value& unaliasedActual(unsigned i, + MaybeCheckAliasing checkAliasing = CHECK_ALIASING) { + MOZ_ASSERT(i < numActualArgs()); + MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); + MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), + !script()->formalIsAliased(i)); + return argv()[i]; + } + + void setReturnValue(const Value& value) { returnValue_ = value; } + + Value& returnValue() { + MOZ_ASSERT(!script()->noScriptRval()); + return returnValue_; + } + + void trace(JSTracer* trc); + void dump(); +}; + +} // namespace jit +} // namespace js + +#endif // jit_RematerializedFrame_h |