Line data Source code
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_BaselineFrame_h
8 : #define jit_BaselineFrame_h
9 :
10 : #include "jit/JitFrames.h"
11 : #include "vm/Stack.h"
12 :
13 : namespace js {
14 : namespace jit {
15 :
16 : struct BaselineDebugModeOSRInfo;
17 :
18 : // The stack looks like this, fp is the frame pointer:
19 : //
20 : // fp+y arguments
21 : // fp+x JitFrameLayout (frame header)
22 : // fp => saved frame pointer
23 : // fp-x BaselineFrame
24 : // locals
25 : // stack values
26 :
27 : class BaselineFrame
28 : {
29 : public:
30 : enum Flags : uint32_t {
31 : // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL.
32 : HAS_RVAL = 1 << 0,
33 :
34 : // An initial environment has been pushed on the environment chain for
35 : // function frames that need a CallObject or eval frames that need a
36 : // VarEnvironmentObject.
37 : HAS_INITIAL_ENV = 1 << 2,
38 :
39 : // Frame has an arguments object, argsObj_.
40 : HAS_ARGS_OBJ = 1 << 4,
41 :
42 : // See InterpreterFrame::PREV_UP_TO_DATE.
43 : PREV_UP_TO_DATE = 1 << 5,
44 :
45 : // Frame has execution observed by a Debugger.
46 : //
47 : // See comment above 'isDebuggee' in jscompartment.h for explanation of
48 : // invariants of debuggee compartments, scripts, and frames.
49 : DEBUGGEE = 1 << 6,
50 :
51 : // (1 << 7 and 1 << 8 are unused)
52 :
53 : // Frame has over-recursed on an early check.
54 : OVER_RECURSED = 1 << 9,
55 :
56 : // Frame has a BaselineRecompileInfo stashed in the scratch value
57 : // slot. See PatchBaselineFramesForDebugMode.
58 : HAS_DEBUG_MODE_OSR_INFO = 1 << 10,
59 :
60 : // This flag is intended for use whenever the frame is settled on a
61 : // native code address without a corresponding ICEntry. In this case,
62 : // the frame contains an explicit bytecode offset for frame iterators.
63 : //
64 : // There can also be an override pc if the frame has had its
65 : // environment chain unwound to a pc during exception handling that is
66 : // different from its current pc.
67 : //
68 : // This flag should never be set when we're executing JIT code.
69 : HAS_OVERRIDE_PC = 1 << 11,
70 :
71 : // If set, we're handling an exception for this frame. This is set for
72 : // debug mode OSR sanity checking when it handles corner cases which
73 : // only arise during exception handling.
74 : HANDLING_EXCEPTION = 1 << 12,
75 :
76 : // If set, this frame has been on the stack when
77 : // |js::SavedStacks::saveCurrentStack| was called, and so there is a
78 : // |js::SavedFrame| object cached for this frame.
79 : HAS_CACHED_SAVED_FRAME = 1 << 13
80 : };
81 :
82 : protected: // Silence Clang warning about unused private fields.
83 : // We need to split the Value into 2 fields of 32 bits, otherwise the C++
84 : // compiler may add some padding between the fields.
85 :
86 : union {
87 : struct {
88 : uint32_t loScratchValue_;
89 : uint32_t hiScratchValue_;
90 : };
91 : BaselineDebugModeOSRInfo* debugModeOSRInfo_;
92 : };
93 : uint32_t loReturnValue_; // If HAS_RVAL, the frame's return value.
94 : uint32_t hiReturnValue_;
95 : uint32_t frameSize_;
96 : JSObject* envChain_; // Environment chain (always initialized).
97 : ArgumentsObject* argsObj_; // If HAS_ARGS_OBJ, the arguments object.
98 : uint32_t overrideOffset_; // If HAS_OVERRIDE_PC, the bytecode offset.
99 : uint32_t flags_;
100 :
101 : public:
102 : // Distance between the frame pointer and the frame header (return address).
103 : // This is the old frame pointer saved in the prologue.
104 : static const uint32_t FramePointerOffset = sizeof(void*);
105 :
106 : MOZ_MUST_USE bool initForOsr(InterpreterFrame* fp, uint32_t numStackValues);
107 :
108 6971 : uint32_t frameSize() const {
109 6971 : return frameSize_;
110 : }
111 0 : void setFrameSize(uint32_t frameSize) {
112 0 : frameSize_ = frameSize;
113 0 : }
114 : inline uint32_t* addressOfFrameSize() {
115 : return &frameSize_;
116 : }
117 16063 : JSObject* environmentChain() const {
118 16063 : return envChain_;
119 : }
120 0 : void setEnvironmentChain(JSObject* envChain) {
121 0 : envChain_ = envChain;
122 0 : }
123 : inline JSObject** addressOfEnvironmentChain() {
124 : return &envChain_;
125 : }
126 :
127 : inline Value* addressOfScratchValue() {
128 : return reinterpret_cast<Value*>(&loScratchValue_);
129 : }
130 :
131 : template <typename SpecificEnvironment>
132 : inline void pushOnEnvironmentChain(SpecificEnvironment& env);
133 : template <typename SpecificEnvironment>
134 : inline void popOffEnvironmentChain();
135 : inline void replaceInnermostEnvironment(EnvironmentObject& env);
136 :
137 233502 : CalleeToken calleeToken() const {
138 233502 : uint8_t* pointer = (uint8_t*)this + Size() + offsetOfCalleeToken();
139 233502 : return *(CalleeToken*)pointer;
140 : }
141 27 : void replaceCalleeToken(CalleeToken token) {
142 27 : uint8_t* pointer = (uint8_t*)this + Size() + offsetOfCalleeToken();
143 27 : *(CalleeToken*)pointer = token;
144 27 : }
145 91 : bool isConstructing() const {
146 91 : return CalleeTokenIsConstructing(calleeToken());
147 : }
148 208912 : JSScript* script() const {
149 208912 : return ScriptFromCalleeToken(calleeToken());
150 : }
151 9703 : JSFunction* callee() const {
152 9703 : return CalleeTokenToFunction(calleeToken());
153 : }
154 : Value calleev() const {
155 : return ObjectValue(*callee());
156 : }
157 6971 : size_t numValueSlots() const {
158 6971 : size_t size = frameSize();
159 :
160 6971 : MOZ_ASSERT(size >= BaselineFrame::FramePointerOffset + BaselineFrame::Size());
161 6971 : size -= BaselineFrame::FramePointerOffset + BaselineFrame::Size();
162 :
163 6971 : MOZ_ASSERT((size % sizeof(Value)) == 0);
164 6971 : return size / sizeof(Value);
165 : }
166 2387 : Value* valueSlot(size_t slot) const {
167 2387 : MOZ_ASSERT(slot < numValueSlots());
168 2387 : return (Value*)this - (slot + 1);
169 : }
170 :
171 7982 : Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
172 7982 : MOZ_ASSERT(i < numFormalArgs());
173 7982 : MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
174 : !script()->formalIsAliased(i));
175 7982 : return argv()[i];
176 : }
177 :
178 16 : Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
179 16 : MOZ_ASSERT(i < numActualArgs());
180 16 : MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
181 16 : MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
182 16 : return argv()[i];
183 : }
184 :
185 13 : Value& unaliasedLocal(uint32_t i) const {
186 13 : MOZ_ASSERT(i < script()->nfixed());
187 13 : return *valueSlot(i);
188 : }
189 :
190 756 : unsigned numActualArgs() const {
191 756 : return *(size_t*)(reinterpret_cast<const uint8_t*>(this) +
192 756 : BaselineFrame::Size() +
193 1512 : offsetOfNumActualArgs());
194 : }
195 8676 : unsigned numFormalArgs() const {
196 8676 : return script()->functionNonDelazifying()->nargs();
197 : }
198 37 : Value& thisArgument() const {
199 37 : MOZ_ASSERT(isFunctionFrame());
200 : return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
201 37 : BaselineFrame::Size() +
202 37 : offsetOfThis());
203 : }
204 8622 : Value* argv() const {
205 : return (Value*)(reinterpret_cast<const uint8_t*>(this) +
206 8622 : BaselineFrame::Size() +
207 8622 : offsetOfArg(0));
208 : }
209 :
210 : private:
211 0 : Value* evalNewTargetAddress() const {
212 0 : MOZ_ASSERT(isEvalFrame());
213 0 : MOZ_ASSERT(script()->isDirectEvalInFunction());
214 : return (Value*)(reinterpret_cast<const uint8_t*>(this) +
215 0 : BaselineFrame::Size() +
216 0 : offsetOfEvalNewTarget());
217 : }
218 :
219 : public:
220 64 : Value newTarget() const {
221 64 : if (isEvalFrame())
222 0 : return *evalNewTargetAddress();
223 64 : MOZ_ASSERT(isFunctionFrame());
224 64 : if (callee()->isArrow())
225 0 : return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
226 64 : if (isConstructing()) {
227 0 : return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
228 0 : BaselineFrame::Size() +
229 0 : offsetOfArg(Max(numFormalArgs(), numActualArgs())));
230 : }
231 64 : return UndefinedValue();
232 : }
233 :
234 29 : bool hasReturnValue() const {
235 29 : return flags_ & HAS_RVAL;
236 : }
237 2 : MutableHandleValue returnValue() {
238 2 : if (!hasReturnValue())
239 1 : addressOfReturnValue()->setUndefined();
240 2 : return MutableHandleValue::fromMarkedLocation(addressOfReturnValue());
241 : }
242 1 : void setReturnValue(const Value& v) {
243 1 : returnValue().set(v);
244 1 : flags_ |= HAS_RVAL;
245 1 : }
246 3 : inline Value* addressOfReturnValue() {
247 3 : return reinterpret_cast<Value*>(&loReturnValue_);
248 : }
249 :
250 0 : bool hasInitialEnvironment() const {
251 0 : return flags_ & HAS_INITIAL_ENV;
252 : }
253 :
254 : inline CallObject& callObj() const;
255 :
256 0 : void setFlags(uint32_t flags) {
257 0 : flags_ = flags;
258 0 : }
259 : uint32_t* addressOfFlags() {
260 : return &flags_;
261 : }
262 :
263 : inline MOZ_MUST_USE bool pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope);
264 : inline MOZ_MUST_USE bool freshenLexicalEnvironment(JSContext* cx);
265 : inline MOZ_MUST_USE bool recreateLexicalEnvironment(JSContext* cx);
266 :
267 : MOZ_MUST_USE bool initFunctionEnvironmentObjects(JSContext* cx);
268 : MOZ_MUST_USE bool pushVarEnvironment(JSContext* cx, HandleScope scope);
269 :
270 50 : void initArgsObjUnchecked(ArgumentsObject& argsobj) {
271 50 : flags_ |= HAS_ARGS_OBJ;
272 50 : argsObj_ = &argsobj;
273 50 : }
274 50 : void initArgsObj(ArgumentsObject& argsobj) {
275 50 : MOZ_ASSERT(script()->needsArgsObj());
276 50 : initArgsObjUnchecked(argsobj);
277 50 : }
278 27 : bool hasArgsObj() const {
279 27 : return flags_ & HAS_ARGS_OBJ;
280 : }
281 0 : ArgumentsObject& argsObj() const {
282 0 : MOZ_ASSERT(hasArgsObj());
283 0 : MOZ_ASSERT(script()->needsArgsObj());
284 0 : return *argsObj_;
285 : }
286 :
287 0 : bool prevUpToDate() const {
288 0 : return flags_ & PREV_UP_TO_DATE;
289 : }
290 0 : void setPrevUpToDate() {
291 0 : flags_ |= PREV_UP_TO_DATE;
292 0 : }
293 0 : void unsetPrevUpToDate() {
294 0 : flags_ &= ~PREV_UP_TO_DATE;
295 0 : }
296 :
297 169 : bool isDebuggee() const {
298 169 : return flags_ & DEBUGGEE;
299 : }
300 0 : void setIsDebuggee() {
301 0 : flags_ |= DEBUGGEE;
302 0 : }
303 : inline void unsetIsDebuggee();
304 :
305 117390 : bool isHandlingException() const {
306 117390 : return flags_ & HANDLING_EXCEPTION;
307 : }
308 1993 : void setIsHandlingException() {
309 1993 : flags_ |= HANDLING_EXCEPTION;
310 1993 : }
311 1993 : void unsetIsHandlingException() {
312 1993 : flags_ &= ~HANDLING_EXCEPTION;
313 1993 : }
314 :
315 775 : bool hasCachedSavedFrame() const {
316 775 : return flags_ & HAS_CACHED_SAVED_FRAME;
317 : }
318 471 : void setHasCachedSavedFrame() {
319 471 : flags_ |= HAS_CACHED_SAVED_FRAME;
320 471 : }
321 :
322 12 : bool overRecursed() const {
323 12 : return flags_ & OVER_RECURSED;
324 : }
325 :
326 0 : void setOverRecursed() {
327 0 : flags_ |= OVER_RECURSED;
328 0 : }
329 :
330 0 : BaselineDebugModeOSRInfo* debugModeOSRInfo() {
331 0 : MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO);
332 0 : return debugModeOSRInfo_;
333 : }
334 :
335 1993 : BaselineDebugModeOSRInfo* getDebugModeOSRInfo() {
336 1993 : if (flags_ & HAS_DEBUG_MODE_OSR_INFO)
337 0 : return debugModeOSRInfo();
338 1993 : return nullptr;
339 : }
340 :
341 0 : void setDebugModeOSRInfo(BaselineDebugModeOSRInfo* info) {
342 0 : flags_ |= HAS_DEBUG_MODE_OSR_INFO;
343 0 : debugModeOSRInfo_ = info;
344 0 : }
345 :
346 : void deleteDebugModeOSRInfo();
347 :
348 : // See the HAS_OVERRIDE_PC comment.
349 11695 : bool hasOverridePc() const {
350 11695 : return flags_ & HAS_OVERRIDE_PC;
351 : }
352 :
353 0 : jsbytecode* overridePc() const {
354 0 : MOZ_ASSERT(hasOverridePc());
355 0 : return script()->offsetToPC(overrideOffset_);
356 : }
357 :
358 7623 : jsbytecode* maybeOverridePc() const {
359 7623 : if (hasOverridePc())
360 0 : return overridePc();
361 7623 : return nullptr;
362 : }
363 :
364 2071 : void setOverridePc(jsbytecode* pc) {
365 2071 : flags_ |= HAS_OVERRIDE_PC;
366 2071 : overrideOffset_ = script()->pcToOffset(pc);
367 2071 : }
368 :
369 1993 : void clearOverridePc() {
370 1993 : flags_ &= ~HAS_OVERRIDE_PC;
371 1993 : }
372 :
373 : void trace(JSTracer* trc, JitFrameIterator& frame);
374 :
375 0 : bool isGlobalFrame() const {
376 0 : return script()->isGlobalCode();
377 : }
378 0 : bool isModuleFrame() const {
379 0 : return script()->module();
380 : }
381 277 : bool isEvalFrame() const {
382 277 : return script()->isForEval();
383 : }
384 : bool isStrictEvalFrame() const {
385 : return isEvalFrame() && script()->strict();
386 : }
387 : bool isNonStrictEvalFrame() const {
388 : return isEvalFrame() && !script()->strict();
389 : }
390 : bool isNonGlobalEvalFrame() const;
391 : bool isNonStrictDirectEvalFrame() const {
392 : return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
393 : }
394 14769 : bool isFunctionFrame() const {
395 14769 : return CalleeTokenIsFunction(calleeToken());
396 : }
397 12 : bool isDebuggerEvalFrame() const {
398 12 : return false;
399 : }
400 :
401 78 : JitFrameLayout* framePrefix() const {
402 78 : uint8_t* fp = (uint8_t*)this + Size() + FramePointerOffset;
403 78 : return (JitFrameLayout*)fp;
404 : }
405 :
406 : // Methods below are used by the compiler.
407 234219 : static size_t offsetOfCalleeToken() {
408 234219 : return FramePointerOffset + js::jit::JitFrameLayout::offsetOfCalleeToken();
409 : }
410 961 : static size_t offsetOfThis() {
411 961 : return FramePointerOffset + js::jit::JitFrameLayout::offsetOfThis();
412 : }
413 0 : static size_t offsetOfEvalNewTarget() {
414 0 : return FramePointerOffset + js::jit::JitFrameLayout::offsetOfEvalNewTarget();
415 : }
416 11628 : static size_t offsetOfArg(size_t index) {
417 11628 : return FramePointerOffset + js::jit::JitFrameLayout::offsetOfActualArg(index);
418 : }
419 819 : static size_t offsetOfNumActualArgs() {
420 819 : return FramePointerOffset + js::jit::JitFrameLayout::offsetOfNumActualArgs();
421 : }
422 350544 : static size_t Size() {
423 350544 : return sizeof(BaselineFrame);
424 : }
425 :
426 : // The reverseOffsetOf methods below compute the offset relative to the
427 : // frame's base pointer. Since the stack grows down, these offsets are
428 : // negative.
429 4677 : static int reverseOffsetOfFrameSize() {
430 4677 : return -int(Size()) + offsetof(BaselineFrame, frameSize_);
431 : }
432 423 : static int reverseOffsetOfScratchValue() {
433 423 : return -int(Size()) + offsetof(BaselineFrame, loScratchValue_);
434 : }
435 2640 : static int reverseOffsetOfEnvironmentChain() {
436 2640 : return -int(Size()) + offsetof(BaselineFrame, envChain_);
437 : }
438 4 : static int reverseOffsetOfArgsObj() {
439 4 : return -int(Size()) + offsetof(BaselineFrame, argsObj_);
440 : }
441 7990 : static int reverseOffsetOfFlags() {
442 7990 : return -int(Size()) + offsetof(BaselineFrame, flags_);
443 : }
444 487 : static int reverseOffsetOfReturnValue() {
445 487 : return -int(Size()) + offsetof(BaselineFrame, loReturnValue_);
446 : }
447 13223 : static int reverseOffsetOfLocal(size_t index) {
448 13223 : return -int(Size()) - (index + 1) * sizeof(Value);
449 : }
450 : };
451 :
452 : // Ensure the frame is 8-byte aligned (required on ARM).
453 : JS_STATIC_ASSERT(((sizeof(BaselineFrame) + BaselineFrame::FramePointerOffset) % 8) == 0);
454 :
455 : } // namespace jit
456 : } // namespace js
457 :
458 : #endif /* jit_BaselineFrame_h */
|