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 #include "jit/RematerializedFrame.h"
8 
9 #include "jit/JitFrames.h"
10 #include "vm/ArgumentsObject.h"
11 #include "vm/Debugger.h"
12 
13 #include "jit/JitFrames-inl.h"
14 #include "vm/EnvironmentObject-inl.h"
15 #include "vm/JSScript-inl.h"
16 
17 using namespace js;
18 using namespace jit;
19 
20 struct CopyValueToRematerializedFrame {
21   Value* slots;
22 
CopyValueToRematerializedFrameCopyValueToRematerializedFrame23   explicit CopyValueToRematerializedFrame(Value* slots) : slots(slots) {}
24 
operator ()CopyValueToRematerializedFrame25   void operator()(const Value& v) { *slots++ = v; }
26 };
27 
RematerializedFrame(JSContext * cx,uint8_t * top,unsigned numActualArgs,InlineFrameIterator & iter,MaybeReadFallback & fallback)28 RematerializedFrame::RematerializedFrame(JSContext* cx, uint8_t* top,
29                                          unsigned numActualArgs,
30                                          InlineFrameIterator& iter,
31                                          MaybeReadFallback& fallback)
32     : prevUpToDate_(false),
33       isDebuggee_(iter.script()->isDebuggee()),
34       isConstructing_(iter.isConstructing()),
35       hasCachedSavedFrame_(false),
36       top_(top),
37       pc_(iter.pc()),
38       frameNo_(iter.frameNo()),
39       numActualArgs_(numActualArgs),
40       script_(iter.script()) {
41   if (iter.isFunctionFrame())
42     callee_ = iter.callee(fallback);
43   else
44     callee_ = nullptr;
45 
46   CopyValueToRematerializedFrame op(slots_);
47   iter.readFrameArgsAndLocals(cx, op, op, &envChain_, &hasInitialEnv_,
48                               &returnValue_, &argsObj_, &thisArgument_,
49                               &newTarget_, ReadFrame_Actuals, fallback);
50 }
51 
New(JSContext * cx,uint8_t * top,InlineFrameIterator & iter,MaybeReadFallback & fallback)52 /* static */ RematerializedFrame* RematerializedFrame::New(
53     JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
54     MaybeReadFallback& fallback) {
55   unsigned numFormals =
56       iter.isFunctionFrame() ? iter.calleeTemplate()->nargs() : 0;
57   unsigned argSlots = Max(numFormals, iter.numActualArgs());
58   unsigned extraSlots = argSlots + iter.script()->nfixed();
59 
60   // One Value slot is included in sizeof(RematerializedFrame), so we can
61   // reduce the extra slot count by one.  However, if there are zero slot
62   // allocations total, then reducing the slots by one will lead to
63   // the memory allocation being smaller  than sizeof(RematerializedFrame).
64   if (extraSlots > 0) extraSlots -= 1;
65 
66   size_t numBytes = sizeof(RematerializedFrame) + (extraSlots * sizeof(Value));
67   MOZ_ASSERT(numBytes >= sizeof(RematerializedFrame));
68 
69   void* buf = cx->pod_calloc<uint8_t>(numBytes);
70   if (!buf) return nullptr;
71 
72   return new (buf)
73       RematerializedFrame(cx, top, iter.numActualArgs(), iter, fallback);
74 }
75 
RematerializeInlineFrames(JSContext * cx,uint8_t * top,InlineFrameIterator & iter,MaybeReadFallback & fallback,GCVector<RematerializedFrame * > & frames)76 /* static */ bool RematerializedFrame::RematerializeInlineFrames(
77     JSContext* cx, uint8_t* top, InlineFrameIterator& iter,
78     MaybeReadFallback& fallback, GCVector<RematerializedFrame*>& frames) {
79   Rooted<GCVector<RematerializedFrame*>> tempFrames(
80       cx, GCVector<RematerializedFrame*>(cx));
81   if (!tempFrames.resize(iter.frameCount())) return false;
82 
83   while (true) {
84     size_t frameNo = iter.frameNo();
85     tempFrames[frameNo].set(RematerializedFrame::New(cx, top, iter, fallback));
86     if (!tempFrames[frameNo]) return false;
87     if (tempFrames[frameNo]->environmentChain()) {
88       if (!EnsureHasEnvironmentObjects(cx, tempFrames[frameNo].get()))
89         return false;
90     }
91 
92     if (!iter.more()) break;
93     ++iter;
94   }
95 
96   frames = Move(tempFrames.get());
97   return true;
98 }
99 
FreeInVector(GCVector<RematerializedFrame * > & frames)100 /* static */ void RematerializedFrame::FreeInVector(
101     GCVector<RematerializedFrame*>& frames) {
102   for (size_t i = 0; i < frames.length(); i++) {
103     RematerializedFrame* f = frames[i];
104     MOZ_ASSERT(!Debugger::inFrameMaps(f));
105     f->RematerializedFrame::~RematerializedFrame();
106     js_free(f);
107   }
108   frames.clear();
109 }
110 
callObj() const111 CallObject& RematerializedFrame::callObj() const {
112   MOZ_ASSERT(hasInitialEnvironment());
113 
114   JSObject* env = environmentChain();
115   while (!env->is<CallObject>()) env = env->enclosingEnvironment();
116   return env->as<CallObject>();
117 }
118 
initFunctionEnvironmentObjects(JSContext * cx)119 bool RematerializedFrame::initFunctionEnvironmentObjects(JSContext* cx) {
120   return js::InitFunctionEnvironmentObjects(cx, this);
121 }
122 
pushVarEnvironment(JSContext * cx,HandleScope scope)123 bool RematerializedFrame::pushVarEnvironment(JSContext* cx, HandleScope scope) {
124   return js::PushVarEnvironmentObject(cx, scope, this);
125 }
126 
trace(JSTracer * trc)127 void RematerializedFrame::trace(JSTracer* trc) {
128   TraceRoot(trc, &script_, "remat ion frame script");
129   TraceRoot(trc, &envChain_, "remat ion frame env chain");
130   if (callee_) TraceRoot(trc, &callee_, "remat ion frame callee");
131   if (argsObj_) TraceRoot(trc, &argsObj_, "remat ion frame argsobj");
132   TraceRoot(trc, &returnValue_, "remat ion frame return value");
133   TraceRoot(trc, &thisArgument_, "remat ion frame this");
134   TraceRoot(trc, &newTarget_, "remat ion frame newTarget");
135   TraceRootRange(trc, numArgSlots() + script_->nfixed(), slots_,
136                  "remat ion frame stack");
137 }
138 
dump()139 void RematerializedFrame::dump() {
140   fprintf(stderr, " Rematerialized Ion Frame%s\n",
141           inlined() ? " (inlined)" : "");
142   if (isFunctionFrame()) {
143     fprintf(stderr, "  callee fun: ");
144 #ifdef DEBUG
145     DumpValue(ObjectValue(*callee()));
146 #else
147     fprintf(stderr, "?\n");
148 #endif
149   } else {
150     fprintf(stderr, "  global frame, no callee\n");
151   }
152 
153   fprintf(stderr, "  file %s line %zu offset %zu\n", script()->filename(),
154           script()->lineno(), script()->pcToOffset(pc()));
155 
156   fprintf(stderr, "  script = %p\n", (void*)script());
157 
158   if (isFunctionFrame()) {
159     fprintf(stderr, "  env chain: ");
160 #ifdef DEBUG
161     DumpValue(ObjectValue(*environmentChain()));
162 #else
163     fprintf(stderr, "?\n");
164 #endif
165 
166     if (hasArgsObj()) {
167       fprintf(stderr, "  args obj: ");
168 #ifdef DEBUG
169       DumpValue(ObjectValue(argsObj()));
170 #else
171       fprintf(stderr, "?\n");
172 #endif
173     }
174 
175     fprintf(stderr, "  this: ");
176 #ifdef DEBUG
177     DumpValue(thisArgument());
178 #else
179     fprintf(stderr, "?\n");
180 #endif
181 
182     for (unsigned i = 0; i < numActualArgs(); i++) {
183       if (i < numFormalArgs())
184         fprintf(stderr, "  formal (arg %d): ", i);
185       else
186         fprintf(stderr, "  overflown (arg %d): ", i);
187 #ifdef DEBUG
188       DumpValue(argv()[i]);
189 #else
190       fprintf(stderr, "?\n");
191 #endif
192     }
193 
194     for (unsigned i = 0; i < script()->nfixed(); i++) {
195       fprintf(stderr, "  local %d: ", i);
196 #ifdef DEBUG
197       DumpValue(locals()[i]);
198 #else
199       fprintf(stderr, "?\n");
200 #endif
201     }
202   }
203 
204   fputc('\n', stderr);
205 }
206