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