summaryrefslogtreecommitdiffstats
path: root/js/src/jit/RematerializedFrame.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/RematerializedFrame.h')
-rw-r--r--js/src/jit/RematerializedFrame.h222
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