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