js/src/jit/Bailouts.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

     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/. */
     7 #ifndef jit_Bailouts_h
     8 #define jit_Bailouts_h
    10 #include "jstypes.h"
    12 #include "jit/IonFrames.h"
    13 #include "jit/JitFrameIterator.h"
    14 #include "vm/Stack.h"
    16 namespace js {
    17 namespace jit {
    19 // A "bailout" is a condition in which we need to recover an interpreter frame
    20 // from an IonFrame. Bailouts can happen for the following reasons:
    21 //   (1) A deoptimization guard, for example, an add overflows or a type check
    22 //       fails.
    23 //   (2) A check or assumption held by the JIT is invalidated by the VM, and
    24 //       JIT code must be thrown away. This includes the GC possibly deciding
    25 //       to evict live JIT code, or a Type Inference reflow.
    26 //
    27 // Note that bailouts as described here do not include normal Ion frame
    28 // inspection, for example, if an exception must be built or the GC needs to
    29 // scan an Ion frame for gcthings.
    30 //
    31 // The second type of bailout needs a different name - "deoptimization" or
    32 // "deep bailout". Here we are concerned with eager (or maybe "shallow")
    33 // bailouts, that happen from JIT code. These happen from guards, like:
    34 //
    35 //  cmp [obj + shape], 0x50M37TH1NG
    36 //  jmp _bailout
    37 //
    38 // The bailout target needs to somehow translate the Ion frame (whose state
    39 // will differ at each program point) to an interpreter frame. This state is
    40 // captured into the IonScript's snapshot buffer, and for each bailout we know
    41 // which snapshot corresponds to its state.
    42 //
    43 // Roughly, the following needs to happen at the bailout target.
    44 //   (1) Move snapshot ID into a known stack location (registers cannot be
    45 //       mutated).
    46 //   (2) Spill all registers to the stack.
    47 //   (3) Call a Bailout() routine, whose argument is the stack pointer.
    48 //   (4) Bailout() will find the IonScript on the stack, use the snapshot ID
    49 //       to find the structure of the frame, and then use the stack and spilled
    50 //       registers to perform frame conversion.
    51 //   (5) Bailout() returns, and the JIT must immediately return to the
    52 //       interpreter (all frames are converted at once).
    53 //
    54 // (2) and (3) are implemented by a trampoline held in the compartment.
    55 // Naively, we could implement (1) like:
    56 //
    57 //   _bailout_ID_1:
    58 //     push 1
    59 //     jmp _global_bailout_handler
    60 //   _bailout_ID_2:
    61 //     push 2
    62 //     jmp _global_bailout_handler
    63 //
    64 // This takes about 10 extra bytes per guard. On some platforms, we can reduce
    65 // this overhead to 4 bytes by creating a global jump table, shared again in
    66 // the compartment:
    67 //
    68 //     call _global_bailout_handler
    69 //     call _global_bailout_handler
    70 //     call _global_bailout_handler
    71 //     call _global_bailout_handler
    72 //      ...
    73 //    _global_bailout_handler:
    74 //
    75 // In the bailout handler, we can recompute which entry in the table was
    76 // selected by subtracting the return addressed pushed by the call, from the
    77 // start of the table, and then dividing by the size of a (call X) entry in the
    78 // table. This gives us a number in [0, TableSize), which we call a
    79 // "BailoutId".
    80 //
    81 // Then, we can provide a per-script mapping from BailoutIds to snapshots,
    82 // which takes only four bytes per entry.
    83 //
    84 // This strategy does not work as given, because the bailout handler has no way
    85 // to compute the location of an IonScript. Currently, we do not use frame
    86 // pointers. To account for this we segregate frames into a limited set of
    87 // "frame sizes", and create a table for each frame size. We also have the
    88 // option of not using bailout tables, for platforms or situations where the
    89 // 10 byte cost is more optimal than a bailout table. See IonFrames.h for more
    90 // detail.
    92 static const BailoutId INVALID_BAILOUT_ID = BailoutId(-1);
    94 // Keep this arbitrarily small for now, for testing.
    95 static const uint32_t BAILOUT_TABLE_SIZE = 16;
    97 // Bailout return codes.
    98 // N.B. the relative order of these values is hard-coded into ::GenerateBailoutThunk.
    99 static const uint32_t BAILOUT_RETURN_OK = 0;
   100 static const uint32_t BAILOUT_RETURN_FATAL_ERROR = 1;
   101 static const uint32_t BAILOUT_RETURN_OVERRECURSED = 2;
   103 class JitCompartment;
   105 // BailoutStack is an architecture specific pointer to the stack, given by the
   106 // bailout handler.
   107 class BailoutStack;
   108 class InvalidationBailoutStack;
   110 // Must be implemented by each architecture.
   112 // This iterator is constructed at a time where there is no exit frame at the
   113 // moment. They must be initialized to the first JS frame instead of the exit
   114 // frame as usually done with JitFrameIterator.
   115 class IonBailoutIterator : public JitFrameIterator
   116 {
   117     MachineState machine_;
   118     uint32_t snapshotOffset_;
   119     size_t topFrameSize_;
   120     IonScript *topIonScript_;
   122   public:
   123     IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
   124     IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
   125     IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame);
   127     SnapshotOffset snapshotOffset() const {
   128         JS_ASSERT(topIonScript_);
   129         return snapshotOffset_;
   130     }
   131     const MachineState &machineState() const {
   132         return machine_;
   133     }
   134     size_t topFrameSize() const {
   135         JS_ASSERT(topIonScript_);
   136         return topFrameSize_;
   137     }
   138     IonScript *ionScript() const {
   139         if (topIonScript_)
   140             return topIonScript_;
   141         return JitFrameIterator::ionScript();
   142     }
   144     void dump() const;
   145 };
   147 bool EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp);
   149 struct BaselineBailoutInfo;
   151 // Called from a bailout thunk. Returns a BAILOUT_* error code.
   152 uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
   154 // Called from the invalidation thunk. Returns a BAILOUT_* error code.
   155 uint32_t InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
   156                              BaselineBailoutInfo **info);
   158 class ExceptionBailoutInfo
   159 {
   160     size_t frameNo_;
   161     jsbytecode *resumePC_;
   162     size_t numExprSlots_;
   164   public:
   165     ExceptionBailoutInfo(size_t frameNo, jsbytecode *resumePC, size_t numExprSlots)
   166       : frameNo_(frameNo),
   167         resumePC_(resumePC),
   168         numExprSlots_(numExprSlots)
   169     { }
   171     ExceptionBailoutInfo()
   172       : frameNo_(0),
   173         resumePC_(nullptr),
   174         numExprSlots_(0)
   175     { }
   177     bool catchingException() const {
   178         return !!resumePC_;
   179     }
   180     bool propagatingIonExceptionForDebugMode() const {
   181         return !resumePC_;
   182     }
   184     size_t frameNo() const {
   185         MOZ_ASSERT(catchingException());
   186         return frameNo_;
   187     }
   188     jsbytecode *resumePC() const {
   189         MOZ_ASSERT(catchingException());
   190         return resumePC_;
   191     }
   192     size_t numExprSlots() const {
   193         MOZ_ASSERT(catchingException());
   194         return numExprSlots_;
   195     }
   196 };
   198 // Called from the exception handler to enter a catch or finally block.
   199 // Returns a BAILOUT_* error code.
   200 uint32_t ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
   201                                  ResumeFromException *rfe,
   202                                  const ExceptionBailoutInfo &excInfo,
   203                                  bool *overrecursed);
   205 uint32_t FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo);
   207 bool CheckFrequentBailouts(JSContext *cx, JSScript *script);
   209 } // namespace jit
   210 } // namespace js
   212 #endif /* jit_Bailouts_h */

mercurial