1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/IonFrames.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,849 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_IonFrames_h 1.11 +#define jit_IonFrames_h 1.12 + 1.13 +#ifdef JS_ION 1.14 + 1.15 +#include <stdint.h> 1.16 + 1.17 +#include "jscntxt.h" 1.18 +#include "jsfun.h" 1.19 + 1.20 +#include "jit/JitFrameIterator.h" 1.21 + 1.22 +namespace js { 1.23 +namespace jit { 1.24 + 1.25 +typedef void * CalleeToken; 1.26 + 1.27 +enum CalleeTokenTag 1.28 +{ 1.29 + CalleeToken_Function = 0x0, // untagged 1.30 + CalleeToken_Script = 0x1 1.31 +}; 1.32 + 1.33 +static inline CalleeTokenTag 1.34 +GetCalleeTokenTag(CalleeToken token) 1.35 +{ 1.36 + CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3); 1.37 + JS_ASSERT(tag <= CalleeToken_Script); 1.38 + return tag; 1.39 +} 1.40 +static inline CalleeToken 1.41 +CalleeToToken(JSFunction *fun) 1.42 +{ 1.43 + return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function)); 1.44 +} 1.45 +static inline CalleeToken 1.46 +CalleeToToken(JSScript *script) 1.47 +{ 1.48 + return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script)); 1.49 +} 1.50 +static inline bool 1.51 +CalleeTokenIsFunction(CalleeToken token) 1.52 +{ 1.53 + return GetCalleeTokenTag(token) == CalleeToken_Function; 1.54 +} 1.55 +static inline JSFunction * 1.56 +CalleeTokenToFunction(CalleeToken token) 1.57 +{ 1.58 + JS_ASSERT(CalleeTokenIsFunction(token)); 1.59 + return (JSFunction *)token; 1.60 +} 1.61 +static inline JSScript * 1.62 +CalleeTokenToScript(CalleeToken token) 1.63 +{ 1.64 + JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script); 1.65 + return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3)); 1.66 +} 1.67 + 1.68 +static inline JSScript * 1.69 +ScriptFromCalleeToken(CalleeToken token) 1.70 +{ 1.71 + switch (GetCalleeTokenTag(token)) { 1.72 + case CalleeToken_Script: 1.73 + return CalleeTokenToScript(token); 1.74 + case CalleeToken_Function: 1.75 + return CalleeTokenToFunction(token)->nonLazyScript(); 1.76 + } 1.77 + MOZ_ASSUME_UNREACHABLE("invalid callee token tag"); 1.78 +} 1.79 + 1.80 +// In between every two frames lies a small header describing both frames. This 1.81 +// header, minimally, contains a returnAddress word and a descriptor word. The 1.82 +// descriptor describes the size and type of the previous frame, whereas the 1.83 +// returnAddress describes the address the newer frame (the callee) will return 1.84 +// to. The exact mechanism in which frames are laid out is architecture 1.85 +// dependent. 1.86 +// 1.87 +// Two special frame types exist. Entry frames begin an ion activation, and 1.88 +// therefore there is exactly one per activation of jit::Cannon. Exit frames 1.89 +// are necessary to leave JIT code and enter C++, and thus, C++ code will 1.90 +// always begin iterating from the topmost exit frame. 1.91 + 1.92 +class LSafepoint; 1.93 + 1.94 +// Two-tuple that lets you look up the safepoint entry given the 1.95 +// displacement of a call instruction within the JIT code. 1.96 +class SafepointIndex 1.97 +{ 1.98 + // The displacement is the distance from the first byte of the JIT'd code 1.99 + // to the return address (of the call that the safepoint was generated for). 1.100 + uint32_t displacement_; 1.101 + 1.102 + union { 1.103 + LSafepoint *safepoint_; 1.104 + 1.105 + // Offset to the start of the encoded safepoint in the safepoint stream. 1.106 + uint32_t safepointOffset_; 1.107 + }; 1.108 + 1.109 +#ifdef DEBUG 1.110 + bool resolved; 1.111 +#endif 1.112 + 1.113 + public: 1.114 + SafepointIndex(uint32_t displacement, LSafepoint *safepoint) 1.115 + : displacement_(displacement), 1.116 + safepoint_(safepoint) 1.117 +#ifdef DEBUG 1.118 + , resolved(false) 1.119 +#endif 1.120 + { } 1.121 + 1.122 + void resolve(); 1.123 + 1.124 + LSafepoint *safepoint() { 1.125 + JS_ASSERT(!resolved); 1.126 + return safepoint_; 1.127 + } 1.128 + uint32_t displacement() const { 1.129 + return displacement_; 1.130 + } 1.131 + uint32_t safepointOffset() const { 1.132 + return safepointOffset_; 1.133 + } 1.134 + void adjustDisplacement(uint32_t offset) { 1.135 + JS_ASSERT(offset >= displacement_); 1.136 + displacement_ = offset; 1.137 + } 1.138 + inline SnapshotOffset snapshotOffset() const; 1.139 + inline bool hasSnapshotOffset() const; 1.140 +}; 1.141 + 1.142 +class MacroAssembler; 1.143 +// The OSI point is patched to a call instruction. Therefore, the 1.144 +// returnPoint for an OSI call is the address immediately following that 1.145 +// call instruction. The displacement of that point within the assembly 1.146 +// buffer is the |returnPointDisplacement|. 1.147 +class OsiIndex 1.148 +{ 1.149 + uint32_t callPointDisplacement_; 1.150 + uint32_t snapshotOffset_; 1.151 + 1.152 + public: 1.153 + OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset) 1.154 + : callPointDisplacement_(callPointDisplacement), 1.155 + snapshotOffset_(snapshotOffset) 1.156 + { } 1.157 + 1.158 + uint32_t returnPointDisplacement() const; 1.159 + uint32_t callPointDisplacement() const { 1.160 + return callPointDisplacement_; 1.161 + } 1.162 + uint32_t snapshotOffset() const { 1.163 + return snapshotOffset_; 1.164 + } 1.165 + void fixUpOffset(MacroAssembler &masm); 1.166 +}; 1.167 + 1.168 +// The layout of an Ion frame on the C stack is roughly: 1.169 +// argN _ 1.170 +// ... \ - These are jsvals 1.171 +// arg0 / 1.172 +// -3 this _/ 1.173 +// -2 callee 1.174 +// -1 descriptor 1.175 +// 0 returnAddress 1.176 +// .. locals .. 1.177 + 1.178 +// The descriptor is organized into three sections: 1.179 +// [ frame size | constructing bit | frame type ] 1.180 +// < highest - - - - - - - - - - - - - - lowest > 1.181 +static const uintptr_t FRAMESIZE_SHIFT = 4; 1.182 +static const uintptr_t FRAMETYPE_BITS = 4; 1.183 +static const uintptr_t FRAMETYPE_MASK = (1 << FRAMETYPE_BITS) - 1; 1.184 + 1.185 +// Ion frames have a few important numbers associated with them: 1.186 +// Local depth: The number of bytes required to spill local variables. 1.187 +// Argument depth: The number of bytes required to push arguments and make 1.188 +// a function call. 1.189 +// Slack: A frame may temporarily use extra stack to resolve cycles. 1.190 +// 1.191 +// The (local + argument) depth determines the "fixed frame size". The fixed 1.192 +// frame size is the distance between the stack pointer and the frame header. 1.193 +// Thus, fixed >= (local + argument). 1.194 +// 1.195 +// In order to compress guards, we create shared jump tables that recover the 1.196 +// script from the stack and recover a snapshot pointer based on which jump was 1.197 +// taken. Thus, we create a jump table for each fixed frame size. 1.198 +// 1.199 +// Jump tables are big. To control the amount of jump tables we generate, each 1.200 +// platform chooses how to segregate stack size classes based on its 1.201 +// architecture. 1.202 +// 1.203 +// On some architectures, these jump tables are not used at all, or frame 1.204 +// size segregation is not needed. Thus, there is an option for a frame to not 1.205 +// have any frame size class, and to be totally dynamic. 1.206 +static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1); 1.207 + 1.208 +class FrameSizeClass 1.209 +{ 1.210 + uint32_t class_; 1.211 + 1.212 + explicit FrameSizeClass(uint32_t class_) : class_(class_) 1.213 + { } 1.214 + 1.215 + public: 1.216 + FrameSizeClass() 1.217 + { } 1.218 + 1.219 + static FrameSizeClass None() { 1.220 + return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID); 1.221 + } 1.222 + static FrameSizeClass FromClass(uint32_t class_) { 1.223 + return FrameSizeClass(class_); 1.224 + } 1.225 + 1.226 + // These functions are implemented in specific CodeGenerator-* files. 1.227 + static FrameSizeClass FromDepth(uint32_t frameDepth); 1.228 + static FrameSizeClass ClassLimit(); 1.229 + uint32_t frameSize() const; 1.230 + 1.231 + uint32_t classId() const { 1.232 + JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID); 1.233 + return class_; 1.234 + } 1.235 + 1.236 + bool operator ==(const FrameSizeClass &other) const { 1.237 + return class_ == other.class_; 1.238 + } 1.239 + bool operator !=(const FrameSizeClass &other) const { 1.240 + return class_ != other.class_; 1.241 + } 1.242 +}; 1.243 + 1.244 +struct BaselineBailoutInfo; 1.245 + 1.246 +// Data needed to recover from an exception. 1.247 +struct ResumeFromException 1.248 +{ 1.249 + static const uint32_t RESUME_ENTRY_FRAME = 0; 1.250 + static const uint32_t RESUME_CATCH = 1; 1.251 + static const uint32_t RESUME_FINALLY = 2; 1.252 + static const uint32_t RESUME_FORCED_RETURN = 3; 1.253 + static const uint32_t RESUME_BAILOUT = 4; 1.254 + 1.255 + uint8_t *framePointer; 1.256 + uint8_t *stackPointer; 1.257 + uint8_t *target; 1.258 + uint32_t kind; 1.259 + 1.260 + // Value to push when resuming into a |finally| block. 1.261 + Value exception; 1.262 + 1.263 + BaselineBailoutInfo *bailoutInfo; 1.264 +}; 1.265 + 1.266 +void HandleException(ResumeFromException *rfe); 1.267 +void HandleParallelFailure(ResumeFromException *rfe); 1.268 + 1.269 +void EnsureExitFrame(IonCommonFrameLayout *frame); 1.270 + 1.271 +void MarkJitActivations(JSRuntime *rt, JSTracer *trc); 1.272 +void MarkIonCompilerRoots(JSTracer *trc); 1.273 + 1.274 +#ifdef JSGC_GENERATIONAL 1.275 +void UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc); 1.276 +#endif 1.277 + 1.278 +static inline uint32_t 1.279 +MakeFrameDescriptor(uint32_t frameSize, FrameType type) 1.280 +{ 1.281 + return (frameSize << FRAMESIZE_SHIFT) | type; 1.282 +} 1.283 + 1.284 +// Returns the JSScript associated with the topmost Ion frame. 1.285 +inline JSScript * 1.286 +GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode) 1.287 +{ 1.288 + JitFrameIterator iter(ionTop, mode); 1.289 + JS_ASSERT(iter.type() == JitFrame_Exit); 1.290 + ++iter; 1.291 + 1.292 + JS_ASSERT(iter.returnAddressToFp() != nullptr); 1.293 + if (returnAddrOut) 1.294 + *returnAddrOut = (void *) iter.returnAddressToFp(); 1.295 + 1.296 + if (iter.isBaselineStub()) { 1.297 + ++iter; 1.298 + JS_ASSERT(iter.isBaselineJS()); 1.299 + } 1.300 + 1.301 + JS_ASSERT(iter.isScripted()); 1.302 + return iter.script(); 1.303 +} 1.304 + 1.305 +static JitCode *const ION_FRAME_DOMGETTER = (JitCode *)0x1; 1.306 +static JitCode *const ION_FRAME_DOMSETTER = (JitCode *)0x2; 1.307 +static JitCode *const ION_FRAME_DOMMETHOD = (JitCode *)0x3; 1.308 +static JitCode *const ION_FRAME_OOL_NATIVE = (JitCode *)0x4; 1.309 +static JitCode *const ION_FRAME_OOL_PROPERTY_OP = (JitCode *)0x5; 1.310 +static JitCode *const ION_FRAME_OOL_PROXY = (JitCode *)0x6; 1.311 + 1.312 +// Layout of the frame prefix. This assumes the stack architecture grows down. 1.313 +// If this is ever not the case, we'll have to refactor. 1.314 +class IonCommonFrameLayout 1.315 +{ 1.316 + uint8_t *returnAddress_; 1.317 + uintptr_t descriptor_; 1.318 + 1.319 + static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1; 1.320 + 1.321 + public: 1.322 + static size_t offsetOfDescriptor() { 1.323 + return offsetof(IonCommonFrameLayout, descriptor_); 1.324 + } 1.325 + static size_t offsetOfReturnAddress() { 1.326 + return offsetof(IonCommonFrameLayout, returnAddress_); 1.327 + } 1.328 + FrameType prevType() const { 1.329 + return FrameType(descriptor_ & FrameTypeMask); 1.330 + } 1.331 + void changePrevType(FrameType type) { 1.332 + descriptor_ &= ~FrameTypeMask; 1.333 + descriptor_ |= type; 1.334 + } 1.335 + size_t prevFrameLocalSize() const { 1.336 + return descriptor_ >> FRAMESIZE_SHIFT; 1.337 + } 1.338 + void setFrameDescriptor(size_t size, FrameType type) { 1.339 + descriptor_ = (size << FRAMESIZE_SHIFT) | type; 1.340 + } 1.341 + uint8_t *returnAddress() const { 1.342 + return returnAddress_; 1.343 + } 1.344 + void setReturnAddress(uint8_t *addr) { 1.345 + returnAddress_ = addr; 1.346 + } 1.347 +}; 1.348 + 1.349 +class IonJSFrameLayout : public IonCommonFrameLayout 1.350 +{ 1.351 + CalleeToken calleeToken_; 1.352 + uintptr_t numActualArgs_; 1.353 + 1.354 + public: 1.355 + CalleeToken calleeToken() const { 1.356 + return calleeToken_; 1.357 + } 1.358 + void replaceCalleeToken(CalleeToken calleeToken) { 1.359 + calleeToken_ = calleeToken; 1.360 + } 1.361 + 1.362 + static size_t offsetOfCalleeToken() { 1.363 + return offsetof(IonJSFrameLayout, calleeToken_); 1.364 + } 1.365 + static size_t offsetOfNumActualArgs() { 1.366 + return offsetof(IonJSFrameLayout, numActualArgs_); 1.367 + } 1.368 + static size_t offsetOfThis() { 1.369 + IonJSFrameLayout *base = nullptr; 1.370 + return reinterpret_cast<size_t>(&base->argv()[0]); 1.371 + } 1.372 + static size_t offsetOfActualArgs() { 1.373 + IonJSFrameLayout *base = nullptr; 1.374 + // +1 to skip |this|. 1.375 + return reinterpret_cast<size_t>(&base->argv()[1]); 1.376 + } 1.377 + static size_t offsetOfActualArg(size_t arg) { 1.378 + return offsetOfActualArgs() + arg * sizeof(Value); 1.379 + } 1.380 + 1.381 + Value thisv() { 1.382 + return argv()[0]; 1.383 + } 1.384 + Value *argv() { 1.385 + return (Value *)(this + 1); 1.386 + } 1.387 + uintptr_t numActualArgs() const { 1.388 + return numActualArgs_; 1.389 + } 1.390 + 1.391 + // Computes a reference to a slot, where a slot is a distance from the base 1.392 + // frame pointer (as would be used for LStackSlot). 1.393 + uintptr_t *slotRef(uint32_t slot) { 1.394 + return (uintptr_t *)((uint8_t *)this - slot); 1.395 + } 1.396 + 1.397 + static inline size_t Size() { 1.398 + return sizeof(IonJSFrameLayout); 1.399 + } 1.400 +}; 1.401 + 1.402 +// this is the layout of the frame that is used when we enter Ion code from platform ABI code 1.403 +class IonEntryFrameLayout : public IonJSFrameLayout 1.404 +{ 1.405 + public: 1.406 + static inline size_t Size() { 1.407 + return sizeof(IonEntryFrameLayout); 1.408 + } 1.409 +}; 1.410 + 1.411 +class IonRectifierFrameLayout : public IonJSFrameLayout 1.412 +{ 1.413 + public: 1.414 + static inline size_t Size() { 1.415 + return sizeof(IonRectifierFrameLayout); 1.416 + } 1.417 +}; 1.418 + 1.419 +// The callee token is now dead. 1.420 +class IonUnwoundRectifierFrameLayout : public IonRectifierFrameLayout 1.421 +{ 1.422 + public: 1.423 + static inline size_t Size() { 1.424 + // It is not necessary to accout for an extra callee token here because 1.425 + // sizeof(IonExitFrameLayout) == sizeof(IonRectifierFrameLayout) due to 1.426 + // extra padding. 1.427 + return sizeof(IonUnwoundRectifierFrameLayout); 1.428 + } 1.429 +}; 1.430 + 1.431 +// GC related data used to keep alive data surrounding the Exit frame. 1.432 +class IonExitFooterFrame 1.433 +{ 1.434 + const VMFunction *function_; 1.435 + JitCode *jitCode_; 1.436 + 1.437 + public: 1.438 + static inline size_t Size() { 1.439 + return sizeof(IonExitFooterFrame); 1.440 + } 1.441 + inline JitCode *jitCode() const { 1.442 + return jitCode_; 1.443 + } 1.444 + inline JitCode **addressOfJitCode() { 1.445 + return &jitCode_; 1.446 + } 1.447 + inline const VMFunction *function() const { 1.448 + return function_; 1.449 + } 1.450 + 1.451 + // This should only be called for function()->outParam == Type_Handle 1.452 + template <typename T> 1.453 + T *outParam() { 1.454 + return reinterpret_cast<T *>(reinterpret_cast<char *>(this) - sizeof(T)); 1.455 + } 1.456 +}; 1.457 + 1.458 +class IonNativeExitFrameLayout; 1.459 +class IonOOLNativeExitFrameLayout; 1.460 +class IonOOLPropertyOpExitFrameLayout; 1.461 +class IonOOLProxyExitFrameLayout; 1.462 +class IonDOMExitFrameLayout; 1.463 + 1.464 +// this is the frame layout when we are exiting ion code, and about to enter platform ABI code 1.465 +class IonExitFrameLayout : public IonCommonFrameLayout 1.466 +{ 1.467 + inline uint8_t *top() { 1.468 + return reinterpret_cast<uint8_t *>(this + 1); 1.469 + } 1.470 + 1.471 + public: 1.472 + static inline size_t Size() { 1.473 + return sizeof(IonExitFrameLayout); 1.474 + } 1.475 + static inline size_t SizeWithFooter() { 1.476 + return Size() + IonExitFooterFrame::Size(); 1.477 + } 1.478 + 1.479 + inline IonExitFooterFrame *footer() { 1.480 + uint8_t *sp = reinterpret_cast<uint8_t *>(this); 1.481 + return reinterpret_cast<IonExitFooterFrame *>(sp - IonExitFooterFrame::Size()); 1.482 + } 1.483 + 1.484 + // argBase targets the point which precedes the exit frame. Arguments of VM 1.485 + // each wrapper are pushed before the exit frame. This correspond exactly 1.486 + // to the value of the argBase register of the generateVMWrapper function. 1.487 + inline uint8_t *argBase() { 1.488 + JS_ASSERT(footer()->jitCode() != nullptr); 1.489 + return top(); 1.490 + } 1.491 + 1.492 + inline bool isWrapperExit() { 1.493 + return footer()->function() != nullptr; 1.494 + } 1.495 + inline bool isNativeExit() { 1.496 + return footer()->jitCode() == nullptr; 1.497 + } 1.498 + inline bool isOOLNativeExit() { 1.499 + return footer()->jitCode() == ION_FRAME_OOL_NATIVE; 1.500 + } 1.501 + inline bool isOOLPropertyOpExit() { 1.502 + return footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP; 1.503 + } 1.504 + inline bool isOOLProxyExit() { 1.505 + return footer()->jitCode() == ION_FRAME_OOL_PROXY; 1.506 + } 1.507 + inline bool isDomExit() { 1.508 + JitCode *code = footer()->jitCode(); 1.509 + return 1.510 + code == ION_FRAME_DOMGETTER || 1.511 + code == ION_FRAME_DOMSETTER || 1.512 + code == ION_FRAME_DOMMETHOD; 1.513 + } 1.514 + 1.515 + inline IonNativeExitFrameLayout *nativeExit() { 1.516 + // see CodeGenerator::visitCallNative 1.517 + JS_ASSERT(isNativeExit()); 1.518 + return reinterpret_cast<IonNativeExitFrameLayout *>(footer()); 1.519 + } 1.520 + inline IonOOLNativeExitFrameLayout *oolNativeExit() { 1.521 + JS_ASSERT(isOOLNativeExit()); 1.522 + return reinterpret_cast<IonOOLNativeExitFrameLayout *>(footer()); 1.523 + } 1.524 + inline IonOOLPropertyOpExitFrameLayout *oolPropertyOpExit() { 1.525 + JS_ASSERT(isOOLPropertyOpExit()); 1.526 + return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer()); 1.527 + } 1.528 + inline IonOOLProxyExitFrameLayout *oolProxyExit() { 1.529 + JS_ASSERT(isOOLProxyExit()); 1.530 + return reinterpret_cast<IonOOLProxyExitFrameLayout *>(footer()); 1.531 + } 1.532 + inline IonDOMExitFrameLayout *DOMExit() { 1.533 + JS_ASSERT(isDomExit()); 1.534 + return reinterpret_cast<IonDOMExitFrameLayout *>(footer()); 1.535 + } 1.536 +}; 1.537 + 1.538 +// Cannot inherit implementa<tion since we need to extend the top of 1.539 +// IonExitFrameLayout. 1.540 +class IonNativeExitFrameLayout 1.541 +{ 1.542 + protected: // only to silence a clang warning about unused private fields 1.543 + IonExitFooterFrame footer_; 1.544 + IonExitFrameLayout exit_; 1.545 + uintptr_t argc_; 1.546 + 1.547 + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 1.548 + // compiler may add some padding between the fields. 1.549 + uint32_t loCalleeResult_; 1.550 + uint32_t hiCalleeResult_; 1.551 + 1.552 + public: 1.553 + static inline size_t Size() { 1.554 + return sizeof(IonNativeExitFrameLayout); 1.555 + } 1.556 + 1.557 + static size_t offsetOfResult() { 1.558 + return offsetof(IonNativeExitFrameLayout, loCalleeResult_); 1.559 + } 1.560 + inline Value *vp() { 1.561 + return reinterpret_cast<Value*>(&loCalleeResult_); 1.562 + } 1.563 + inline uintptr_t argc() const { 1.564 + return argc_; 1.565 + } 1.566 +}; 1.567 + 1.568 +class IonOOLNativeExitFrameLayout 1.569 +{ 1.570 + protected: // only to silence a clang warning about unused private fields 1.571 + IonExitFooterFrame footer_; 1.572 + IonExitFrameLayout exit_; 1.573 + 1.574 + // pointer to root the stub's JitCode 1.575 + JitCode *stubCode_; 1.576 + 1.577 + uintptr_t argc_; 1.578 + 1.579 + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 1.580 + // compiler may add some padding between the fields. 1.581 + uint32_t loCalleeResult_; 1.582 + uint32_t hiCalleeResult_; 1.583 + 1.584 + // Split Value for |this| and args above. 1.585 + uint32_t loThis_; 1.586 + uint32_t hiThis_; 1.587 + 1.588 + public: 1.589 + static inline size_t Size(size_t argc) { 1.590 + // The frame accounts for the callee/result and |this|, so we only need args. 1.591 + return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value)); 1.592 + } 1.593 + 1.594 + static size_t offsetOfResult() { 1.595 + return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_); 1.596 + } 1.597 + 1.598 + inline JitCode **stubCode() { 1.599 + return &stubCode_; 1.600 + } 1.601 + inline Value *vp() { 1.602 + return reinterpret_cast<Value*>(&loCalleeResult_); 1.603 + } 1.604 + inline Value *thisp() { 1.605 + return reinterpret_cast<Value*>(&loThis_); 1.606 + } 1.607 + inline uintptr_t argc() const { 1.608 + return argc_; 1.609 + } 1.610 +}; 1.611 + 1.612 +class IonOOLPropertyOpExitFrameLayout 1.613 +{ 1.614 + protected: // only to silence a clang warning about unused private fields 1.615 + IonExitFooterFrame footer_; 1.616 + IonExitFrameLayout exit_; 1.617 + 1.618 + // Object for HandleObject 1.619 + JSObject *obj_; 1.620 + 1.621 + // id for HandleId 1.622 + jsid id_; 1.623 + 1.624 + // space for MutableHandleValue result 1.625 + // use two uint32_t so compiler doesn't align. 1.626 + uint32_t vp0_; 1.627 + uint32_t vp1_; 1.628 + 1.629 + // pointer to root the stub's JitCode 1.630 + JitCode *stubCode_; 1.631 + 1.632 + public: 1.633 + static inline size_t Size() { 1.634 + return sizeof(IonOOLPropertyOpExitFrameLayout); 1.635 + } 1.636 + 1.637 + static size_t offsetOfResult() { 1.638 + return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_); 1.639 + } 1.640 + 1.641 + inline JitCode **stubCode() { 1.642 + return &stubCode_; 1.643 + } 1.644 + inline Value *vp() { 1.645 + return reinterpret_cast<Value*>(&vp0_); 1.646 + } 1.647 + inline jsid *id() { 1.648 + return &id_; 1.649 + } 1.650 + inline JSObject **obj() { 1.651 + return &obj_; 1.652 + } 1.653 +}; 1.654 + 1.655 +// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, 1.656 +// MutableHandleValue vp) 1.657 +// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, 1.658 +// bool strict, MutableHandleValue vp) 1.659 +class IonOOLProxyExitFrameLayout 1.660 +{ 1.661 + protected: // only to silence a clang warning about unused private fields 1.662 + IonExitFooterFrame footer_; 1.663 + IonExitFrameLayout exit_; 1.664 + 1.665 + // The proxy object. 1.666 + JSObject *proxy_; 1.667 + 1.668 + // Object for HandleObject 1.669 + JSObject *receiver_; 1.670 + 1.671 + // id for HandleId 1.672 + jsid id_; 1.673 + 1.674 + // space for MutableHandleValue result 1.675 + // use two uint32_t so compiler doesn't align. 1.676 + uint32_t vp0_; 1.677 + uint32_t vp1_; 1.678 + 1.679 + // pointer to root the stub's JitCode 1.680 + JitCode *stubCode_; 1.681 + 1.682 + public: 1.683 + static inline size_t Size() { 1.684 + return sizeof(IonOOLProxyExitFrameLayout); 1.685 + } 1.686 + 1.687 + static size_t offsetOfResult() { 1.688 + return offsetof(IonOOLProxyExitFrameLayout, vp0_); 1.689 + } 1.690 + 1.691 + inline JitCode **stubCode() { 1.692 + return &stubCode_; 1.693 + } 1.694 + inline Value *vp() { 1.695 + return reinterpret_cast<Value*>(&vp0_); 1.696 + } 1.697 + inline jsid *id() { 1.698 + return &id_; 1.699 + } 1.700 + inline JSObject **receiver() { 1.701 + return &receiver_; 1.702 + } 1.703 + inline JSObject **proxy() { 1.704 + return &proxy_; 1.705 + } 1.706 +}; 1.707 + 1.708 +class IonDOMExitFrameLayout 1.709 +{ 1.710 + protected: // only to silence a clang warning about unused private fields 1.711 + IonExitFooterFrame footer_; 1.712 + IonExitFrameLayout exit_; 1.713 + JSObject *thisObj; 1.714 + 1.715 + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 1.716 + // compiler may add some padding between the fields. 1.717 + uint32_t loCalleeResult_; 1.718 + uint32_t hiCalleeResult_; 1.719 + 1.720 + public: 1.721 + static inline size_t Size() { 1.722 + return sizeof(IonDOMExitFrameLayout); 1.723 + } 1.724 + 1.725 + static size_t offsetOfResult() { 1.726 + return offsetof(IonDOMExitFrameLayout, loCalleeResult_); 1.727 + } 1.728 + inline Value *vp() { 1.729 + return reinterpret_cast<Value*>(&loCalleeResult_); 1.730 + } 1.731 + inline JSObject **thisObjAddress() { 1.732 + return &thisObj; 1.733 + } 1.734 + inline bool isMethodFrame() { 1.735 + return footer_.jitCode() == ION_FRAME_DOMMETHOD; 1.736 + } 1.737 +}; 1.738 + 1.739 +struct IonDOMMethodExitFrameLayoutTraits; 1.740 + 1.741 +class IonDOMMethodExitFrameLayout 1.742 +{ 1.743 + protected: // only to silence a clang warning about unused private fields 1.744 + IonExitFooterFrame footer_; 1.745 + IonExitFrameLayout exit_; 1.746 + // This must be the last thing pushed, so as to stay common with 1.747 + // IonDOMExitFrameLayout. 1.748 + JSObject *thisObj_; 1.749 + Value *argv_; 1.750 + uintptr_t argc_; 1.751 + 1.752 + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 1.753 + // compiler may add some padding between the fields. 1.754 + uint32_t loCalleeResult_; 1.755 + uint32_t hiCalleeResult_; 1.756 + 1.757 + friend struct IonDOMMethodExitFrameLayoutTraits; 1.758 + 1.759 + public: 1.760 + static inline size_t Size() { 1.761 + return sizeof(IonDOMMethodExitFrameLayout); 1.762 + } 1.763 + 1.764 + static size_t offsetOfResult() { 1.765 + return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_); 1.766 + } 1.767 + 1.768 + inline Value *vp() { 1.769 + // The code in visitCallDOMNative depends on this static assert holding 1.770 + JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) == 1.771 + (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t))); 1.772 + return reinterpret_cast<Value*>(&loCalleeResult_); 1.773 + } 1.774 + inline JSObject **thisObjAddress() { 1.775 + return &thisObj_; 1.776 + } 1.777 + inline uintptr_t argc() { 1.778 + return argc_; 1.779 + } 1.780 +}; 1.781 + 1.782 +struct IonDOMMethodExitFrameLayoutTraits { 1.783 + static const size_t offsetOfArgcFromArgv = 1.784 + offsetof(IonDOMMethodExitFrameLayout, argc_) - 1.785 + offsetof(IonDOMMethodExitFrameLayout, argv_); 1.786 +}; 1.787 + 1.788 +class ICStub; 1.789 + 1.790 +class IonBaselineStubFrameLayout : public IonCommonFrameLayout 1.791 +{ 1.792 + public: 1.793 + static inline size_t Size() { 1.794 + return sizeof(IonBaselineStubFrameLayout); 1.795 + } 1.796 + 1.797 + static inline int reverseOffsetOfStubPtr() { 1.798 + return -int(sizeof(void *)); 1.799 + } 1.800 + static inline int reverseOffsetOfSavedFramePtr() { 1.801 + return -int(2 * sizeof(void *)); 1.802 + } 1.803 + 1.804 + inline ICStub *maybeStubPtr() { 1.805 + uint8_t *fp = reinterpret_cast<uint8_t *>(this); 1.806 + return *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()); 1.807 + } 1.808 + inline void setStubPtr(ICStub *stub) { 1.809 + uint8_t *fp = reinterpret_cast<uint8_t *>(this); 1.810 + *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()) = stub; 1.811 + } 1.812 +}; 1.813 + 1.814 +// An invalidation bailout stack is at the stack pointer for the callee frame. 1.815 +class InvalidationBailoutStack 1.816 +{ 1.817 + mozilla::Array<double, FloatRegisters::Total> fpregs_; 1.818 + mozilla::Array<uintptr_t, Registers::Total> regs_; 1.819 + IonScript *ionScript_; 1.820 + uint8_t *osiPointReturnAddress_; 1.821 + 1.822 + public: 1.823 + uint8_t *sp() const { 1.824 + return (uint8_t *) this + sizeof(InvalidationBailoutStack); 1.825 + } 1.826 + IonJSFrameLayout *fp() const; 1.827 + MachineState machine() { 1.828 + return MachineState::FromBailout(regs_, fpregs_); 1.829 + } 1.830 + 1.831 + IonScript *ionScript() const { 1.832 + return ionScript_; 1.833 + } 1.834 + uint8_t *osiPointReturnAddress() const { 1.835 + return osiPointReturnAddress_; 1.836 + } 1.837 + 1.838 + void checkInvariants() const; 1.839 +}; 1.840 + 1.841 +void 1.842 +GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes); 1.843 + 1.844 +CalleeToken 1.845 +MarkCalleeToken(JSTracer *trc, CalleeToken token); 1.846 + 1.847 +} /* namespace jit */ 1.848 +} /* namespace js */ 1.849 + 1.850 +#endif // JS_ION 1.851 + 1.852 +#endif /* jit_IonFrames_h */