1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
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 #ifndef jit_RematerializedFrame_h
8 #define jit_RematerializedFrame_h
9 
10 #include <algorithm>
11 
12 #include "jit/JitFrames.h"
13 #include "jit/JSJitFrameIter.h"
14 #include "vm/EnvironmentObject.h"
15 #include "vm/JSFunction.h"
16 #include "vm/Stack.h"
17 
18 namespace js {
19 namespace jit {
20 
21 //
22 // An optimized frame that has been rematerialized with values read out of
23 // Snapshots.
24 //
25 class RematerializedFrame {
26   // See DebugScopes::updateLiveScopes.
27   bool prevUpToDate_;
28 
29   // Propagated to the Baseline frame once this is popped.
30   bool isDebuggee_;
31 
32   // Has an initial environment has been pushed on the environment chain for
33   // function frames that need a CallObject or eval frames that need a
34   // VarEnvironmentObject?
35   bool hasInitialEnv_;
36 
37   // Is this frame constructing?
38   bool isConstructing_;
39 
40   // If true, this frame has been on the stack when
41   // |js::SavedStacks::saveCurrentStack| was called, and so there is a
42   // |js::SavedFrame| object cached for this frame.
43   bool hasCachedSavedFrame_;
44 
45   // The fp of the top frame associated with this possibly inlined frame.
46   uint8_t* top_;
47 
48   // The bytecode at the time of rematerialization.
49   jsbytecode* pc_;
50 
51   size_t frameNo_;
52   unsigned numActualArgs_;
53 
54   JSScript* script_;
55   JSObject* envChain_;
56   JSFunction* callee_;
57   ArgumentsObject* argsObj_;
58 
59   Value returnValue_;
60   Value thisArgument_;
61   Value newTarget_;
62   Value slots_[1];
63 
64   RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs,
65                       InlineFrameIterator& iter, MaybeReadFallback& fallback);
66 
67  public:
68   static RematerializedFrame* New(JSContext* cx, uint8_t* top,
69                                   InlineFrameIterator& iter,
70                                   MaybeReadFallback& fallback);
71 
72   // Rematerialize all remaining frames pointed to by |iter| into |frames|
73   // in older-to-younger order, e.g., frames[0] is the oldest frame.
74   static MOZ_MUST_USE bool RematerializeInlineFrames(
75       JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
76       MaybeReadFallback& fallback, GCVector<RematerializedFrame*>& frames);
77 
78   // Free a vector of RematerializedFrames; takes care to call the
79   // destructor. Also clears the vector.
80   static void FreeInVector(GCVector<RematerializedFrame*>& frames);
81 
prevUpToDate()82   bool prevUpToDate() const { return prevUpToDate_; }
setPrevUpToDate()83   void setPrevUpToDate() { prevUpToDate_ = true; }
unsetPrevUpToDate()84   void unsetPrevUpToDate() { prevUpToDate_ = false; }
85 
isDebuggee()86   bool isDebuggee() const { return isDebuggee_; }
setIsDebuggee()87   void setIsDebuggee() { isDebuggee_ = true; }
unsetIsDebuggee()88   void unsetIsDebuggee() {
89     MOZ_ASSERT(!script()->isDebuggee());
90     isDebuggee_ = false;
91   }
92 
top()93   uint8_t* top() const { return top_; }
outerScript()94   JSScript* outerScript() const {
95     JitFrameLayout* jsFrame = (JitFrameLayout*)top_;
96     return ScriptFromCalleeToken(jsFrame->calleeToken());
97   }
pc()98   jsbytecode* pc() const { return pc_; }
frameNo()99   size_t frameNo() const { return frameNo_; }
inlined()100   bool inlined() const { return frameNo_ > 0; }
101 
environmentChain()102   JSObject* environmentChain() const { return envChain_; }
103 
104   template <typename SpecificEnvironment>
pushOnEnvironmentChain(SpecificEnvironment & env)105   void pushOnEnvironmentChain(SpecificEnvironment& env) {
106     MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment());
107     envChain_ = &env;
108     if (IsFrameInitialEnvironment(this, env)) hasInitialEnv_ = true;
109   }
110 
111   template <typename SpecificEnvironment>
popOffEnvironmentChain()112   void popOffEnvironmentChain() {
113     MOZ_ASSERT(envChain_->is<SpecificEnvironment>());
114     envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment();
115   }
116 
117   MOZ_MUST_USE bool initFunctionEnvironmentObjects(JSContext* cx);
118   MOZ_MUST_USE bool pushVarEnvironment(JSContext* cx, HandleScope scope);
119 
hasInitialEnvironment()120   bool hasInitialEnvironment() const { return hasInitialEnv_; }
121   CallObject& callObj() const;
122 
hasArgsObj()123   bool hasArgsObj() const { return !!argsObj_; }
argsObj()124   ArgumentsObject& argsObj() const {
125     MOZ_ASSERT(hasArgsObj());
126     MOZ_ASSERT(script()->needsArgsObj());
127     return *argsObj_;
128   }
129 
isFunctionFrame()130   bool isFunctionFrame() const { return !!script_->functionNonDelazifying(); }
isGlobalFrame()131   bool isGlobalFrame() const { return script_->isGlobalCode(); }
isModuleFrame()132   bool isModuleFrame() const { return script_->module(); }
133 
script()134   JSScript* script() const { return script_; }
callee()135   JSFunction* callee() const {
136     MOZ_ASSERT(isFunctionFrame());
137     MOZ_ASSERT(callee_);
138     return callee_;
139   }
calleev()140   Value calleev() const { return ObjectValue(*callee()); }
thisArgument()141   Value& thisArgument() { return thisArgument_; }
142 
isConstructing()143   bool isConstructing() const { return isConstructing_; }
144 
hasCachedSavedFrame()145   bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }
146 
setHasCachedSavedFrame()147   void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }
148 
numFormalArgs()149   unsigned numFormalArgs() const {
150     return isFunctionFrame() ? callee()->nargs() : 0;
151   }
numActualArgs()152   unsigned numActualArgs() const { return numActualArgs_; }
numArgSlots()153   unsigned numArgSlots() const {
154     return (std::max)(numFormalArgs(), numActualArgs());
155   }
156 
argv()157   Value* argv() { return slots_; }
locals()158   Value* locals() { return slots_ + numArgSlots(); }
159 
unaliasedLocal(unsigned i)160   Value& unaliasedLocal(unsigned i) {
161     MOZ_ASSERT(i < script()->nfixed());
162     return locals()[i];
163   }
164   Value& unaliasedFormal(unsigned i,
165                          MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
166     MOZ_ASSERT(i < numFormalArgs());
167     MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
168                                      !script()->formalIsAliased(i));
169     return argv()[i];
170   }
171   Value& unaliasedActual(unsigned i,
172                          MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
173     MOZ_ASSERT(i < numActualArgs());
174     MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
175     MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(),
176                   !script()->formalIsAliased(i));
177     return argv()[i];
178   }
179 
newTarget()180   Value newTarget() {
181     MOZ_ASSERT(isFunctionFrame());
182     if (callee()->isArrow())
183       return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
184     MOZ_ASSERT_IF(!isConstructing(), newTarget_.isUndefined());
185     return newTarget_;
186   }
187 
setReturnValue(const Value & value)188   void setReturnValue(const Value& value) { returnValue_ = value; }
189 
returnValue()190   Value& returnValue() { return returnValue_; }
191 
192   void trace(JSTracer* trc);
193   void dump();
194 };
195 
196 }  // namespace jit
197 }  // namespace js
198 
199 namespace JS {
200 
201 template <>
202 struct MapTypeToRootKind<js::jit::RematerializedFrame*> {
203   static const RootKind kind = RootKind::Traceable;
204 };
205 
206 template <>
207 struct GCPolicy<js::jit::RematerializedFrame*>
208     : public NonGCPointerPolicy<js::jit::RematerializedFrame*> {};
209 
210 }  // namespace JS
211 
212 #endif  // jit_RematerializedFrame_h
213