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_JitFrames_h
8 : #define jit_JitFrames_h
9 :
10 : #include <stdint.h>
11 :
12 : #include "jscntxt.h"
13 : #include "jsfun.h"
14 :
15 : #include "jit/JitFrameIterator.h"
16 : #include "jit/Safepoints.h"
17 :
18 : namespace js {
19 : namespace jit {
20 :
21 : enum CalleeTokenTag
22 : {
23 : CalleeToken_Function = 0x0, // untagged
24 : CalleeToken_FunctionConstructing = 0x1,
25 : CalleeToken_Script = 0x2
26 : };
27 :
28 : static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
29 :
30 : static inline CalleeTokenTag
31 510574 : GetCalleeTokenTag(CalleeToken token)
32 : {
33 510574 : CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
34 510574 : MOZ_ASSERT(tag <= CalleeToken_Script);
35 510574 : return tag;
36 : }
37 : static inline CalleeToken
38 7695 : CalleeToToken(JSFunction* fun, bool constructing)
39 : {
40 7695 : CalleeTokenTag tag = constructing ? CalleeToken_FunctionConstructing : CalleeToken_Function;
41 7695 : return CalleeToken(uintptr_t(fun) | uintptr_t(tag));
42 : }
43 : static inline CalleeToken
44 5 : CalleeToToken(JSScript* script)
45 : {
46 5 : return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
47 : }
48 : static inline bool
49 263467 : CalleeTokenIsFunction(CalleeToken token)
50 : {
51 263467 : CalleeTokenTag tag = GetCalleeTokenTag(token);
52 263467 : return tag == CalleeToken_Function || tag == CalleeToken_FunctionConstructing;
53 : }
54 : static inline bool
55 141 : CalleeTokenIsConstructing(CalleeToken token)
56 : {
57 141 : return GetCalleeTokenTag(token) == CalleeToken_FunctionConstructing;
58 : }
59 : static inline JSFunction*
60 242839 : CalleeTokenToFunction(CalleeToken token)
61 : {
62 242839 : MOZ_ASSERT(CalleeTokenIsFunction(token));
63 242839 : return (JSFunction*)(uintptr_t(token) & CalleeTokenMask);
64 : }
65 : static inline JSScript*
66 9464 : CalleeTokenToScript(CalleeToken token)
67 : {
68 9464 : MOZ_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
69 9464 : return (JSScript*)(uintptr_t(token) & CalleeTokenMask);
70 : }
71 : static inline bool
72 : CalleeTokenIsModuleScript(CalleeToken token)
73 : {
74 : CalleeTokenTag tag = GetCalleeTokenTag(token);
75 : return tag == CalleeToken_Script && CalleeTokenToScript(token)->module();
76 : }
77 :
78 : static inline JSScript*
79 237475 : ScriptFromCalleeToken(CalleeToken token)
80 : {
81 237475 : switch (GetCalleeTokenTag(token)) {
82 : case CalleeToken_Script:
83 9464 : return CalleeTokenToScript(token);
84 : case CalleeToken_Function:
85 : case CalleeToken_FunctionConstructing:
86 228011 : return CalleeTokenToFunction(token)->nonLazyScript();
87 : }
88 0 : MOZ_CRASH("invalid callee token tag");
89 : }
90 :
91 : // In between every two frames lies a small header describing both frames. This
92 : // header, minimally, contains a returnAddress word and a descriptor word. The
93 : // descriptor describes the size and type of the previous frame, whereas the
94 : // returnAddress describes the address the newer frame (the callee) will return
95 : // to. The exact mechanism in which frames are laid out is architecture
96 : // dependent.
97 : //
98 : // Two special frame types exist:
99 : // - Entry frames begin a JitActivation, and therefore there is exactly one
100 : // per activation of EnterIon or EnterBaseline. These reuse JitFrameLayout.
101 : // - Exit frames are necessary to leave JIT code and enter C++, and thus,
102 : // C++ code will always begin iterating from the topmost exit frame.
103 :
104 : class LSafepoint;
105 :
106 : // Two-tuple that lets you look up the safepoint entry given the
107 : // displacement of a call instruction within the JIT code.
108 : class SafepointIndex
109 : {
110 : // The displacement is the distance from the first byte of the JIT'd code
111 : // to the return address (of the call that the safepoint was generated for).
112 : uint32_t displacement_;
113 :
114 : union {
115 : LSafepoint* safepoint_;
116 :
117 : // Offset to the start of the encoded safepoint in the safepoint stream.
118 : uint32_t safepointOffset_;
119 : };
120 :
121 : #ifdef DEBUG
122 : bool resolved;
123 : #endif
124 :
125 : public:
126 147 : SafepointIndex(uint32_t displacement, LSafepoint* safepoint)
127 147 : : displacement_(displacement),
128 : safepoint_(safepoint)
129 : #ifdef DEBUG
130 147 : , resolved(false)
131 : #endif
132 147 : { }
133 :
134 : void resolve();
135 :
136 43 : LSafepoint* safepoint() {
137 43 : MOZ_ASSERT(!resolved);
138 43 : return safepoint_;
139 : }
140 6860 : uint32_t displacement() const {
141 6860 : return displacement_;
142 : }
143 1680 : uint32_t safepointOffset() const {
144 1680 : return safepointOffset_;
145 : }
146 : void adjustDisplacement(uint32_t offset) {
147 : MOZ_ASSERT(offset >= displacement_);
148 : displacement_ = offset;
149 : }
150 : inline SnapshotOffset snapshotOffset() const;
151 : inline bool hasSnapshotOffset() const;
152 : };
153 :
154 : class MacroAssembler;
155 : // The OSI point is patched to a call instruction. Therefore, the
156 : // returnPoint for an OSI call is the address immediately following that
157 : // call instruction. The displacement of that point within the assembly
158 : // buffer is the |returnPointDisplacement|.
159 : class OsiIndex
160 : {
161 : uint32_t callPointDisplacement_;
162 : uint32_t snapshotOffset_;
163 :
164 : public:
165 134 : OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset)
166 134 : : callPointDisplacement_(callPointDisplacement),
167 134 : snapshotOffset_(snapshotOffset)
168 134 : { }
169 :
170 : uint32_t returnPointDisplacement() const;
171 : uint32_t callPointDisplacement() const {
172 : return callPointDisplacement_;
173 : }
174 840 : uint32_t snapshotOffset() const {
175 840 : return snapshotOffset_;
176 : }
177 : };
178 :
179 : // The layout of an Ion frame on the C stack is roughly:
180 : // argN _
181 : // ... \ - These are jsvals
182 : // arg0 /
183 : // -3 this _/
184 : // -2 callee
185 : // -1 descriptor
186 : // 0 returnAddress
187 : // .. locals ..
188 :
189 : // The descriptor is organized into four sections:
190 : // [ frame size | has cached saved frame bit | frame header size | frame type ]
191 : // < highest - - - - - - - - - - - - - - lowest >
192 : static const uintptr_t FRAMETYPE_BITS = 4;
193 : static const uintptr_t FRAME_HEADER_SIZE_SHIFT = FRAMETYPE_BITS;
194 : static const uintptr_t FRAME_HEADER_SIZE_BITS = 3;
195 : static const uintptr_t FRAME_HEADER_SIZE_MASK = (1 << FRAME_HEADER_SIZE_BITS) - 1;
196 : static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << (FRAMETYPE_BITS + FRAME_HEADER_SIZE_BITS);
197 : static const uintptr_t FRAMESIZE_SHIFT = FRAMETYPE_BITS +
198 : FRAME_HEADER_SIZE_BITS +
199 : 1 /* cached saved frame bit */;
200 : static const uintptr_t FRAMESIZE_BITS = 32 - FRAMESIZE_SHIFT;
201 : static const uintptr_t FRAMESIZE_MASK = (1 << FRAMESIZE_BITS) - 1;
202 :
203 : // Ion frames have a few important numbers associated with them:
204 : // Local depth: The number of bytes required to spill local variables.
205 : // Argument depth: The number of bytes required to push arguments and make
206 : // a function call.
207 : // Slack: A frame may temporarily use extra stack to resolve cycles.
208 : //
209 : // The (local + argument) depth determines the "fixed frame size". The fixed
210 : // frame size is the distance between the stack pointer and the frame header.
211 : // Thus, fixed >= (local + argument).
212 : //
213 : // In order to compress guards, we create shared jump tables that recover the
214 : // script from the stack and recover a snapshot pointer based on which jump was
215 : // taken. Thus, we create a jump table for each fixed frame size.
216 : //
217 : // Jump tables are big. To control the amount of jump tables we generate, each
218 : // platform chooses how to segregate stack size classes based on its
219 : // architecture.
220 : //
221 : // On some architectures, these jump tables are not used at all, or frame
222 : // size segregation is not needed. Thus, there is an option for a frame to not
223 : // have any frame size class, and to be totally dynamic.
224 : static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1);
225 :
226 : class FrameSizeClass
227 : {
228 : uint32_t class_;
229 :
230 590 : explicit FrameSizeClass(uint32_t class_) : class_(class_)
231 590 : { }
232 :
233 : public:
234 8 : FrameSizeClass()
235 8 : { }
236 :
237 578 : static FrameSizeClass None() {
238 578 : return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
239 : }
240 4 : static FrameSizeClass FromClass(uint32_t class_) {
241 4 : return FrameSizeClass(class_);
242 : }
243 :
244 : // These functions are implemented in specific CodeGenerator-* files.
245 : static FrameSizeClass FromDepth(uint32_t frameDepth);
246 : static FrameSizeClass ClassLimit();
247 : uint32_t frameSize() const;
248 :
249 4 : uint32_t classId() const {
250 4 : MOZ_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
251 4 : return class_;
252 : }
253 :
254 196 : bool operator ==(const FrameSizeClass& other) const {
255 196 : return class_ == other.class_;
256 : }
257 378 : bool operator !=(const FrameSizeClass& other) const {
258 378 : return class_ != other.class_;
259 : }
260 : };
261 :
262 : struct BaselineBailoutInfo;
263 :
264 : // Data needed to recover from an exception.
265 : struct ResumeFromException
266 : {
267 : static const uint32_t RESUME_ENTRY_FRAME = 0;
268 : static const uint32_t RESUME_CATCH = 1;
269 : static const uint32_t RESUME_FINALLY = 2;
270 : static const uint32_t RESUME_FORCED_RETURN = 3;
271 : static const uint32_t RESUME_BAILOUT = 4;
272 :
273 : uint8_t* framePointer;
274 : uint8_t* stackPointer;
275 : uint8_t* target;
276 : uint32_t kind;
277 :
278 : // Value to push when resuming into a |finally| block.
279 : Value exception;
280 :
281 : BaselineBailoutInfo* bailoutInfo;
282 : };
283 :
284 : void HandleException(ResumeFromException* rfe);
285 :
286 : void EnsureBareExitFrame(JSContext* cx, JitFrameLayout* frame);
287 :
288 : void TraceJitActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
289 :
290 : void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc);
291 :
292 : static inline uint32_t
293 5227 : EncodeFrameHeaderSize(size_t headerSize)
294 : {
295 5227 : MOZ_ASSERT((headerSize % sizeof(uintptr_t)) == 0);
296 :
297 5227 : uint32_t headerSizeWords = headerSize / sizeof(uintptr_t);
298 5227 : MOZ_ASSERT(headerSizeWords <= FRAME_HEADER_SIZE_MASK);
299 5227 : return headerSizeWords;
300 : }
301 :
302 : static inline uint32_t
303 3583 : MakeFrameDescriptor(uint32_t frameSize, FrameType type, uint32_t headerSize)
304 : {
305 3583 : MOZ_ASSERT(headerSize < FRAMESIZE_MASK);
306 3583 : headerSize = EncodeFrameHeaderSize(headerSize);
307 3583 : return 0 | (frameSize << FRAMESIZE_SHIFT) | (headerSize << FRAME_HEADER_SIZE_SHIFT) | type;
308 : }
309 :
310 : // Returns the JSScript associated with the topmost JIT frame.
311 : inline JSScript*
312 0 : GetTopJitJSScript(JSContext* cx)
313 : {
314 0 : JitFrameIterator iter(cx);
315 0 : MOZ_ASSERT(iter.type() == JitFrame_Exit);
316 0 : ++iter;
317 :
318 0 : if (iter.isBaselineStub()) {
319 0 : ++iter;
320 0 : MOZ_ASSERT(iter.isBaselineJS());
321 : }
322 :
323 0 : MOZ_ASSERT(iter.isScripted());
324 0 : return iter.script();
325 : }
326 :
327 : #ifdef JS_CODEGEN_MIPS32
328 : uint8_t* alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset);
329 : #else
330 : inline uint8_t*
331 855 : alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset)
332 : {
333 : // This is NO-OP on non-MIPS platforms.
334 855 : return pointer;
335 : }
336 : #endif
337 :
338 : // Layout of the frame prefix. This assumes the stack architecture grows down.
339 : // If this is ever not the case, we'll have to refactor.
340 : class CommonFrameLayout
341 : {
342 : uint8_t* returnAddress_;
343 : uintptr_t descriptor_;
344 :
345 : static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1;
346 :
347 : public:
348 12 : static size_t offsetOfDescriptor() {
349 12 : return offsetof(CommonFrameLayout, descriptor_);
350 : }
351 : uintptr_t descriptor() const {
352 : return descriptor_;
353 : }
354 20 : static size_t offsetOfReturnAddress() {
355 20 : return offsetof(CommonFrameLayout, returnAddress_);
356 : }
357 43293 : FrameType prevType() const {
358 43293 : return FrameType(descriptor_ & FrameTypeMask);
359 : }
360 : void changePrevType(FrameType type) {
361 : descriptor_ &= ~FrameTypeMask;
362 : descriptor_ |= type;
363 : }
364 43293 : size_t prevFrameLocalSize() const {
365 43293 : return descriptor_ >> FRAMESIZE_SHIFT;
366 : }
367 20063 : size_t headerSize() const {
368 : return sizeof(uintptr_t) *
369 20063 : ((descriptor_ >> FRAME_HEADER_SIZE_SHIFT) & FRAME_HEADER_SIZE_MASK);
370 : }
371 0 : bool hasCachedSavedFrame() const {
372 0 : return descriptor_ & HASCACHEDSAVEDFRAME_BIT;
373 : }
374 0 : void setHasCachedSavedFrame() {
375 0 : descriptor_ |= HASCACHEDSAVEDFRAME_BIT;
376 0 : }
377 20063 : uint8_t* returnAddress() const {
378 20063 : return returnAddress_;
379 : }
380 0 : void setReturnAddress(uint8_t* addr) {
381 0 : returnAddress_ = addr;
382 0 : }
383 : };
384 :
385 : class JitFrameLayout : public CommonFrameLayout
386 : {
387 : CalleeToken calleeToken_;
388 : uintptr_t numActualArgs_;
389 :
390 : public:
391 39490 : CalleeToken calleeToken() const {
392 39490 : return calleeToken_;
393 : }
394 0 : void replaceCalleeToken(CalleeToken calleeToken) {
395 0 : calleeToken_ = calleeToken;
396 0 : }
397 :
398 234226 : static size_t offsetOfCalleeToken() {
399 234226 : return offsetof(JitFrameLayout, calleeToken_);
400 : }
401 825 : static size_t offsetOfNumActualArgs() {
402 825 : return offsetof(JitFrameLayout, numActualArgs_);
403 : }
404 12591 : static size_t offsetOfThis() {
405 12591 : return sizeof(JitFrameLayout);
406 : }
407 0 : static size_t offsetOfEvalNewTarget() {
408 0 : return sizeof(JitFrameLayout);
409 : }
410 11630 : static size_t offsetOfActualArgs() {
411 11630 : return offsetOfThis() + sizeof(Value);
412 : }
413 11628 : static size_t offsetOfActualArg(size_t arg) {
414 11628 : return offsetOfActualArgs() + arg * sizeof(Value);
415 : }
416 :
417 : Value thisv() {
418 : MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
419 : return argv()[0];
420 : }
421 1 : Value* argv() {
422 1 : MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
423 1 : return (Value*)(this + 1);
424 : }
425 0 : uintptr_t numActualArgs() const {
426 0 : return numActualArgs_;
427 : }
428 :
429 : // Computes a reference to a stack or argument slot, where a slot is a
430 : // distance from the base frame pointer, as would be used for LStackSlot
431 : // or LArgument.
432 : uintptr_t* slotRef(SafepointSlotEntry where);
433 :
434 118 : static inline size_t Size() {
435 118 : return sizeof(JitFrameLayout);
436 : }
437 : };
438 :
439 : class RectifierFrameLayout : public JitFrameLayout
440 : {
441 : public:
442 12 : static inline size_t Size() {
443 12 : return sizeof(RectifierFrameLayout);
444 : }
445 : };
446 :
447 : class IonICCallFrameLayout : public CommonFrameLayout
448 : {
449 : protected:
450 : // Pointer to root the stub's JitCode.
451 : JitCode* stubCode_;
452 :
453 : public:
454 0 : JitCode** stubCode() {
455 0 : return &stubCode_;
456 : }
457 4 : static size_t Size() {
458 4 : return sizeof(IonICCallFrameLayout);
459 : }
460 : };
461 :
462 : // GC related data used to keep alive data surrounding the Exit frame.
463 : class ExitFooterFrame
464 : {
465 : const VMFunction* function_;
466 : JitCode* jitCode_;
467 :
468 : public:
469 2613 : static inline size_t Size() {
470 2613 : return sizeof(ExitFooterFrame);
471 : }
472 388 : inline JitCode* jitCode() const {
473 388 : return jitCode_;
474 : }
475 97 : inline JitCode** addressOfJitCode() {
476 97 : return &jitCode_;
477 : }
478 19 : inline const VMFunction* function() const {
479 19 : return function_;
480 : }
481 :
482 : // This should only be called for function()->outParam == Type_Handle
483 : template <typename T>
484 15 : T* outParam() {
485 15 : uint8_t* address = reinterpret_cast<uint8_t*>(this);
486 15 : address = alignDoubleSpillWithOffset(address, sizeof(intptr_t));
487 15 : return reinterpret_cast<T*>(address - sizeof(T));
488 : }
489 : };
490 :
491 : class NativeExitFrameLayout;
492 : class IonOOLNativeExitFrameLayout;
493 : class IonOOLPropertyOpExitFrameLayout;
494 : class IonOOLProxyExitFrameLayout;
495 : class IonDOMExitFrameLayout;
496 :
497 : enum ExitFrameTokenValues
498 : {
499 : CallNativeExitFrameLayoutToken = 0x0,
500 : ConstructNativeExitFrameLayoutToken = 0x1,
501 : IonDOMExitFrameLayoutGetterToken = 0x2,
502 : IonDOMExitFrameLayoutSetterToken = 0x3,
503 : IonDOMMethodExitFrameLayoutToken = 0x4,
504 : IonOOLNativeExitFrameLayoutToken = 0x5,
505 : IonOOLPropertyOpExitFrameLayoutToken = 0x6,
506 : IonOOLSetterOpExitFrameLayoutToken = 0x7,
507 : IonOOLProxyExitFrameLayoutToken = 0x8,
508 : LazyLinkExitFrameLayoutToken = 0xFE,
509 : ExitFrameLayoutBareToken = 0xFF
510 : };
511 :
512 : // this is the frame layout when we are exiting ion code, and about to enter platform ABI code
513 : class ExitFrameLayout : public CommonFrameLayout
514 : {
515 19 : inline uint8_t* top() {
516 19 : return reinterpret_cast<uint8_t*>(this + 1);
517 : }
518 :
519 : public:
520 : // Pushed for "bare" fake exit frames that have no GC things on stack to be
521 : // traced.
522 253 : static JitCode* BareToken() { return (JitCode*)ExitFrameLayoutBareToken; }
523 :
524 5777 : static inline size_t Size() {
525 5777 : return sizeof(ExitFrameLayout);
526 : }
527 1024 : static inline size_t SizeWithFooter() {
528 1024 : return Size() + ExitFooterFrame::Size();
529 : }
530 :
531 549 : inline ExitFooterFrame* footer() {
532 549 : uint8_t* sp = reinterpret_cast<uint8_t*>(this);
533 549 : return reinterpret_cast<ExitFooterFrame*>(sp - ExitFooterFrame::Size());
534 : }
535 :
536 : // argBase targets the point which precedes the exit frame. Arguments of VM
537 : // each wrapper are pushed before the exit frame. This correspond exactly
538 : // to the value of the argBase register of the generateVMWrapper function.
539 19 : inline uint8_t* argBase() {
540 19 : MOZ_ASSERT(footer()->jitCode() != nullptr);
541 19 : return top();
542 : }
543 :
544 : inline bool isWrapperExit() {
545 : return footer()->function() != nullptr;
546 : }
547 175 : inline bool isBareExit() {
548 175 : return footer()->jitCode() == BareToken();
549 : }
550 :
551 : // See the various exit frame layouts below.
552 151 : template <typename T> inline bool is() {
553 151 : return footer()->jitCode() == T::Token();
554 : }
555 5 : template <typename T> inline T* as() {
556 5 : MOZ_ASSERT(this->is<T>());
557 5 : return reinterpret_cast<T*>(footer());
558 : }
559 : };
560 :
561 : // Cannot inherit implementation since we need to extend the top of
562 : // ExitFrameLayout.
563 : class NativeExitFrameLayout
564 : {
565 : protected: // only to silence a clang warning about unused private fields
566 : ExitFooterFrame footer_;
567 : ExitFrameLayout exit_;
568 : uintptr_t argc_;
569 :
570 : // We need to split the Value into 2 fields of 32 bits, otherwise the C++
571 : // compiler may add some padding between the fields.
572 : uint32_t loCalleeResult_;
573 : uint32_t hiCalleeResult_;
574 :
575 : public:
576 9 : static inline size_t Size() {
577 9 : return sizeof(NativeExitFrameLayout);
578 : }
579 :
580 86 : static size_t offsetOfResult() {
581 86 : return offsetof(NativeExitFrameLayout, loCalleeResult_);
582 : }
583 5 : inline Value* vp() {
584 5 : return reinterpret_cast<Value*>(&loCalleeResult_);
585 : }
586 5 : inline uintptr_t argc() const {
587 5 : return argc_;
588 : }
589 : };
590 :
591 : class CallNativeExitFrameLayout : public NativeExitFrameLayout
592 : {
593 : public:
594 29 : static JitCode* Token() { return (JitCode*)CallNativeExitFrameLayoutToken; }
595 : };
596 :
597 : class ConstructNativeExitFrameLayout : public NativeExitFrameLayout
598 : {
599 : public:
600 24 : static JitCode* Token() { return (JitCode*)ConstructNativeExitFrameLayoutToken; }
601 : };
602 :
603 : template<>
604 : inline bool
605 29 : ExitFrameLayout::is<NativeExitFrameLayout>()
606 : {
607 29 : return is<CallNativeExitFrameLayout>() || is<ConstructNativeExitFrameLayout>();
608 : }
609 :
610 : class IonOOLNativeExitFrameLayout
611 : {
612 : protected: // only to silence a clang warning about unused private fields
613 : ExitFooterFrame footer_;
614 : ExitFrameLayout exit_;
615 :
616 : // pointer to root the stub's JitCode
617 : JitCode* stubCode_;
618 :
619 : uintptr_t argc_;
620 :
621 : // We need to split the Value into 2 fields of 32 bits, otherwise the C++
622 : // compiler may add some padding between the fields.
623 : uint32_t loCalleeResult_;
624 : uint32_t hiCalleeResult_;
625 :
626 : // Split Value for |this| and args above.
627 : uint32_t loThis_;
628 : uint32_t hiThis_;
629 :
630 : public:
631 19 : static JitCode* Token() { return (JitCode*)IonOOLNativeExitFrameLayoutToken; }
632 :
633 0 : static inline size_t Size(size_t argc) {
634 : // The frame accounts for the callee/result and |this|, so we only need args.
635 0 : return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value));
636 : }
637 :
638 0 : static size_t offsetOfResult() {
639 0 : return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_);
640 : }
641 :
642 0 : inline JitCode** stubCode() {
643 0 : return &stubCode_;
644 : }
645 0 : inline Value* vp() {
646 0 : return reinterpret_cast<Value*>(&loCalleeResult_);
647 : }
648 0 : inline Value* thisp() {
649 0 : return reinterpret_cast<Value*>(&loThis_);
650 : }
651 0 : inline uintptr_t argc() const {
652 0 : return argc_;
653 : }
654 : };
655 :
656 : class IonOOLPropertyOpExitFrameLayout
657 : {
658 : protected:
659 : ExitFooterFrame footer_;
660 : ExitFrameLayout exit_;
661 :
662 : // Object for HandleObject
663 : JSObject* obj_;
664 :
665 : // id for HandleId
666 : jsid id_;
667 :
668 : // space for MutableHandleValue result
669 : // use two uint32_t so compiler doesn't align.
670 : uint32_t vp0_;
671 : uint32_t vp1_;
672 :
673 : // pointer to root the stub's JitCode
674 : JitCode* stubCode_;
675 :
676 : public:
677 19 : static JitCode* Token() { return (JitCode*)IonOOLPropertyOpExitFrameLayoutToken; }
678 :
679 : static inline size_t Size() {
680 : return sizeof(IonOOLPropertyOpExitFrameLayout);
681 : }
682 :
683 : static size_t offsetOfObject() {
684 : return offsetof(IonOOLPropertyOpExitFrameLayout, obj_);
685 : }
686 :
687 : static size_t offsetOfId() {
688 : return offsetof(IonOOLPropertyOpExitFrameLayout, id_);
689 : }
690 :
691 : static size_t offsetOfResult() {
692 : return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
693 : }
694 :
695 0 : inline JitCode** stubCode() {
696 0 : return &stubCode_;
697 : }
698 0 : inline Value* vp() {
699 0 : return reinterpret_cast<Value*>(&vp0_);
700 : }
701 0 : inline jsid* id() {
702 0 : return &id_;
703 : }
704 0 : inline JSObject** obj() {
705 0 : return &obj_;
706 : }
707 : };
708 :
709 : class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
710 : {
711 : protected: // only to silence a clang warning about unused private fields
712 : JS::ObjectOpResult result_;
713 :
714 : public:
715 19 : static JitCode* Token() { return (JitCode*)IonOOLSetterOpExitFrameLayoutToken; }
716 :
717 : static size_t offsetOfObjectOpResult() {
718 : return offsetof(IonOOLSetterOpExitFrameLayout, result_);
719 : }
720 :
721 : static size_t Size() {
722 : return sizeof(IonOOLSetterOpExitFrameLayout);
723 : }
724 : };
725 :
726 : // ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
727 : // ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
728 : // ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
729 : // bool strict)
730 : class IonOOLProxyExitFrameLayout
731 : {
732 : protected: // only to silence a clang warning about unused private fields
733 : ExitFooterFrame footer_;
734 : ExitFrameLayout exit_;
735 :
736 : // The proxy object.
737 : JSObject* proxy_;
738 :
739 : // id for HandleId
740 : jsid id_;
741 :
742 : // space for MutableHandleValue result
743 : // use two uint32_t so compiler doesn't align.
744 : uint32_t vp0_;
745 : uint32_t vp1_;
746 :
747 : // pointer to root the stub's JitCode
748 : JitCode* stubCode_;
749 :
750 : public:
751 19 : static JitCode* Token() { return (JitCode*)IonOOLProxyExitFrameLayoutToken; }
752 :
753 0 : static inline size_t Size() {
754 0 : return sizeof(IonOOLProxyExitFrameLayout);
755 : }
756 :
757 0 : static size_t offsetOfResult() {
758 0 : return offsetof(IonOOLProxyExitFrameLayout, vp0_);
759 : }
760 :
761 0 : inline JitCode** stubCode() {
762 0 : return &stubCode_;
763 : }
764 0 : inline Value* vp() {
765 0 : return reinterpret_cast<Value*>(&vp0_);
766 : }
767 0 : inline jsid* id() {
768 0 : return &id_;
769 : }
770 0 : inline JSObject** proxy() {
771 0 : return &proxy_;
772 : }
773 : };
774 :
775 : class IonDOMExitFrameLayout
776 : {
777 : protected: // only to silence a clang warning about unused private fields
778 : ExitFooterFrame footer_;
779 : ExitFrameLayout exit_;
780 : JSObject* thisObj;
781 :
782 : // We need to split the Value into 2 fields of 32 bits, otherwise the C++
783 : // compiler may add some padding between the fields.
784 : uint32_t loCalleeResult_;
785 : uint32_t hiCalleeResult_;
786 :
787 : public:
788 19 : static JitCode* GetterToken() { return (JitCode*)IonDOMExitFrameLayoutGetterToken; }
789 19 : static JitCode* SetterToken() { return (JitCode*)IonDOMExitFrameLayoutSetterToken; }
790 :
791 0 : static inline size_t Size() {
792 0 : return sizeof(IonDOMExitFrameLayout);
793 : }
794 :
795 0 : static size_t offsetOfResult() {
796 0 : return offsetof(IonDOMExitFrameLayout, loCalleeResult_);
797 : }
798 0 : inline Value* vp() {
799 0 : return reinterpret_cast<Value*>(&loCalleeResult_);
800 : }
801 0 : inline JSObject** thisObjAddress() {
802 0 : return &thisObj;
803 : }
804 : inline bool isMethodFrame();
805 : };
806 :
807 : struct IonDOMMethodExitFrameLayoutTraits;
808 :
809 : class IonDOMMethodExitFrameLayout
810 : {
811 : protected: // only to silence a clang warning about unused private fields
812 : ExitFooterFrame footer_;
813 : ExitFrameLayout exit_;
814 : // This must be the last thing pushed, so as to stay common with
815 : // IonDOMExitFrameLayout.
816 : JSObject* thisObj_;
817 : Value* argv_;
818 : uintptr_t argc_;
819 :
820 : // We need to split the Value into 2 fields of 32 bits, otherwise the C++
821 : // compiler may add some padding between the fields.
822 : uint32_t loCalleeResult_;
823 : uint32_t hiCalleeResult_;
824 :
825 : friend struct IonDOMMethodExitFrameLayoutTraits;
826 :
827 : public:
828 19 : static JitCode* Token() { return (JitCode*)IonDOMMethodExitFrameLayoutToken; }
829 :
830 0 : static inline size_t Size() {
831 0 : return sizeof(IonDOMMethodExitFrameLayout);
832 : }
833 :
834 0 : static size_t offsetOfResult() {
835 0 : return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_);
836 : }
837 :
838 0 : inline Value* vp() {
839 : // The code in visitCallDOMNative depends on this static assert holding
840 : JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) ==
841 : (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
842 0 : return reinterpret_cast<Value*>(&loCalleeResult_);
843 : }
844 : inline JSObject** thisObjAddress() {
845 : return &thisObj_;
846 : }
847 0 : inline uintptr_t argc() {
848 0 : return argc_;
849 : }
850 : };
851 :
852 : inline bool
853 0 : IonDOMExitFrameLayout::isMethodFrame()
854 : {
855 0 : return footer_.jitCode() == IonDOMMethodExitFrameLayout::Token();
856 : }
857 :
858 : template <>
859 : inline bool
860 19 : ExitFrameLayout::is<IonDOMExitFrameLayout>()
861 : {
862 19 : JitCode* code = footer()->jitCode();
863 : return
864 38 : code == IonDOMExitFrameLayout::GetterToken() ||
865 38 : code == IonDOMExitFrameLayout::SetterToken() ||
866 38 : code == IonDOMMethodExitFrameLayout::Token();
867 : }
868 :
869 : template <>
870 : inline IonDOMExitFrameLayout*
871 0 : ExitFrameLayout::as<IonDOMExitFrameLayout>()
872 : {
873 0 : MOZ_ASSERT(is<IonDOMExitFrameLayout>());
874 0 : return reinterpret_cast<IonDOMExitFrameLayout*>(footer());
875 : }
876 :
877 : struct IonDOMMethodExitFrameLayoutTraits {
878 : static const size_t offsetOfArgcFromArgv =
879 : offsetof(IonDOMMethodExitFrameLayout, argc_) -
880 : offsetof(IonDOMMethodExitFrameLayout, argv_);
881 : };
882 :
883 : // Cannot inherit implementation since we need to extend the top of
884 : // ExitFrameLayout.
885 : class LazyLinkExitFrameLayout
886 : {
887 : protected: // silence clang warning about unused private fields
888 : JitCode* stubCode_;
889 : ExitFooterFrame footer_;
890 : JitFrameLayout exit_;
891 :
892 : public:
893 22 : static JitCode* Token() { return (JitCode*) LazyLinkExitFrameLayoutToken; }
894 :
895 : static inline size_t Size() {
896 : return sizeof(LazyLinkExitFrameLayout);
897 : }
898 :
899 0 : inline JitCode** stubCode() {
900 0 : return &stubCode_;
901 : }
902 3 : inline JitFrameLayout* jsFrame() {
903 3 : return &exit_;
904 : }
905 3 : static size_t offsetOfExitFrame() {
906 3 : return offsetof(LazyLinkExitFrameLayout, exit_);
907 : }
908 : };
909 :
910 : template <>
911 : inline LazyLinkExitFrameLayout*
912 3 : ExitFrameLayout::as<LazyLinkExitFrameLayout>()
913 : {
914 3 : MOZ_ASSERT(is<LazyLinkExitFrameLayout>());
915 3 : uint8_t* sp = reinterpret_cast<uint8_t*>(this);
916 3 : sp -= LazyLinkExitFrameLayout::offsetOfExitFrame();
917 3 : return reinterpret_cast<LazyLinkExitFrameLayout*>(sp);
918 : }
919 :
920 : class ICStub;
921 :
922 : class JitStubFrameLayout : public CommonFrameLayout
923 : {
924 : // Info on the stack
925 : //
926 : // --------------------
927 : // |JitStubFrameLayout|
928 : // +------------------+
929 : // | - Descriptor | => Marks end of JitFrame_IonJS
930 : // | - returnaddres |
931 : // +------------------+
932 : // | - StubPtr | => First thing pushed in a stub only when the stub will do
933 : // -------------------- a vmcall. Else we cannot have JitStubFrame. But technically
934 : // not a member of the layout.
935 :
936 : public:
937 0 : static size_t Size() {
938 0 : return sizeof(JitStubFrameLayout);
939 : }
940 :
941 22 : static inline int reverseOffsetOfStubPtr() {
942 22 : return -int(sizeof(void*));
943 : }
944 :
945 22 : inline ICStub* maybeStubPtr() {
946 22 : uint8_t* fp = reinterpret_cast<uint8_t*>(this);
947 22 : return *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr());
948 : }
949 : };
950 :
951 : class BaselineStubFrameLayout : public JitStubFrameLayout
952 : {
953 : // Info on the stack
954 : //
955 : // -------------------------
956 : // |BaselineStubFrameLayout|
957 : // +-----------------------+
958 : // | - Descriptor | => Marks end of JitFrame_BaselineJS
959 : // | - returnaddres |
960 : // +-----------------------+
961 : // | - StubPtr | => First thing pushed in a stub only when the stub will do
962 : // +-----------------------+ a vmcall. Else we cannot have BaselineStubFrame.
963 : // | - FramePtr | => Baseline stubs also need to push the frame ptr when doing
964 : // ------------------------- a vmcall.
965 : // Technically these last two variables are not part of the
966 : // layout.
967 :
968 : public:
969 385 : static inline size_t Size() {
970 385 : return sizeof(BaselineStubFrameLayout);
971 : }
972 :
973 0 : static inline int reverseOffsetOfSavedFramePtr() {
974 0 : return -int(2 * sizeof(void*));
975 : }
976 :
977 0 : void* reverseSavedFramePtr() {
978 0 : uint8_t* addr = ((uint8_t*) this) + reverseOffsetOfSavedFramePtr();
979 0 : return *(void**)addr;
980 : }
981 :
982 0 : inline void setStubPtr(ICStub* stub) {
983 0 : uint8_t* fp = reinterpret_cast<uint8_t*>(this);
984 0 : *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr()) = stub;
985 0 : }
986 : };
987 :
988 : // An invalidation bailout stack is at the stack pointer for the callee frame.
989 : class InvalidationBailoutStack
990 : {
991 : RegisterDump::FPUArray fpregs_;
992 : RegisterDump::GPRArray regs_;
993 : IonScript* ionScript_;
994 : uint8_t* osiPointReturnAddress_;
995 :
996 : public:
997 0 : uint8_t* sp() const {
998 0 : return (uint8_t*) this + sizeof(InvalidationBailoutStack);
999 : }
1000 : JitFrameLayout* fp() const;
1001 0 : MachineState machine() {
1002 0 : return MachineState::FromBailout(regs_, fpregs_);
1003 : }
1004 :
1005 0 : IonScript* ionScript() const {
1006 0 : return ionScript_;
1007 : }
1008 0 : uint8_t* osiPointReturnAddress() const {
1009 0 : return osiPointReturnAddress_;
1010 : }
1011 : static size_t offsetOfFpRegs() {
1012 : return offsetof(InvalidationBailoutStack, fpregs_);
1013 : }
1014 : static size_t offsetOfRegs() {
1015 : return offsetof(InvalidationBailoutStack, regs_);
1016 : }
1017 :
1018 : void checkInvariants() const;
1019 : };
1020 :
1021 : void
1022 : GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes);
1023 :
1024 : CalleeToken
1025 : TraceCalleeToken(JSTracer* trc, CalleeToken token);
1026 :
1027 : // Baseline requires one slot for this/argument type checks.
1028 : static const uint32_t MinJITStackSize = 1;
1029 :
1030 : } /* namespace jit */
1031 : } /* namespace js */
1032 :
1033 : #endif /* jit_JitFrames_h */
|