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