LCOV - code coverage report
Current view: top level - js/src/jit - CacheIRCompiler.h (source / functions) Hit Total Coverage
Test: output.info Lines: 205 254 80.7 %
Date: 2017-07-14 16:53:18 Functions: 80 95 84.2 %
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_CacheIRCompiler_h
       8             : #define jit_CacheIRCompiler_h
       9             : 
      10             : #include "jit/CacheIR.h"
      11             : 
      12             : namespace js {
      13             : namespace jit {
      14             : 
      15             : // The ops below are defined in CacheIRCompiler and codegen is shared between
      16             : // BaselineCacheIRCompiler and IonCacheIRCompiler.
      17             : #define CACHE_IR_SHARED_OPS(_)            \
      18             :     _(GuardIsObject)                      \
      19             :     _(GuardIsObjectOrNull)                \
      20             :     _(GuardIsString)                      \
      21             :     _(GuardIsSymbol)                      \
      22             :     _(GuardIsInt32Index)                  \
      23             :     _(GuardType)                          \
      24             :     _(GuardClass)                         \
      25             :     _(GuardIsNativeFunction)              \
      26             :     _(GuardIsProxy)                       \
      27             :     _(GuardIsCrossCompartmentWrapper)     \
      28             :     _(GuardNotDOMProxy)                   \
      29             :     _(GuardSpecificInt32Immediate)        \
      30             :     _(GuardMagicValue)                    \
      31             :     _(GuardNoUnboxedExpando)              \
      32             :     _(GuardAndLoadUnboxedExpando)         \
      33             :     _(GuardNoDetachedTypedObjects)        \
      34             :     _(GuardNoDenseElements)               \
      35             :     _(GuardAndGetIndexFromString)         \
      36             :     _(LoadProto)                          \
      37             :     _(LoadEnclosingEnvironment)           \
      38             :     _(LoadWrapperTarget)                  \
      39             :     _(LoadDOMExpandoValue)                \
      40             :     _(LoadDOMExpandoValueIgnoreGeneration)\
      41             :     _(LoadUndefinedResult)                \
      42             :     _(LoadBooleanResult)                  \
      43             :     _(LoadInt32ArrayLengthResult)         \
      44             :     _(LoadUnboxedArrayLengthResult)       \
      45             :     _(LoadArgumentsObjectLengthResult)    \
      46             :     _(LoadFunctionLengthResult)           \
      47             :     _(LoadStringLengthResult)             \
      48             :     _(LoadStringCharResult)               \
      49             :     _(LoadArgumentsObjectArgResult)       \
      50             :     _(LoadDenseElementResult)             \
      51             :     _(LoadDenseElementHoleResult)         \
      52             :     _(LoadDenseElementExistsResult)       \
      53             :     _(LoadDenseElementHoleExistsResult)   \
      54             :     _(LoadUnboxedArrayElementResult)      \
      55             :     _(LoadTypedElementResult)             \
      56             :     _(LoadObjectResult)                   \
      57             :     _(LoadTypeOfObjectResult)             \
      58             :     _(CompareStringResult)                \
      59             :     _(CompareObjectResult)                \
      60             :     _(CompareSymbolResult)                \
      61             :     _(CallPrintString)                    \
      62             :     _(Breakpoint)                         \
      63             :     _(MegamorphicLoadSlotByValueResult)   \
      64             :     _(MegamorphicHasOwnResult)            \
      65             :     _(WrapResult)
      66             : 
      67             : // Represents a Value on the Baseline frame's expression stack. Slot 0 is the
      68             : // value on top of the stack (the most recently pushed value), slot 1 is the
      69             : // value pushed before that, etc.
      70             : class BaselineFrameSlot
      71             : {
      72             :     uint32_t slot_;
      73             : 
      74             :   public:
      75          27 :     explicit BaselineFrameSlot(uint32_t slot) : slot_(slot) {}
      76          27 :     uint32_t slot() const { return slot_; }
      77             : 
      78         142 :     bool operator==(const BaselineFrameSlot& other) const { return slot_ == other.slot_; }
      79             :     bool operator!=(const BaselineFrameSlot& other) const { return slot_ != other.slot_; }
      80             : };
      81             : 
      82             : // OperandLocation represents the location of an OperandId. The operand is
      83             : // either in a register or on the stack, and is either boxed or unboxed.
      84             : class OperandLocation
      85             : {
      86             :   public:
      87             :     enum Kind {
      88             :         Uninitialized = 0,
      89             :         PayloadReg,
      90             :         DoubleReg,
      91             :         ValueReg,
      92             :         PayloadStack,
      93             :         ValueStack,
      94             :         BaselineFrame,
      95             :         Constant,
      96             :     };
      97             : 
      98             :   private:
      99             :     Kind kind_;
     100             : 
     101             :     union Data {
     102             :         struct {
     103             :             Register reg;
     104             :             JSValueType type;
     105             :         } payloadReg;
     106             :         FloatRegister doubleReg;
     107             :         ValueOperand valueReg;
     108             :         struct {
     109             :             uint32_t stackPushed;
     110             :             JSValueType type;
     111             :         } payloadStack;
     112             :         uint32_t valueStackPushed;
     113             :         BaselineFrameSlot baselineFrameSlot;
     114             :         Value constant;
     115             : 
     116        1076 :         Data() : valueStackPushed(0) {}
     117             :     };
     118             :     Data data_;
     119             : 
     120             :   public:
     121        1076 :     OperandLocation() : kind_(Uninitialized) {}
     122             : 
     123        5489 :     Kind kind() const { return kind_; }
     124             : 
     125        2565 :     void setUninitialized() {
     126        2565 :         kind_ = Uninitialized;
     127        2565 :     }
     128             : 
     129        3784 :     ValueOperand valueReg() const {
     130        3784 :         MOZ_ASSERT(kind_ == ValueReg);
     131        3784 :         return data_.valueReg;
     132             :     }
     133        3465 :     Register payloadReg() const {
     134        3465 :         MOZ_ASSERT(kind_ == PayloadReg);
     135        3465 :         return data_.payloadReg.reg;
     136             :     }
     137           0 :     FloatRegister doubleReg() const {
     138           0 :         MOZ_ASSERT(kind_ == DoubleReg);
     139           0 :         return data_.doubleReg;
     140             :     }
     141          58 :     uint32_t payloadStack() const {
     142          58 :         MOZ_ASSERT(kind_ == PayloadStack);
     143          58 :         return data_.payloadStack.stackPushed;
     144             :     }
     145           7 :     uint32_t valueStack() const {
     146           7 :         MOZ_ASSERT(kind_ == ValueStack);
     147           7 :         return data_.valueStackPushed;
     148             :     }
     149        1689 :     JSValueType payloadType() const {
     150        1689 :         if (kind_ == PayloadReg)
     151        1642 :             return data_.payloadReg.type;
     152          47 :         MOZ_ASSERT(kind_ == PayloadStack);
     153          47 :         return data_.payloadStack.type;
     154             :     }
     155           0 :     Value constant() const {
     156           0 :         MOZ_ASSERT(kind_ == Constant);
     157           0 :         return data_.constant;
     158             :     }
     159         308 :     BaselineFrameSlot baselineFrameSlot() const {
     160         308 :         MOZ_ASSERT(kind_ == BaselineFrame);
     161         308 :         return data_.baselineFrameSlot;
     162             :     }
     163             : 
     164         746 :     void setPayloadReg(Register reg, JSValueType type) {
     165         746 :         kind_ = PayloadReg;
     166         746 :         data_.payloadReg.reg = reg;
     167         746 :         data_.payloadReg.type = type;
     168         746 :     }
     169           0 :     void setDoubleReg(FloatRegister reg) {
     170           0 :         kind_ = DoubleReg;
     171           0 :         data_.doubleReg = reg;
     172           0 :     }
     173         920 :     void setValueReg(ValueOperand reg) {
     174         920 :         kind_ = ValueReg;
     175         920 :         data_.valueReg = reg;
     176         920 :     }
     177          17 :     void setPayloadStack(uint32_t stackPushed, JSValueType type) {
     178          17 :         kind_ = PayloadStack;
     179          17 :         data_.payloadStack.stackPushed = stackPushed;
     180          17 :         data_.payloadStack.type = type;
     181          17 :     }
     182          18 :     void setValueStack(uint32_t stackPushed) {
     183          18 :         kind_ = ValueStack;
     184          18 :         data_.valueStackPushed = stackPushed;
     185          18 :     }
     186           0 :     void setConstant(const Value& v) {
     187           0 :         kind_ = Constant;
     188           0 :         data_.constant = v;
     189           0 :     }
     190          48 :     void setBaselineFrame(BaselineFrameSlot slot) {
     191          48 :         kind_ = BaselineFrame;
     192          48 :         data_.baselineFrameSlot = slot;
     193          48 :     }
     194             : 
     195          16 :     bool isInRegister() const { return kind_ == PayloadReg || kind_ == ValueReg; }
     196           0 :     bool isOnStack() const { return kind_ == PayloadStack || kind_ == ValueStack; }
     197             : 
     198           0 :     size_t stackPushed() const {
     199           0 :         if (kind_ == PayloadStack)
     200           0 :             return data_.payloadStack.stackPushed;
     201           0 :         MOZ_ASSERT(kind_ == ValueStack);
     202           0 :         return data_.valueStackPushed;
     203             :     }
     204           0 :     size_t stackSizeInBytes() const {
     205           0 :         if (kind_ == PayloadStack)
     206           0 :             return sizeof(uintptr_t);
     207           0 :         MOZ_ASSERT(kind_ == ValueStack);
     208           0 :         return sizeof(js::Value);
     209             :     }
     210           0 :     void adjustStackPushed(int32_t diff) {
     211           0 :         if (kind_ == PayloadStack) {
     212           0 :             data_.payloadStack.stackPushed += diff;
     213           0 :             return;
     214             :         }
     215           0 :         MOZ_ASSERT(kind_ == ValueStack);
     216           0 :         data_.valueStackPushed += diff;
     217             :     }
     218             : 
     219         200 :     bool aliasesReg(Register reg) const {
     220         200 :         if (kind_ == PayloadReg)
     221          18 :             return payloadReg() == reg;
     222         182 :         if (kind_ == ValueReg)
     223         182 :             return valueReg().aliases(reg);
     224           0 :         return false;
     225             :     }
     226         106 :     bool aliasesReg(ValueOperand reg) const {
     227             : #if defined(JS_NUNBOX32)
     228             :         return aliasesReg(reg.typeReg()) || aliasesReg(reg.payloadReg());
     229             : #else
     230         106 :         return aliasesReg(reg.valueReg());
     231             : #endif
     232             :     }
     233             : 
     234             :     bool aliasesReg(const OperandLocation& other) const;
     235             : 
     236             :     bool operator==(const OperandLocation& other) const;
     237        1096 :     bool operator!=(const OperandLocation& other) const { return !operator==(other); }
     238             : };
     239             : 
     240             : struct SpilledRegister
     241             : {
     242             :     Register reg;
     243             :     uint32_t stackPushed;
     244             : 
     245           1 :     SpilledRegister(Register reg, uint32_t stackPushed)
     246           1 :         : reg(reg), stackPushed(stackPushed)
     247           1 :     {}
     248           0 :     bool operator==(const SpilledRegister& other) const {
     249           0 :         return reg == other.reg && stackPushed == other.stackPushed;
     250             :     }
     251           0 :     bool operator!=(const SpilledRegister& other) const { return !(*this == other); }
     252             : };
     253             : 
     254             : using SpilledRegisterVector = Vector<SpilledRegister, 2, SystemAllocPolicy>;
     255             : 
     256             : // Class to track and allocate registers while emitting IC code.
     257         266 : class MOZ_RAII CacheRegisterAllocator
     258             : {
     259             :     // The original location of the inputs to the cache.
     260             :     Vector<OperandLocation, 4, SystemAllocPolicy> origInputLocations_;
     261             : 
     262             :     // The current location of each operand.
     263             :     Vector<OperandLocation, 8, SystemAllocPolicy> operandLocations_;
     264             : 
     265             :     // Free lists for value- and payload-slots on stack
     266             :     Vector<uint32_t, 2, SystemAllocPolicy> freeValueSlots_;
     267             :     Vector<uint32_t, 2, SystemAllocPolicy> freePayloadSlots_;
     268             : 
     269             :     // The registers allocated while emitting the current CacheIR op.
     270             :     // This prevents us from allocating a register and then immediately
     271             :     // clobbering it for something else, while we're still holding on to it.
     272             :     LiveGeneralRegisterSet currentOpRegs_;
     273             : 
     274             :     const AllocatableGeneralRegisterSet allocatableRegs_;
     275             : 
     276             :     // Registers that are currently unused and available.
     277             :     AllocatableGeneralRegisterSet availableRegs_;
     278             : 
     279             :     // Registers that are available, but before use they must be saved and
     280             :     // then restored when returning from the stub.
     281             :     AllocatableGeneralRegisterSet availableRegsAfterSpill_;
     282             : 
     283             :     // Registers we took from availableRegsAfterSpill_ and spilled to the stack.
     284             :     SpilledRegisterVector spilledRegs_;
     285             : 
     286             :     // The number of bytes pushed on the native stack.
     287             :     uint32_t stackPushed_;
     288             : 
     289             :     // The index of the CacheIR instruction we're currently emitting.
     290             :     uint32_t currentInstruction_;
     291             : 
     292             :     const CacheIRWriter& writer_;
     293             : 
     294             :     CacheRegisterAllocator(const CacheRegisterAllocator&) = delete;
     295             :     CacheRegisterAllocator& operator=(const CacheRegisterAllocator&) = delete;
     296             : 
     297             :     void freeDeadOperandLocations(MacroAssembler& masm);
     298             : 
     299             :     void spillOperandToStack(MacroAssembler& masm, OperandLocation* loc);
     300             :     void spillOperandToStackOrRegister(MacroAssembler& masm, OperandLocation* loc);
     301             : 
     302             :     void popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest);
     303             :     void popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest);
     304             : 
     305             :   public:
     306             :     friend class AutoScratchRegister;
     307             :     friend class AutoScratchRegisterExcluding;
     308             : 
     309         266 :     explicit CacheRegisterAllocator(const CacheIRWriter& writer)
     310         798 :       : allocatableRegs_(GeneralRegisterSet::All()),
     311             :         stackPushed_(0),
     312             :         currentInstruction_(0),
     313         798 :         writer_(writer)
     314         266 :     {}
     315             : 
     316             :     MOZ_MUST_USE bool init();
     317             : 
     318         266 :     void initAvailableRegs(const AllocatableGeneralRegisterSet& available) {
     319         266 :         availableRegs_ = available;
     320         266 :     }
     321             :     void initAvailableRegsAfterSpill();
     322             : 
     323             :     void fixupAliasedInputs(MacroAssembler& masm);
     324             : 
     325        1772 :     OperandLocation operandLocation(size_t i) const {
     326        1772 :         return operandLocations_[i];
     327             :     }
     328        1036 :     void setOperandLocation(size_t i, const OperandLocation& loc) {
     329        1036 :         operandLocations_[i] = loc;
     330        1036 :     }
     331             : 
     332             :     OperandLocation origInputLocation(size_t i) const {
     333             :         return origInputLocations_[i];
     334             :     }
     335         374 :     void initInputLocation(size_t i, ValueOperand reg) {
     336         374 :         origInputLocations_[i].setValueReg(reg);
     337         374 :         operandLocations_[i].setValueReg(reg);
     338         374 :     }
     339          47 :     void initInputLocation(size_t i, Register reg, JSValueType type) {
     340          47 :         origInputLocations_[i].setPayloadReg(reg, type);
     341          47 :         operandLocations_[i].setPayloadReg(reg, type);
     342          47 :     }
     343           0 :     void initInputLocation(size_t i, FloatRegister reg) {
     344           0 :         origInputLocations_[i].setDoubleReg(reg);
     345           0 :         operandLocations_[i].setDoubleReg(reg);
     346           0 :     }
     347           0 :     void initInputLocation(size_t i, const Value& v) {
     348           0 :         origInputLocations_[i].setConstant(v);
     349           0 :         operandLocations_[i].setConstant(v);
     350           0 :     }
     351          24 :     void initInputLocation(size_t i, BaselineFrameSlot slot) {
     352          24 :         origInputLocations_[i].setBaselineFrame(slot);
     353          24 :         operandLocations_[i].setBaselineFrame(slot);
     354          24 :     }
     355             : 
     356             :     void initInputLocation(size_t i, const TypedOrValueRegister& reg);
     357             :     void initInputLocation(size_t i, const ConstantOrRegister& value);
     358             : 
     359         967 :     const SpilledRegisterVector& spilledRegs() const { return spilledRegs_; }
     360             : 
     361         579 :     MOZ_MUST_USE bool setSpilledRegs(const SpilledRegisterVector& regs) {
     362         579 :         spilledRegs_.clear();
     363         579 :         return spilledRegs_.appendAll(regs);
     364             :     }
     365             : 
     366        1609 :     void nextOp() {
     367        1609 :         currentOpRegs_.clear();
     368        1609 :         currentInstruction_++;
     369        1609 :     }
     370             : 
     371        1061 :     uint32_t stackPushed() const {
     372        1061 :         return stackPushed_;
     373             :     }
     374         579 :     void setStackPushed(uint32_t pushed) {
     375         579 :         stackPushed_ = pushed;
     376         579 :     }
     377             : 
     378             :     bool isAllocatable(Register reg) const {
     379             :         return allocatableRegs_.has(reg);
     380             :     }
     381             : 
     382             :     // Allocates a new register.
     383             :     Register allocateRegister(MacroAssembler& masm);
     384             :     ValueOperand allocateValueRegister(MacroAssembler& masm);
     385             : 
     386             :     void allocateFixedRegister(MacroAssembler& masm, Register reg);
     387             :     void allocateFixedValueRegister(MacroAssembler& masm, ValueOperand reg);
     388             : 
     389             :     // Releases a register so it can be reused later.
     390         901 :     void releaseRegister(Register reg) {
     391         901 :         MOZ_ASSERT(currentOpRegs_.has(reg));
     392         901 :         availableRegs_.add(reg);
     393         901 :         currentOpRegs_.take(reg);
     394         901 :     }
     395         178 :     void releaseValueRegister(ValueOperand reg) {
     396             : #ifdef JS_NUNBOX32
     397             :         releaseRegister(reg.payloadReg());
     398             :         releaseRegister(reg.typeReg());
     399             : #else
     400         178 :         releaseRegister(reg.valueReg());
     401             : #endif
     402         178 :     }
     403             : 
     404             :     // Removes spilled values from the native stack. This should only be
     405             :     // called after all registers have been allocated.
     406             :     void discardStack(MacroAssembler& masm);
     407             : 
     408             :     Address addressOf(MacroAssembler& masm, BaselineFrameSlot slot) const;
     409             : 
     410             :     // Returns the register for the given operand. If the operand is currently
     411             :     // not in a register, it will load it into one.
     412             :     ValueOperand useValueRegister(MacroAssembler& masm, ValOperandId val);
     413             :     ValueOperand useFixedValueRegister(MacroAssembler& masm, ValOperandId valId, ValueOperand reg);
     414             :     Register useRegister(MacroAssembler& masm, TypedOperandId typedId);
     415             : 
     416             :     ConstantOrRegister useConstantOrRegister(MacroAssembler& masm, ValOperandId val);
     417             : 
     418             :     // Allocates an output register for the given operand.
     419             :     Register defineRegister(MacroAssembler& masm, TypedOperandId typedId);
     420             :     ValueOperand defineValueRegister(MacroAssembler& masm, ValOperandId val);
     421             : 
     422             :     // Returns |val|'s JSValueType or JSVAL_TYPE_UNKNOWN.
     423             :     JSValueType knownType(ValOperandId val) const;
     424             : 
     425             :     // Emits code to restore registers and stack to the state at the start of
     426             :     // the stub.
     427             :     void restoreInputState(MacroAssembler& masm, bool discardStack = true);
     428             : 
     429             :     // Returns the set of registers storing the IC input operands.
     430             :     GeneralRegisterSet inputRegisterSet() const;
     431             : 
     432             :     void saveIonLiveRegisters(MacroAssembler& masm, LiveRegisterSet liveRegs,
     433             :                               Register scratch, IonScript* ionScript);
     434             :     void restoreIonLiveRegisters(MacroAssembler& masm, LiveRegisterSet liveRegs);
     435             : };
     436             : 
     437             : // RAII class to allocate a scratch register and release it when we're done
     438             : // with it.
     439             : class MOZ_RAII AutoScratchRegister
     440             : {
     441             :     CacheRegisterAllocator& alloc_;
     442             :     Register reg_;
     443             : 
     444             :     AutoScratchRegister(const AutoScratchRegister&) = delete;
     445             :     void operator=(const AutoScratchRegister&) = delete;
     446             : 
     447             :   public:
     448         713 :     AutoScratchRegister(CacheRegisterAllocator& alloc, MacroAssembler& masm,
     449             :                         Register reg = InvalidReg)
     450         713 :       : alloc_(alloc)
     451             :     {
     452         713 :         if (reg != InvalidReg) {
     453          58 :             alloc.allocateFixedRegister(masm, reg);
     454          58 :             reg_ = reg;
     455             :         } else {
     456         655 :             reg_ = alloc.allocateRegister(masm);
     457             :         }
     458         713 :         MOZ_ASSERT(alloc_.currentOpRegs_.has(reg_));
     459         713 :     }
     460        1426 :     ~AutoScratchRegister() {
     461         713 :         alloc_.releaseRegister(reg_);
     462         713 :     }
     463             : 
     464           4 :     Register get() const { return reg_; }
     465        2072 :     operator Register() const { return reg_; }
     466             : };
     467             : 
     468             : // Like AutoScratchRegister, but lets the caller specify a register that should
     469             : // not be allocated here.
     470             : class MOZ_RAII AutoScratchRegisterExcluding
     471             : {
     472             :     CacheRegisterAllocator& alloc_;
     473             :     Register reg_;
     474             : 
     475             :   public:
     476           9 :     AutoScratchRegisterExcluding(CacheRegisterAllocator& alloc, MacroAssembler& masm,
     477             :                                  Register excluding)
     478           9 :       : alloc_(alloc)
     479             :     {
     480           9 :         MOZ_ASSERT(excluding != InvalidReg);
     481             : 
     482           9 :         reg_ = alloc.allocateRegister(masm);
     483             : 
     484           9 :         if (reg_ == excluding) {
     485             :             // We need a different register, so try again.
     486           0 :             reg_ = alloc.allocateRegister(masm);
     487           0 :             MOZ_ASSERT(reg_ != excluding);
     488           0 :             alloc_.releaseRegister(excluding);
     489             :         }
     490             : 
     491           9 :         MOZ_ASSERT(alloc_.currentOpRegs_.has(reg_));
     492           9 :     }
     493          18 :     ~AutoScratchRegisterExcluding() {
     494           9 :         alloc_.releaseRegister(reg_);
     495           9 :     }
     496          78 :     operator Register() const { return reg_; }
     497             : };
     498             : 
     499             : // The FailurePath class stores everything we need to generate a failure path
     500             : // at the end of the IC code. The failure path restores the input registers, if
     501             : // needed, and jumps to the next stub.
     502        1546 : class FailurePath
     503             : {
     504             :     Vector<OperandLocation, 4, SystemAllocPolicy> inputs_;
     505             :     SpilledRegisterVector spilledRegs_;
     506             :     NonAssertingLabel label_;
     507             :     uint32_t stackPushed_;
     508             : 
     509             :   public:
     510         967 :     FailurePath() = default;
     511             : 
     512         579 :     FailurePath(FailurePath&& other)
     513         579 :       : inputs_(Move(other.inputs_)),
     514         579 :         spilledRegs_(Move(other.spilledRegs_)),
     515             :         label_(other.label_),
     516        1158 :         stackPushed_(other.stackPushed_)
     517         579 :     {}
     518             : 
     519        1695 :     Label* label() { return &label_; }
     520             : 
     521         967 :     void setStackPushed(uint32_t i) { stackPushed_ = i; }
     522         579 :     uint32_t stackPushed() const { return stackPushed_; }
     523             : 
     524        1772 :     MOZ_MUST_USE bool appendInput(const OperandLocation& loc) {
     525        1772 :         return inputs_.append(loc);
     526             :     }
     527        1036 :     OperandLocation input(size_t i) const {
     528        1036 :         return inputs_[i];
     529             :     }
     530             : 
     531         579 :     const SpilledRegisterVector& spilledRegs() const { return spilledRegs_; }
     532             : 
     533         967 :     MOZ_MUST_USE bool setSpilledRegs(const SpilledRegisterVector& regs) {
     534         967 :         MOZ_ASSERT(spilledRegs_.empty());
     535         967 :         return spilledRegs_.appendAll(regs);
     536             :     }
     537             : 
     538             :     // If canShareFailurePath(other) returns true, the same machine code will
     539             :     // be emitted for two failure paths, so we can share them.
     540             :     bool canShareFailurePath(const FailurePath& other) const;
     541             : };
     542             : 
     543             : class AutoOutputRegister;
     544             : 
     545             : // Base class for BaselineCacheIRCompiler and IonCacheIRCompiler.
     546         266 : class MOZ_RAII CacheIRCompiler
     547             : {
     548             :   protected:
     549             :     friend class AutoOutputRegister;
     550             : 
     551             :     enum class Mode { Baseline, Ion };
     552             : 
     553             :     JSContext* cx_;
     554             :     CacheIRReader reader;
     555             :     const CacheIRWriter& writer_;
     556             :     MacroAssembler masm;
     557             : 
     558             :     CacheRegisterAllocator allocator;
     559             :     Vector<FailurePath, 4, SystemAllocPolicy> failurePaths;
     560             : 
     561             :     // Float registers that are live. Registers not in this set can be
     562             :     // clobbered and don't need to be saved before performing a VM call.
     563             :     // Doing this for non-float registers is a bit more complicated because
     564             :     // the IC register allocator allocates GPRs.
     565             :     LiveFloatRegisterSet liveFloatRegs_;
     566             : 
     567             :     Maybe<TypedOrValueRegister> outputUnchecked_;
     568             :     Mode mode_;
     569             : 
     570             :     // Whether this IC may read double values from uint32 arrays.
     571             :     Maybe<bool> allowDoubleResult_;
     572             : 
     573         266 :     CacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, Mode mode)
     574         266 :       : cx_(cx),
     575             :         reader(writer),
     576             :         writer_(writer),
     577             :         allocator(writer_),
     578         532 :         liveFloatRegs_(FloatRegisterSet::All()),
     579         798 :         mode_(mode)
     580             :     {
     581         266 :         MOZ_ASSERT(!writer.failed());
     582         266 :     }
     583             : 
     584             :     MOZ_MUST_USE bool addFailurePath(FailurePath** failure);
     585             :     MOZ_MUST_USE bool emitFailurePath(size_t i);
     586             : 
     587             :     // Returns the set of volatile float registers that are live. These
     588             :     // registers need to be saved when making non-GC calls with callWithABI.
     589         139 :     FloatRegisterSet liveVolatileFloatRegs() const {
     590         139 :         return FloatRegisterSet::Intersect(liveFloatRegs_.set(), FloatRegisterSet::Volatile());
     591             :     }
     592             : 
     593             :     void emitLoadTypedObjectResultShared(const Address& fieldAddr, Register scratch,
     594             :                                          TypedThingLayout layout, uint32_t typeDescr,
     595             :                                          const AutoOutputRegister& output);
     596             : 
     597             :     void emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type,
     598             :                                            const Address& dest, Register scratch);
     599             : 
     600             :   private:
     601             :     void emitPostBarrierShared(Register obj, const ConstantOrRegister& val, Register scratch,
     602             :                                Register maybeIndex);
     603             : 
     604          52 :     void emitPostBarrierShared(Register obj, ValueOperand val, Register scratch,
     605             :                                Register maybeIndex) {
     606          52 :         emitPostBarrierShared(obj, ConstantOrRegister(val), scratch, maybeIndex);
     607          52 :     }
     608             : 
     609             :   protected:
     610             :     template <typename T>
     611          45 :     void emitPostBarrierSlot(Register obj, const T& val, Register scratch) {
     612          45 :         emitPostBarrierShared(obj, val, scratch, InvalidReg);
     613          45 :     }
     614             : 
     615             :     template <typename T>
     616           7 :     void emitPostBarrierElement(Register obj, const T& val, Register scratch, Register index) {
     617           7 :         MOZ_ASSERT(index != InvalidReg);
     618           7 :         emitPostBarrierShared(obj, val, scratch, index);
     619           7 :     }
     620             : 
     621             :     bool emitComparePointerResultShared(bool symbol);
     622             : 
     623             : #define DEFINE_SHARED_OP(op) MOZ_MUST_USE bool emit##op();
     624             :     CACHE_IR_SHARED_OPS(DEFINE_SHARED_OP)
     625             : #undef DEFINE_SHARED_OP
     626             : };
     627             : 
     628             : // Ensures the IC's output register is available for writing.
     629             : class MOZ_RAII AutoOutputRegister
     630             : {
     631             :     TypedOrValueRegister output_;
     632             :     CacheRegisterAllocator& alloc_;
     633             : 
     634             :     AutoOutputRegister(const AutoOutputRegister&) = delete;
     635             :     void operator=(const AutoOutputRegister&) = delete;
     636             : 
     637             :   public:
     638             :     explicit AutoOutputRegister(CacheIRCompiler& compiler);
     639             :     ~AutoOutputRegister();
     640             : 
     641         138 :     Register maybeReg() const {
     642         138 :         if (output_.hasValue())
     643         137 :             return output_.valueReg().scratchReg();
     644           1 :         if (!output_.typedReg().isFloat())
     645           1 :             return output_.typedReg().gpr();
     646           0 :         return InvalidReg;
     647             :     }
     648             : 
     649          48 :     bool hasValue() const { return output_.hasValue(); }
     650         210 :     ValueOperand valueReg() const { return output_.valueReg(); }
     651           1 :     AnyRegister typedReg() const { return output_.typedReg(); }
     652             : 
     653           1 :     JSValueType type() const {
     654           1 :         MOZ_ASSERT(!hasValue());
     655           1 :         return ValueTypeFromMIRType(output_.type());
     656             :     }
     657             : 
     658          24 :     operator TypedOrValueRegister() const { return output_; }
     659             : };
     660             : 
     661             : // Like AutoScratchRegister, but reuse a register of |output| if possible.
     662         138 : class MOZ_RAII AutoScratchRegisterMaybeOutput
     663             : {
     664             :     mozilla::Maybe<AutoScratchRegister> scratch_;
     665             :     Register scratchReg_;
     666             : 
     667             :     AutoScratchRegisterMaybeOutput(const AutoScratchRegisterMaybeOutput&) = delete;
     668             :     void operator=(const AutoScratchRegisterMaybeOutput&) = delete;
     669             : 
     670             :   public:
     671         138 :     AutoScratchRegisterMaybeOutput(CacheRegisterAllocator& alloc, MacroAssembler& masm,
     672             :                                    const AutoOutputRegister& output)
     673         138 :     {
     674         138 :         scratchReg_ = output.maybeReg();
     675         138 :         if (scratchReg_ == InvalidReg) {
     676           0 :             scratch_.emplace(alloc, masm);
     677           0 :             scratchReg_ = scratch_.ref();
     678             :         }
     679         138 :     }
     680             : 
     681         372 :     operator Register() const { return scratchReg_; }
     682             : };
     683             : 
     684             : // See the 'Sharing Baseline stub code' comment in CacheIR.h for a description
     685             : // of this class.
     686             : class CacheIRStubInfo
     687             : {
     688             :     // These fields don't require 8 bits, but GCC complains if these fields are
     689             :     // smaller than the size of the enums.
     690             :     CacheKind kind_ : 8;
     691             :     ICStubEngine engine_ : 8;
     692             :     bool makesGCCalls_ : 1;
     693             :     uint8_t stubDataOffset_;
     694             : 
     695             :     const uint8_t* code_;
     696             :     uint32_t length_;
     697             :     const uint8_t* fieldTypes_;
     698             : 
     699         251 :     CacheIRStubInfo(CacheKind kind, ICStubEngine engine, bool makesGCCalls,
     700             :                     uint32_t stubDataOffset, const uint8_t* code, uint32_t codeLength,
     701             :                     const uint8_t* fieldTypes)
     702         251 :       : kind_(kind),
     703             :         engine_(engine),
     704             :         makesGCCalls_(makesGCCalls),
     705             :         stubDataOffset_(stubDataOffset),
     706             :         code_(code),
     707             :         length_(codeLength),
     708         251 :         fieldTypes_(fieldTypes)
     709             :     {
     710         251 :         MOZ_ASSERT(kind_ == kind, "Kind must fit in bitfield");
     711         251 :         MOZ_ASSERT(engine_ == engine, "Engine must fit in bitfield");
     712         251 :         MOZ_ASSERT(stubDataOffset_ == stubDataOffset, "stubDataOffset must fit in uint8_t");
     713         251 :     }
     714             : 
     715             :     CacheIRStubInfo(const CacheIRStubInfo&) = delete;
     716             :     CacheIRStubInfo& operator=(const CacheIRStubInfo&) = delete;
     717             : 
     718             :   public:
     719        6131 :     CacheKind kind() const { return kind_; }
     720        6131 :     ICStubEngine engine() const { return engine_; }
     721        7990 :     bool makesGCCalls() const { return makesGCCalls_; }
     722             : 
     723        6419 :     const uint8_t* code() const { return code_; }
     724        6275 :     uint32_t codeLength() const { return length_; }
     725       15372 :     uint32_t stubDataOffset() const { return stubDataOffset_; }
     726             : 
     727             :     size_t stubDataSize() const;
     728             : 
     729       47743 :     StubField::Type fieldType(uint32_t i) const { return (StubField::Type)fieldTypes_[i]; }
     730             : 
     731             :     static CacheIRStubInfo* New(CacheKind kind, ICStubEngine engine, bool canMakeCalls,
     732             :                                 uint32_t stubDataOffset, const CacheIRWriter& writer);
     733             : 
     734             :     template <class Stub, class T>
     735             :     js::GCPtr<T>& getStubField(Stub* stub, uint32_t field) const;
     736             : 
     737             :     template <class T>
     738          59 :     js::GCPtr<T>& getStubField(ICStub* stub, uint32_t field) const {
     739          59 :         return getStubField<ICStub, T>(stub, field);
     740             :     }
     741             : 
     742             :     void copyStubData(ICStub* src, ICStub* dest) const;
     743             : };
     744             : 
     745             : template <typename T>
     746             : void TraceCacheIRStub(JSTracer* trc, T* stub, const CacheIRStubInfo* stubInfo);
     747             : 
     748             : } // namespace jit
     749             : } // namespace js
     750             : 
     751             : #endif /* jit_CacheIRCompiler_h */

Generated by: LCOV version 1.13