|
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_IonFrames_h |
|
8 #define jit_IonFrames_h |
|
9 |
|
10 #ifdef JS_ION |
|
11 |
|
12 #include <stdint.h> |
|
13 |
|
14 #include "jscntxt.h" |
|
15 #include "jsfun.h" |
|
16 |
|
17 #include "jit/JitFrameIterator.h" |
|
18 |
|
19 namespace js { |
|
20 namespace jit { |
|
21 |
|
22 typedef void * CalleeToken; |
|
23 |
|
24 enum CalleeTokenTag |
|
25 { |
|
26 CalleeToken_Function = 0x0, // untagged |
|
27 CalleeToken_Script = 0x1 |
|
28 }; |
|
29 |
|
30 static inline CalleeTokenTag |
|
31 GetCalleeTokenTag(CalleeToken token) |
|
32 { |
|
33 CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3); |
|
34 JS_ASSERT(tag <= CalleeToken_Script); |
|
35 return tag; |
|
36 } |
|
37 static inline CalleeToken |
|
38 CalleeToToken(JSFunction *fun) |
|
39 { |
|
40 return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function)); |
|
41 } |
|
42 static inline CalleeToken |
|
43 CalleeToToken(JSScript *script) |
|
44 { |
|
45 return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script)); |
|
46 } |
|
47 static inline bool |
|
48 CalleeTokenIsFunction(CalleeToken token) |
|
49 { |
|
50 return GetCalleeTokenTag(token) == CalleeToken_Function; |
|
51 } |
|
52 static inline JSFunction * |
|
53 CalleeTokenToFunction(CalleeToken token) |
|
54 { |
|
55 JS_ASSERT(CalleeTokenIsFunction(token)); |
|
56 return (JSFunction *)token; |
|
57 } |
|
58 static inline JSScript * |
|
59 CalleeTokenToScript(CalleeToken token) |
|
60 { |
|
61 JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script); |
|
62 return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3)); |
|
63 } |
|
64 |
|
65 static inline JSScript * |
|
66 ScriptFromCalleeToken(CalleeToken token) |
|
67 { |
|
68 switch (GetCalleeTokenTag(token)) { |
|
69 case CalleeToken_Script: |
|
70 return CalleeTokenToScript(token); |
|
71 case CalleeToken_Function: |
|
72 return CalleeTokenToFunction(token)->nonLazyScript(); |
|
73 } |
|
74 MOZ_ASSUME_UNREACHABLE("invalid callee token tag"); |
|
75 } |
|
76 |
|
77 // In between every two frames lies a small header describing both frames. This |
|
78 // header, minimally, contains a returnAddress word and a descriptor word. The |
|
79 // descriptor describes the size and type of the previous frame, whereas the |
|
80 // returnAddress describes the address the newer frame (the callee) will return |
|
81 // to. The exact mechanism in which frames are laid out is architecture |
|
82 // dependent. |
|
83 // |
|
84 // Two special frame types exist. Entry frames begin an ion activation, and |
|
85 // therefore there is exactly one per activation of jit::Cannon. Exit frames |
|
86 // are necessary to leave JIT code and enter C++, and thus, C++ code will |
|
87 // always begin iterating from the topmost exit frame. |
|
88 |
|
89 class LSafepoint; |
|
90 |
|
91 // Two-tuple that lets you look up the safepoint entry given the |
|
92 // displacement of a call instruction within the JIT code. |
|
93 class SafepointIndex |
|
94 { |
|
95 // The displacement is the distance from the first byte of the JIT'd code |
|
96 // to the return address (of the call that the safepoint was generated for). |
|
97 uint32_t displacement_; |
|
98 |
|
99 union { |
|
100 LSafepoint *safepoint_; |
|
101 |
|
102 // Offset to the start of the encoded safepoint in the safepoint stream. |
|
103 uint32_t safepointOffset_; |
|
104 }; |
|
105 |
|
106 #ifdef DEBUG |
|
107 bool resolved; |
|
108 #endif |
|
109 |
|
110 public: |
|
111 SafepointIndex(uint32_t displacement, LSafepoint *safepoint) |
|
112 : displacement_(displacement), |
|
113 safepoint_(safepoint) |
|
114 #ifdef DEBUG |
|
115 , resolved(false) |
|
116 #endif |
|
117 { } |
|
118 |
|
119 void resolve(); |
|
120 |
|
121 LSafepoint *safepoint() { |
|
122 JS_ASSERT(!resolved); |
|
123 return safepoint_; |
|
124 } |
|
125 uint32_t displacement() const { |
|
126 return displacement_; |
|
127 } |
|
128 uint32_t safepointOffset() const { |
|
129 return safepointOffset_; |
|
130 } |
|
131 void adjustDisplacement(uint32_t offset) { |
|
132 JS_ASSERT(offset >= displacement_); |
|
133 displacement_ = offset; |
|
134 } |
|
135 inline SnapshotOffset snapshotOffset() const; |
|
136 inline bool hasSnapshotOffset() const; |
|
137 }; |
|
138 |
|
139 class MacroAssembler; |
|
140 // The OSI point is patched to a call instruction. Therefore, the |
|
141 // returnPoint for an OSI call is the address immediately following that |
|
142 // call instruction. The displacement of that point within the assembly |
|
143 // buffer is the |returnPointDisplacement|. |
|
144 class OsiIndex |
|
145 { |
|
146 uint32_t callPointDisplacement_; |
|
147 uint32_t snapshotOffset_; |
|
148 |
|
149 public: |
|
150 OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset) |
|
151 : callPointDisplacement_(callPointDisplacement), |
|
152 snapshotOffset_(snapshotOffset) |
|
153 { } |
|
154 |
|
155 uint32_t returnPointDisplacement() const; |
|
156 uint32_t callPointDisplacement() const { |
|
157 return callPointDisplacement_; |
|
158 } |
|
159 uint32_t snapshotOffset() const { |
|
160 return snapshotOffset_; |
|
161 } |
|
162 void fixUpOffset(MacroAssembler &masm); |
|
163 }; |
|
164 |
|
165 // The layout of an Ion frame on the C stack is roughly: |
|
166 // argN _ |
|
167 // ... \ - These are jsvals |
|
168 // arg0 / |
|
169 // -3 this _/ |
|
170 // -2 callee |
|
171 // -1 descriptor |
|
172 // 0 returnAddress |
|
173 // .. locals .. |
|
174 |
|
175 // The descriptor is organized into three sections: |
|
176 // [ frame size | constructing bit | frame type ] |
|
177 // < highest - - - - - - - - - - - - - - lowest > |
|
178 static const uintptr_t FRAMESIZE_SHIFT = 4; |
|
179 static const uintptr_t FRAMETYPE_BITS = 4; |
|
180 static const uintptr_t FRAMETYPE_MASK = (1 << FRAMETYPE_BITS) - 1; |
|
181 |
|
182 // Ion frames have a few important numbers associated with them: |
|
183 // Local depth: The number of bytes required to spill local variables. |
|
184 // Argument depth: The number of bytes required to push arguments and make |
|
185 // a function call. |
|
186 // Slack: A frame may temporarily use extra stack to resolve cycles. |
|
187 // |
|
188 // The (local + argument) depth determines the "fixed frame size". The fixed |
|
189 // frame size is the distance between the stack pointer and the frame header. |
|
190 // Thus, fixed >= (local + argument). |
|
191 // |
|
192 // In order to compress guards, we create shared jump tables that recover the |
|
193 // script from the stack and recover a snapshot pointer based on which jump was |
|
194 // taken. Thus, we create a jump table for each fixed frame size. |
|
195 // |
|
196 // Jump tables are big. To control the amount of jump tables we generate, each |
|
197 // platform chooses how to segregate stack size classes based on its |
|
198 // architecture. |
|
199 // |
|
200 // On some architectures, these jump tables are not used at all, or frame |
|
201 // size segregation is not needed. Thus, there is an option for a frame to not |
|
202 // have any frame size class, and to be totally dynamic. |
|
203 static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1); |
|
204 |
|
205 class FrameSizeClass |
|
206 { |
|
207 uint32_t class_; |
|
208 |
|
209 explicit FrameSizeClass(uint32_t class_) : class_(class_) |
|
210 { } |
|
211 |
|
212 public: |
|
213 FrameSizeClass() |
|
214 { } |
|
215 |
|
216 static FrameSizeClass None() { |
|
217 return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID); |
|
218 } |
|
219 static FrameSizeClass FromClass(uint32_t class_) { |
|
220 return FrameSizeClass(class_); |
|
221 } |
|
222 |
|
223 // These functions are implemented in specific CodeGenerator-* files. |
|
224 static FrameSizeClass FromDepth(uint32_t frameDepth); |
|
225 static FrameSizeClass ClassLimit(); |
|
226 uint32_t frameSize() const; |
|
227 |
|
228 uint32_t classId() const { |
|
229 JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID); |
|
230 return class_; |
|
231 } |
|
232 |
|
233 bool operator ==(const FrameSizeClass &other) const { |
|
234 return class_ == other.class_; |
|
235 } |
|
236 bool operator !=(const FrameSizeClass &other) const { |
|
237 return class_ != other.class_; |
|
238 } |
|
239 }; |
|
240 |
|
241 struct BaselineBailoutInfo; |
|
242 |
|
243 // Data needed to recover from an exception. |
|
244 struct ResumeFromException |
|
245 { |
|
246 static const uint32_t RESUME_ENTRY_FRAME = 0; |
|
247 static const uint32_t RESUME_CATCH = 1; |
|
248 static const uint32_t RESUME_FINALLY = 2; |
|
249 static const uint32_t RESUME_FORCED_RETURN = 3; |
|
250 static const uint32_t RESUME_BAILOUT = 4; |
|
251 |
|
252 uint8_t *framePointer; |
|
253 uint8_t *stackPointer; |
|
254 uint8_t *target; |
|
255 uint32_t kind; |
|
256 |
|
257 // Value to push when resuming into a |finally| block. |
|
258 Value exception; |
|
259 |
|
260 BaselineBailoutInfo *bailoutInfo; |
|
261 }; |
|
262 |
|
263 void HandleException(ResumeFromException *rfe); |
|
264 void HandleParallelFailure(ResumeFromException *rfe); |
|
265 |
|
266 void EnsureExitFrame(IonCommonFrameLayout *frame); |
|
267 |
|
268 void MarkJitActivations(JSRuntime *rt, JSTracer *trc); |
|
269 void MarkIonCompilerRoots(JSTracer *trc); |
|
270 |
|
271 #ifdef JSGC_GENERATIONAL |
|
272 void UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc); |
|
273 #endif |
|
274 |
|
275 static inline uint32_t |
|
276 MakeFrameDescriptor(uint32_t frameSize, FrameType type) |
|
277 { |
|
278 return (frameSize << FRAMESIZE_SHIFT) | type; |
|
279 } |
|
280 |
|
281 // Returns the JSScript associated with the topmost Ion frame. |
|
282 inline JSScript * |
|
283 GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode) |
|
284 { |
|
285 JitFrameIterator iter(ionTop, mode); |
|
286 JS_ASSERT(iter.type() == JitFrame_Exit); |
|
287 ++iter; |
|
288 |
|
289 JS_ASSERT(iter.returnAddressToFp() != nullptr); |
|
290 if (returnAddrOut) |
|
291 *returnAddrOut = (void *) iter.returnAddressToFp(); |
|
292 |
|
293 if (iter.isBaselineStub()) { |
|
294 ++iter; |
|
295 JS_ASSERT(iter.isBaselineJS()); |
|
296 } |
|
297 |
|
298 JS_ASSERT(iter.isScripted()); |
|
299 return iter.script(); |
|
300 } |
|
301 |
|
302 static JitCode *const ION_FRAME_DOMGETTER = (JitCode *)0x1; |
|
303 static JitCode *const ION_FRAME_DOMSETTER = (JitCode *)0x2; |
|
304 static JitCode *const ION_FRAME_DOMMETHOD = (JitCode *)0x3; |
|
305 static JitCode *const ION_FRAME_OOL_NATIVE = (JitCode *)0x4; |
|
306 static JitCode *const ION_FRAME_OOL_PROPERTY_OP = (JitCode *)0x5; |
|
307 static JitCode *const ION_FRAME_OOL_PROXY = (JitCode *)0x6; |
|
308 |
|
309 // Layout of the frame prefix. This assumes the stack architecture grows down. |
|
310 // If this is ever not the case, we'll have to refactor. |
|
311 class IonCommonFrameLayout |
|
312 { |
|
313 uint8_t *returnAddress_; |
|
314 uintptr_t descriptor_; |
|
315 |
|
316 static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1; |
|
317 |
|
318 public: |
|
319 static size_t offsetOfDescriptor() { |
|
320 return offsetof(IonCommonFrameLayout, descriptor_); |
|
321 } |
|
322 static size_t offsetOfReturnAddress() { |
|
323 return offsetof(IonCommonFrameLayout, returnAddress_); |
|
324 } |
|
325 FrameType prevType() const { |
|
326 return FrameType(descriptor_ & FrameTypeMask); |
|
327 } |
|
328 void changePrevType(FrameType type) { |
|
329 descriptor_ &= ~FrameTypeMask; |
|
330 descriptor_ |= type; |
|
331 } |
|
332 size_t prevFrameLocalSize() const { |
|
333 return descriptor_ >> FRAMESIZE_SHIFT; |
|
334 } |
|
335 void setFrameDescriptor(size_t size, FrameType type) { |
|
336 descriptor_ = (size << FRAMESIZE_SHIFT) | type; |
|
337 } |
|
338 uint8_t *returnAddress() const { |
|
339 return returnAddress_; |
|
340 } |
|
341 void setReturnAddress(uint8_t *addr) { |
|
342 returnAddress_ = addr; |
|
343 } |
|
344 }; |
|
345 |
|
346 class IonJSFrameLayout : public IonCommonFrameLayout |
|
347 { |
|
348 CalleeToken calleeToken_; |
|
349 uintptr_t numActualArgs_; |
|
350 |
|
351 public: |
|
352 CalleeToken calleeToken() const { |
|
353 return calleeToken_; |
|
354 } |
|
355 void replaceCalleeToken(CalleeToken calleeToken) { |
|
356 calleeToken_ = calleeToken; |
|
357 } |
|
358 |
|
359 static size_t offsetOfCalleeToken() { |
|
360 return offsetof(IonJSFrameLayout, calleeToken_); |
|
361 } |
|
362 static size_t offsetOfNumActualArgs() { |
|
363 return offsetof(IonJSFrameLayout, numActualArgs_); |
|
364 } |
|
365 static size_t offsetOfThis() { |
|
366 IonJSFrameLayout *base = nullptr; |
|
367 return reinterpret_cast<size_t>(&base->argv()[0]); |
|
368 } |
|
369 static size_t offsetOfActualArgs() { |
|
370 IonJSFrameLayout *base = nullptr; |
|
371 // +1 to skip |this|. |
|
372 return reinterpret_cast<size_t>(&base->argv()[1]); |
|
373 } |
|
374 static size_t offsetOfActualArg(size_t arg) { |
|
375 return offsetOfActualArgs() + arg * sizeof(Value); |
|
376 } |
|
377 |
|
378 Value thisv() { |
|
379 return argv()[0]; |
|
380 } |
|
381 Value *argv() { |
|
382 return (Value *)(this + 1); |
|
383 } |
|
384 uintptr_t numActualArgs() const { |
|
385 return numActualArgs_; |
|
386 } |
|
387 |
|
388 // Computes a reference to a slot, where a slot is a distance from the base |
|
389 // frame pointer (as would be used for LStackSlot). |
|
390 uintptr_t *slotRef(uint32_t slot) { |
|
391 return (uintptr_t *)((uint8_t *)this - slot); |
|
392 } |
|
393 |
|
394 static inline size_t Size() { |
|
395 return sizeof(IonJSFrameLayout); |
|
396 } |
|
397 }; |
|
398 |
|
399 // this is the layout of the frame that is used when we enter Ion code from platform ABI code |
|
400 class IonEntryFrameLayout : public IonJSFrameLayout |
|
401 { |
|
402 public: |
|
403 static inline size_t Size() { |
|
404 return sizeof(IonEntryFrameLayout); |
|
405 } |
|
406 }; |
|
407 |
|
408 class IonRectifierFrameLayout : public IonJSFrameLayout |
|
409 { |
|
410 public: |
|
411 static inline size_t Size() { |
|
412 return sizeof(IonRectifierFrameLayout); |
|
413 } |
|
414 }; |
|
415 |
|
416 // The callee token is now dead. |
|
417 class IonUnwoundRectifierFrameLayout : public IonRectifierFrameLayout |
|
418 { |
|
419 public: |
|
420 static inline size_t Size() { |
|
421 // It is not necessary to accout for an extra callee token here because |
|
422 // sizeof(IonExitFrameLayout) == sizeof(IonRectifierFrameLayout) due to |
|
423 // extra padding. |
|
424 return sizeof(IonUnwoundRectifierFrameLayout); |
|
425 } |
|
426 }; |
|
427 |
|
428 // GC related data used to keep alive data surrounding the Exit frame. |
|
429 class IonExitFooterFrame |
|
430 { |
|
431 const VMFunction *function_; |
|
432 JitCode *jitCode_; |
|
433 |
|
434 public: |
|
435 static inline size_t Size() { |
|
436 return sizeof(IonExitFooterFrame); |
|
437 } |
|
438 inline JitCode *jitCode() const { |
|
439 return jitCode_; |
|
440 } |
|
441 inline JitCode **addressOfJitCode() { |
|
442 return &jitCode_; |
|
443 } |
|
444 inline const VMFunction *function() const { |
|
445 return function_; |
|
446 } |
|
447 |
|
448 // This should only be called for function()->outParam == Type_Handle |
|
449 template <typename T> |
|
450 T *outParam() { |
|
451 return reinterpret_cast<T *>(reinterpret_cast<char *>(this) - sizeof(T)); |
|
452 } |
|
453 }; |
|
454 |
|
455 class IonNativeExitFrameLayout; |
|
456 class IonOOLNativeExitFrameLayout; |
|
457 class IonOOLPropertyOpExitFrameLayout; |
|
458 class IonOOLProxyExitFrameLayout; |
|
459 class IonDOMExitFrameLayout; |
|
460 |
|
461 // this is the frame layout when we are exiting ion code, and about to enter platform ABI code |
|
462 class IonExitFrameLayout : public IonCommonFrameLayout |
|
463 { |
|
464 inline uint8_t *top() { |
|
465 return reinterpret_cast<uint8_t *>(this + 1); |
|
466 } |
|
467 |
|
468 public: |
|
469 static inline size_t Size() { |
|
470 return sizeof(IonExitFrameLayout); |
|
471 } |
|
472 static inline size_t SizeWithFooter() { |
|
473 return Size() + IonExitFooterFrame::Size(); |
|
474 } |
|
475 |
|
476 inline IonExitFooterFrame *footer() { |
|
477 uint8_t *sp = reinterpret_cast<uint8_t *>(this); |
|
478 return reinterpret_cast<IonExitFooterFrame *>(sp - IonExitFooterFrame::Size()); |
|
479 } |
|
480 |
|
481 // argBase targets the point which precedes the exit frame. Arguments of VM |
|
482 // each wrapper are pushed before the exit frame. This correspond exactly |
|
483 // to the value of the argBase register of the generateVMWrapper function. |
|
484 inline uint8_t *argBase() { |
|
485 JS_ASSERT(footer()->jitCode() != nullptr); |
|
486 return top(); |
|
487 } |
|
488 |
|
489 inline bool isWrapperExit() { |
|
490 return footer()->function() != nullptr; |
|
491 } |
|
492 inline bool isNativeExit() { |
|
493 return footer()->jitCode() == nullptr; |
|
494 } |
|
495 inline bool isOOLNativeExit() { |
|
496 return footer()->jitCode() == ION_FRAME_OOL_NATIVE; |
|
497 } |
|
498 inline bool isOOLPropertyOpExit() { |
|
499 return footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP; |
|
500 } |
|
501 inline bool isOOLProxyExit() { |
|
502 return footer()->jitCode() == ION_FRAME_OOL_PROXY; |
|
503 } |
|
504 inline bool isDomExit() { |
|
505 JitCode *code = footer()->jitCode(); |
|
506 return |
|
507 code == ION_FRAME_DOMGETTER || |
|
508 code == ION_FRAME_DOMSETTER || |
|
509 code == ION_FRAME_DOMMETHOD; |
|
510 } |
|
511 |
|
512 inline IonNativeExitFrameLayout *nativeExit() { |
|
513 // see CodeGenerator::visitCallNative |
|
514 JS_ASSERT(isNativeExit()); |
|
515 return reinterpret_cast<IonNativeExitFrameLayout *>(footer()); |
|
516 } |
|
517 inline IonOOLNativeExitFrameLayout *oolNativeExit() { |
|
518 JS_ASSERT(isOOLNativeExit()); |
|
519 return reinterpret_cast<IonOOLNativeExitFrameLayout *>(footer()); |
|
520 } |
|
521 inline IonOOLPropertyOpExitFrameLayout *oolPropertyOpExit() { |
|
522 JS_ASSERT(isOOLPropertyOpExit()); |
|
523 return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer()); |
|
524 } |
|
525 inline IonOOLProxyExitFrameLayout *oolProxyExit() { |
|
526 JS_ASSERT(isOOLProxyExit()); |
|
527 return reinterpret_cast<IonOOLProxyExitFrameLayout *>(footer()); |
|
528 } |
|
529 inline IonDOMExitFrameLayout *DOMExit() { |
|
530 JS_ASSERT(isDomExit()); |
|
531 return reinterpret_cast<IonDOMExitFrameLayout *>(footer()); |
|
532 } |
|
533 }; |
|
534 |
|
535 // Cannot inherit implementa<tion since we need to extend the top of |
|
536 // IonExitFrameLayout. |
|
537 class IonNativeExitFrameLayout |
|
538 { |
|
539 protected: // only to silence a clang warning about unused private fields |
|
540 IonExitFooterFrame footer_; |
|
541 IonExitFrameLayout exit_; |
|
542 uintptr_t argc_; |
|
543 |
|
544 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ |
|
545 // compiler may add some padding between the fields. |
|
546 uint32_t loCalleeResult_; |
|
547 uint32_t hiCalleeResult_; |
|
548 |
|
549 public: |
|
550 static inline size_t Size() { |
|
551 return sizeof(IonNativeExitFrameLayout); |
|
552 } |
|
553 |
|
554 static size_t offsetOfResult() { |
|
555 return offsetof(IonNativeExitFrameLayout, loCalleeResult_); |
|
556 } |
|
557 inline Value *vp() { |
|
558 return reinterpret_cast<Value*>(&loCalleeResult_); |
|
559 } |
|
560 inline uintptr_t argc() const { |
|
561 return argc_; |
|
562 } |
|
563 }; |
|
564 |
|
565 class IonOOLNativeExitFrameLayout |
|
566 { |
|
567 protected: // only to silence a clang warning about unused private fields |
|
568 IonExitFooterFrame footer_; |
|
569 IonExitFrameLayout exit_; |
|
570 |
|
571 // pointer to root the stub's JitCode |
|
572 JitCode *stubCode_; |
|
573 |
|
574 uintptr_t argc_; |
|
575 |
|
576 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ |
|
577 // compiler may add some padding between the fields. |
|
578 uint32_t loCalleeResult_; |
|
579 uint32_t hiCalleeResult_; |
|
580 |
|
581 // Split Value for |this| and args above. |
|
582 uint32_t loThis_; |
|
583 uint32_t hiThis_; |
|
584 |
|
585 public: |
|
586 static inline size_t Size(size_t argc) { |
|
587 // The frame accounts for the callee/result and |this|, so we only need args. |
|
588 return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value)); |
|
589 } |
|
590 |
|
591 static size_t offsetOfResult() { |
|
592 return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_); |
|
593 } |
|
594 |
|
595 inline JitCode **stubCode() { |
|
596 return &stubCode_; |
|
597 } |
|
598 inline Value *vp() { |
|
599 return reinterpret_cast<Value*>(&loCalleeResult_); |
|
600 } |
|
601 inline Value *thisp() { |
|
602 return reinterpret_cast<Value*>(&loThis_); |
|
603 } |
|
604 inline uintptr_t argc() const { |
|
605 return argc_; |
|
606 } |
|
607 }; |
|
608 |
|
609 class IonOOLPropertyOpExitFrameLayout |
|
610 { |
|
611 protected: // only to silence a clang warning about unused private fields |
|
612 IonExitFooterFrame footer_; |
|
613 IonExitFrameLayout exit_; |
|
614 |
|
615 // Object for HandleObject |
|
616 JSObject *obj_; |
|
617 |
|
618 // id for HandleId |
|
619 jsid id_; |
|
620 |
|
621 // space for MutableHandleValue result |
|
622 // use two uint32_t so compiler doesn't align. |
|
623 uint32_t vp0_; |
|
624 uint32_t vp1_; |
|
625 |
|
626 // pointer to root the stub's JitCode |
|
627 JitCode *stubCode_; |
|
628 |
|
629 public: |
|
630 static inline size_t Size() { |
|
631 return sizeof(IonOOLPropertyOpExitFrameLayout); |
|
632 } |
|
633 |
|
634 static size_t offsetOfResult() { |
|
635 return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_); |
|
636 } |
|
637 |
|
638 inline JitCode **stubCode() { |
|
639 return &stubCode_; |
|
640 } |
|
641 inline Value *vp() { |
|
642 return reinterpret_cast<Value*>(&vp0_); |
|
643 } |
|
644 inline jsid *id() { |
|
645 return &id_; |
|
646 } |
|
647 inline JSObject **obj() { |
|
648 return &obj_; |
|
649 } |
|
650 }; |
|
651 |
|
652 // Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, |
|
653 // MutableHandleValue vp) |
|
654 // Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, |
|
655 // bool strict, MutableHandleValue vp) |
|
656 class IonOOLProxyExitFrameLayout |
|
657 { |
|
658 protected: // only to silence a clang warning about unused private fields |
|
659 IonExitFooterFrame footer_; |
|
660 IonExitFrameLayout exit_; |
|
661 |
|
662 // The proxy object. |
|
663 JSObject *proxy_; |
|
664 |
|
665 // Object for HandleObject |
|
666 JSObject *receiver_; |
|
667 |
|
668 // id for HandleId |
|
669 jsid id_; |
|
670 |
|
671 // space for MutableHandleValue result |
|
672 // use two uint32_t so compiler doesn't align. |
|
673 uint32_t vp0_; |
|
674 uint32_t vp1_; |
|
675 |
|
676 // pointer to root the stub's JitCode |
|
677 JitCode *stubCode_; |
|
678 |
|
679 public: |
|
680 static inline size_t Size() { |
|
681 return sizeof(IonOOLProxyExitFrameLayout); |
|
682 } |
|
683 |
|
684 static size_t offsetOfResult() { |
|
685 return offsetof(IonOOLProxyExitFrameLayout, vp0_); |
|
686 } |
|
687 |
|
688 inline JitCode **stubCode() { |
|
689 return &stubCode_; |
|
690 } |
|
691 inline Value *vp() { |
|
692 return reinterpret_cast<Value*>(&vp0_); |
|
693 } |
|
694 inline jsid *id() { |
|
695 return &id_; |
|
696 } |
|
697 inline JSObject **receiver() { |
|
698 return &receiver_; |
|
699 } |
|
700 inline JSObject **proxy() { |
|
701 return &proxy_; |
|
702 } |
|
703 }; |
|
704 |
|
705 class IonDOMExitFrameLayout |
|
706 { |
|
707 protected: // only to silence a clang warning about unused private fields |
|
708 IonExitFooterFrame footer_; |
|
709 IonExitFrameLayout exit_; |
|
710 JSObject *thisObj; |
|
711 |
|
712 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ |
|
713 // compiler may add some padding between the fields. |
|
714 uint32_t loCalleeResult_; |
|
715 uint32_t hiCalleeResult_; |
|
716 |
|
717 public: |
|
718 static inline size_t Size() { |
|
719 return sizeof(IonDOMExitFrameLayout); |
|
720 } |
|
721 |
|
722 static size_t offsetOfResult() { |
|
723 return offsetof(IonDOMExitFrameLayout, loCalleeResult_); |
|
724 } |
|
725 inline Value *vp() { |
|
726 return reinterpret_cast<Value*>(&loCalleeResult_); |
|
727 } |
|
728 inline JSObject **thisObjAddress() { |
|
729 return &thisObj; |
|
730 } |
|
731 inline bool isMethodFrame() { |
|
732 return footer_.jitCode() == ION_FRAME_DOMMETHOD; |
|
733 } |
|
734 }; |
|
735 |
|
736 struct IonDOMMethodExitFrameLayoutTraits; |
|
737 |
|
738 class IonDOMMethodExitFrameLayout |
|
739 { |
|
740 protected: // only to silence a clang warning about unused private fields |
|
741 IonExitFooterFrame footer_; |
|
742 IonExitFrameLayout exit_; |
|
743 // This must be the last thing pushed, so as to stay common with |
|
744 // IonDOMExitFrameLayout. |
|
745 JSObject *thisObj_; |
|
746 Value *argv_; |
|
747 uintptr_t argc_; |
|
748 |
|
749 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ |
|
750 // compiler may add some padding between the fields. |
|
751 uint32_t loCalleeResult_; |
|
752 uint32_t hiCalleeResult_; |
|
753 |
|
754 friend struct IonDOMMethodExitFrameLayoutTraits; |
|
755 |
|
756 public: |
|
757 static inline size_t Size() { |
|
758 return sizeof(IonDOMMethodExitFrameLayout); |
|
759 } |
|
760 |
|
761 static size_t offsetOfResult() { |
|
762 return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_); |
|
763 } |
|
764 |
|
765 inline Value *vp() { |
|
766 // The code in visitCallDOMNative depends on this static assert holding |
|
767 JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) == |
|
768 (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t))); |
|
769 return reinterpret_cast<Value*>(&loCalleeResult_); |
|
770 } |
|
771 inline JSObject **thisObjAddress() { |
|
772 return &thisObj_; |
|
773 } |
|
774 inline uintptr_t argc() { |
|
775 return argc_; |
|
776 } |
|
777 }; |
|
778 |
|
779 struct IonDOMMethodExitFrameLayoutTraits { |
|
780 static const size_t offsetOfArgcFromArgv = |
|
781 offsetof(IonDOMMethodExitFrameLayout, argc_) - |
|
782 offsetof(IonDOMMethodExitFrameLayout, argv_); |
|
783 }; |
|
784 |
|
785 class ICStub; |
|
786 |
|
787 class IonBaselineStubFrameLayout : public IonCommonFrameLayout |
|
788 { |
|
789 public: |
|
790 static inline size_t Size() { |
|
791 return sizeof(IonBaselineStubFrameLayout); |
|
792 } |
|
793 |
|
794 static inline int reverseOffsetOfStubPtr() { |
|
795 return -int(sizeof(void *)); |
|
796 } |
|
797 static inline int reverseOffsetOfSavedFramePtr() { |
|
798 return -int(2 * sizeof(void *)); |
|
799 } |
|
800 |
|
801 inline ICStub *maybeStubPtr() { |
|
802 uint8_t *fp = reinterpret_cast<uint8_t *>(this); |
|
803 return *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()); |
|
804 } |
|
805 inline void setStubPtr(ICStub *stub) { |
|
806 uint8_t *fp = reinterpret_cast<uint8_t *>(this); |
|
807 *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()) = stub; |
|
808 } |
|
809 }; |
|
810 |
|
811 // An invalidation bailout stack is at the stack pointer for the callee frame. |
|
812 class InvalidationBailoutStack |
|
813 { |
|
814 mozilla::Array<double, FloatRegisters::Total> fpregs_; |
|
815 mozilla::Array<uintptr_t, Registers::Total> regs_; |
|
816 IonScript *ionScript_; |
|
817 uint8_t *osiPointReturnAddress_; |
|
818 |
|
819 public: |
|
820 uint8_t *sp() const { |
|
821 return (uint8_t *) this + sizeof(InvalidationBailoutStack); |
|
822 } |
|
823 IonJSFrameLayout *fp() const; |
|
824 MachineState machine() { |
|
825 return MachineState::FromBailout(regs_, fpregs_); |
|
826 } |
|
827 |
|
828 IonScript *ionScript() const { |
|
829 return ionScript_; |
|
830 } |
|
831 uint8_t *osiPointReturnAddress() const { |
|
832 return osiPointReturnAddress_; |
|
833 } |
|
834 |
|
835 void checkInvariants() const; |
|
836 }; |
|
837 |
|
838 void |
|
839 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes); |
|
840 |
|
841 CalleeToken |
|
842 MarkCalleeToken(JSTracer *trc, CalleeToken token); |
|
843 |
|
844 } /* namespace jit */ |
|
845 } /* namespace js */ |
|
846 |
|
847 #endif // JS_ION |
|
848 |
|
849 #endif /* jit_IonFrames_h */ |