LCOV - code coverage report
Current view: top level - js/src/jit - Bailouts.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 33 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_Bailouts_h
       8             : #define jit_Bailouts_h
       9             : 
      10             : #include "jstypes.h"
      11             : 
      12             : #include "jit/JitFrameIterator.h"
      13             : #include "jit/JitFrames.h"
      14             : #include "vm/Stack.h"
      15             : 
      16             : namespace js {
      17             : namespace jit {
      18             : 
      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 JitFrames.h for more
      90             : // detail.
      91             : 
      92             : static const BailoutId INVALID_BAILOUT_ID = BailoutId(-1);
      93             : 
      94             : // Keep this arbitrarily small for now, for testing.
      95             : static const uint32_t BAILOUT_TABLE_SIZE = 16;
      96             : 
      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;
     102             : 
     103             : // This address is a magic number made to cause crashes while indicating that we
     104             : // are making an attempt to mark the stack during a bailout.
     105             : static uint8_t* const FAKE_EXITFP_FOR_BAILOUT = reinterpret_cast<uint8_t*>(0xba1);
     106             : 
     107             : // BailoutStack is an architecture specific pointer to the stack, given by the
     108             : // bailout handler.
     109             : class BailoutStack;
     110             : class InvalidationBailoutStack;
     111             : 
     112             : // Must be implemented by each architecture.
     113             : 
     114             : // This structure is constructed before recovering the baseline frames for a
     115             : // bailout. It records all information extracted from the stack, and which are
     116             : // needed for the JitFrameIterator.
     117             : class BailoutFrameInfo
     118             : {
     119             :     MachineState machine_;
     120             :     uint8_t* framePointer_;
     121             :     size_t topFrameSize_;
     122             :     IonScript* topIonScript_;
     123             :     uint32_t snapshotOffset_;
     124             :     JitActivation* activation_;
     125             : 
     126             :     void attachOnJitActivation(const JitActivationIterator& activations);
     127             : 
     128             :   public:
     129             :     BailoutFrameInfo(const JitActivationIterator& activations, BailoutStack* sp);
     130             :     BailoutFrameInfo(const JitActivationIterator& activations, InvalidationBailoutStack* sp);
     131             :     BailoutFrameInfo(const JitActivationIterator& activations, const JitFrameIterator& frame);
     132             :     ~BailoutFrameInfo();
     133             : 
     134           0 :     uint8_t* fp() const {
     135           0 :         return framePointer_;
     136             :     }
     137           0 :     SnapshotOffset snapshotOffset() const {
     138           0 :         return snapshotOffset_;
     139             :     }
     140           0 :     const MachineState* machineState() const {
     141           0 :         return &machine_;
     142             :     }
     143           0 :     size_t topFrameSize() const {
     144           0 :         return topFrameSize_;
     145             :     }
     146           0 :     IonScript* ionScript() const {
     147           0 :         return topIonScript_;
     148             :     }
     149           0 :     JitActivation* activation() const {
     150           0 :         return activation_;
     151             :     }
     152             : };
     153             : 
     154             : MOZ_MUST_USE bool EnsureHasEnvironmentObjects(JSContext* cx, AbstractFramePtr fp);
     155             : 
     156             : struct BaselineBailoutInfo;
     157             : 
     158             : // Called from a bailout thunk. Returns a BAILOUT_* error code.
     159             : uint32_t Bailout(BailoutStack* sp, BaselineBailoutInfo** info);
     160             : 
     161             : // Called from the invalidation thunk. Returns a BAILOUT_* error code.
     162             : uint32_t InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
     163             :                              BaselineBailoutInfo** info);
     164             : 
     165             : class ExceptionBailoutInfo
     166             : {
     167             :     size_t frameNo_;
     168             :     jsbytecode* resumePC_;
     169             :     size_t numExprSlots_;
     170             : 
     171             :   public:
     172           0 :     ExceptionBailoutInfo(size_t frameNo, jsbytecode* resumePC, size_t numExprSlots)
     173           0 :       : frameNo_(frameNo),
     174             :         resumePC_(resumePC),
     175           0 :         numExprSlots_(numExprSlots)
     176           0 :     { }
     177             : 
     178           0 :     ExceptionBailoutInfo()
     179           0 :       : frameNo_(0),
     180             :         resumePC_(nullptr),
     181           0 :         numExprSlots_(0)
     182           0 :     { }
     183             : 
     184           0 :     bool catchingException() const {
     185           0 :         return !!resumePC_;
     186             :     }
     187           0 :     bool propagatingIonExceptionForDebugMode() const {
     188           0 :         return !resumePC_;
     189             :     }
     190             : 
     191           0 :     size_t frameNo() const {
     192           0 :         MOZ_ASSERT(catchingException());
     193           0 :         return frameNo_;
     194             :     }
     195           0 :     jsbytecode* resumePC() const {
     196           0 :         MOZ_ASSERT(catchingException());
     197           0 :         return resumePC_;
     198             :     }
     199           0 :     size_t numExprSlots() const {
     200           0 :         MOZ_ASSERT(catchingException());
     201           0 :         return numExprSlots_;
     202             :     }
     203             : };
     204             : 
     205             : // Called from the exception handler to enter a catch or finally block.
     206             : // Returns a BAILOUT_* error code.
     207             : uint32_t ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
     208             :                                  ResumeFromException* rfe,
     209             :                                  const ExceptionBailoutInfo& excInfo,
     210             :                                  bool* overrecursed);
     211             : 
     212             : uint32_t FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo);
     213             : 
     214             : void CheckFrequentBailouts(JSContext* cx, JSScript* script, BailoutKind bailoutKind);
     215             : 
     216             : } // namespace jit
     217             : } // namespace js
     218             : 
     219             : #endif /* jit_Bailouts_h */

Generated by: LCOV version 1.13