Home | History | Annotate | Download | only in dfg
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef DFGJITCodeGenerator_h
     27 #define DFGJITCodeGenerator_h
     28 
     29 #if ENABLE(DFG_JIT)
     30 
     31 #include "CodeBlock.h"
     32 #include <dfg/DFGGenerationInfo.h>
     33 #include <dfg/DFGGraph.h>
     34 #include <dfg/DFGJITCompiler.h>
     35 #include <dfg/DFGOperations.h>
     36 #include <dfg/DFGRegisterBank.h>
     37 
     38 namespace JSC { namespace DFG {
     39 
     40 class SpeculateIntegerOperand;
     41 class SpeculateStrictInt32Operand;
     42 class SpeculateCellOperand;
     43 
     44 
     45 // === JITCodeGenerator ===
     46 //
     47 // This class provides common infrastructure used by the speculative &
     48 // non-speculative JITs. Provides common mechanisms for virtual and
     49 // physical register management, calls out from JIT code to helper
     50 // functions, etc.
     51 class JITCodeGenerator {
     52 protected:
     53     typedef MacroAssembler::TrustedImm32 TrustedImm32;
     54     typedef MacroAssembler::Imm32 Imm32;
     55 
     56     // These constants are used to set priorities for spill order for
     57     // the register allocator.
     58     enum SpillOrder {
     59         SpillOrderNone,
     60         SpillOrderConstant = 1, // no spill, and cheap fill
     61         SpillOrderSpilled = 2,  // no spill
     62         SpillOrderJS = 4,       // needs spill
     63         SpillOrderCell = 4,     // needs spill
     64         SpillOrderInteger = 5,  // needs spill and box
     65         SpillOrderDouble = 6,   // needs spill and convert
     66         SpillOrderMax
     67     };
     68 
     69 
     70 public:
     71     GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
     72     FPRReg fillDouble(NodeIndex);
     73     GPRReg fillJSValue(NodeIndex);
     74 
     75     // lock and unlock GPR & FPR registers.
     76     void lock(GPRReg reg)
     77     {
     78         m_gprs.lock(reg);
     79     }
     80     void lock(FPRReg reg)
     81     {
     82         m_fprs.lock(reg);
     83     }
     84     void unlock(GPRReg reg)
     85     {
     86         m_gprs.unlock(reg);
     87     }
     88     void unlock(FPRReg reg)
     89     {
     90         m_fprs.unlock(reg);
     91     }
     92 
     93     // Used to check whether a child node is on its last use,
     94     // and its machine registers may be reused.
     95     bool canReuse(NodeIndex nodeIndex)
     96     {
     97         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister;
     98         GenerationInfo& info = m_generationInfo[virtualRegister];
     99         return info.canReuse();
    100     }
    101     GPRReg reuse(GPRReg reg)
    102     {
    103         m_gprs.lock(reg);
    104         return reg;
    105     }
    106     FPRReg reuse(FPRReg reg)
    107     {
    108         m_fprs.lock(reg);
    109         return reg;
    110     }
    111 
    112     // Allocate a gpr/fpr.
    113     GPRReg allocate()
    114     {
    115         VirtualRegister spillMe;
    116         GPRReg gpr = m_gprs.allocate(spillMe);
    117         if (spillMe != InvalidVirtualRegister)
    118             spill(spillMe);
    119         return gpr;
    120     }
    121     FPRReg fprAllocate()
    122     {
    123         VirtualRegister spillMe;
    124         FPRReg fpr = m_fprs.allocate(spillMe);
    125         if (spillMe != InvalidVirtualRegister)
    126             spill(spillMe);
    127         return fpr;
    128     }
    129 
    130     // Check whether a VirtualRegsiter is currently in a machine register.
    131     // We use this when filling operands to fill those that are already in
    132     // machine registers first (by locking VirtualRegsiters that are already
    133     // in machine register before filling those that are not we attempt to
    134     // avoid spilling values we will need immediately).
    135     bool isFilled(NodeIndex nodeIndex)
    136     {
    137         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister;
    138         GenerationInfo& info = m_generationInfo[virtualRegister];
    139         return info.registerFormat() != DataFormatNone;
    140     }
    141     bool isFilledDouble(NodeIndex nodeIndex)
    142     {
    143         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister;
    144         GenerationInfo& info = m_generationInfo[virtualRegister];
    145         return info.registerFormat() == DataFormatDouble;
    146     }
    147 
    148 protected:
    149     JITCodeGenerator(JITCompiler& jit, bool isSpeculative)
    150         : m_jit(jit)
    151         , m_isSpeculative(isSpeculative)
    152         , m_compileIndex(0)
    153         , m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
    154         , m_blockHeads(jit.graph().m_blocks.size())
    155     {
    156     }
    157 
    158     // These methods convert between doubles, and doubles boxed and JSValues.
    159     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
    160     {
    161         JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr);
    162         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
    163         m_jit.moveDoubleToPtr(fpReg, reg);
    164         m_jit.subPtr(JITCompiler::tagTypeNumberRegister, reg);
    165         return gpr;
    166     }
    167     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
    168     {
    169         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
    170         JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr);
    171         m_jit.addPtr(JITCompiler::tagTypeNumberRegister, reg);
    172         m_jit.movePtrToDouble(reg, fpReg);
    173         return fpr;
    174     }
    175     GPRReg boxDouble(FPRReg fpr)
    176     {
    177         return boxDouble(fpr, allocate());
    178     }
    179     FPRReg unboxDouble(GPRReg gpr)
    180     {
    181         return unboxDouble(gpr, fprAllocate());
    182     }
    183 
    184     // Called on an operand once it has been consumed by a parent node.
    185     void use(NodeIndex nodeIndex)
    186     {
    187         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister;
    188         GenerationInfo& info = m_generationInfo[virtualRegister];
    189 
    190         // use() returns true when the value becomes dead, and any
    191         // associated resources may be freed.
    192         if (!info.use())
    193             return;
    194 
    195         // Release the associated machine registers.
    196         DataFormat registerFormat = info.registerFormat();
    197         if (registerFormat == DataFormatDouble)
    198             m_fprs.release(info.fpr());
    199         else if (registerFormat != DataFormatNone)
    200             m_gprs.release(info.gpr());
    201     }
    202 
    203     // Spill a VirtualRegister to the RegisterFile.
    204     void spill(VirtualRegister spillMe)
    205     {
    206         GenerationInfo& info = m_generationInfo[spillMe];
    207 
    208         // Check the GenerationInfo to see if this value need writing
    209         // to the RegisterFile - if not, mark it as spilled & return.
    210         if (!info.needsSpill()) {
    211             info.setSpilled();
    212             return;
    213         }
    214 
    215         DataFormat spillFormat = info.registerFormat();
    216         if (spillFormat == DataFormatDouble) {
    217             // All values are spilled as JSValues, so box the double via a temporary gpr.
    218             GPRReg gpr = boxDouble(info.fpr());
    219             m_jit.storePtr(JITCompiler::gprToRegisterID(gpr), JITCompiler::addressFor(spillMe));
    220             unlock(gpr);
    221             info.spill(DataFormatJSDouble);
    222             return;
    223         }
    224 
    225         // The following code handles JSValues, int32s, and cells.
    226         ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
    227 
    228         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
    229         // We need to box int32 and cell values ...
    230         // but on JSVALUE64 boxing a cell is a no-op!
    231         if (spillFormat == DataFormatInteger)
    232             m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
    233 
    234         // Spill the value, and record it as spilled in its boxed form.
    235         m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
    236         info.spill((DataFormat)(spillFormat | DataFormatJS));
    237     }
    238 
    239     // Checks/accessors for constant values.
    240     bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
    241     bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
    242     bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
    243     bool isJSConstant(NodeIndex nodeIndex) { return m_jit.isJSConstant(nodeIndex); }
    244     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
    245     double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
    246     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
    247 
    248     Identifier* identifier(unsigned index)
    249     {
    250         return &m_jit.codeBlock()->identifier(index);
    251     }
    252 
    253     // Spill all VirtualRegisters back to the RegisterFile.
    254     void flushRegisters()
    255     {
    256         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    257             VirtualRegister name = m_gprs.name(gpr);
    258             if (name != InvalidVirtualRegister) {
    259                 spill(name);
    260                 m_gprs.release(gpr);
    261             }
    262         }
    263         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    264             VirtualRegister name = m_fprs.name(fpr);
    265             if (name != InvalidVirtualRegister) {
    266                 spill(name);
    267                 m_fprs.release(fpr);
    268             }
    269         }
    270     }
    271 
    272 #ifndef NDEBUG
    273     // Used to ASSERT flushRegisters() has been called prior to
    274     // calling out from JIT code to a C helper function.
    275     bool isFlushed()
    276     {
    277         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    278             VirtualRegister name = m_gprs.name(gpr);
    279             if (name != InvalidVirtualRegister)
    280                 return false;
    281         }
    282         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    283             VirtualRegister name = m_fprs.name(fpr);
    284             if (name != InvalidVirtualRegister)
    285                 return false;
    286         }
    287         return true;
    288     }
    289 #endif
    290 
    291     // Get the JSValue representation of a constant.
    292     JSValue constantAsJSValue(NodeIndex nodeIndex)
    293     {
    294         Node& node = m_jit.graph()[nodeIndex];
    295         if (isInt32Constant(nodeIndex))
    296             return jsNumber(node.int32Constant());
    297         if (isDoubleConstant(nodeIndex))
    298             return JSValue(JSValue::EncodeAsDouble, node.numericConstant());
    299         ASSERT(isJSConstant(nodeIndex));
    300         return valueOfJSConstant(nodeIndex);
    301     }
    302     MacroAssembler::ImmPtr constantAsJSValueAsImmPtr(NodeIndex nodeIndex)
    303     {
    304         return MacroAssembler::ImmPtr(JSValue::encode(constantAsJSValue(nodeIndex)));
    305     }
    306 
    307     // Helper functions to enable code sharing in implementations of bit/shift ops.
    308     void bitOp(NodeType op, int32_t imm, MacroAssembler::RegisterID op1, MacroAssembler::RegisterID result)
    309     {
    310         switch (op) {
    311         case BitAnd:
    312             m_jit.and32(Imm32(imm), op1, result);
    313             break;
    314         case BitOr:
    315             m_jit.or32(Imm32(imm), op1, result);
    316             break;
    317         case BitXor:
    318             m_jit.xor32(Imm32(imm), op1, result);
    319             break;
    320         default:
    321             ASSERT_NOT_REACHED();
    322         }
    323     }
    324     void bitOp(NodeType op, MacroAssembler::RegisterID op1, MacroAssembler::RegisterID op2, MacroAssembler::RegisterID result)
    325     {
    326         switch (op) {
    327         case BitAnd:
    328             m_jit.and32(op1, op2, result);
    329             break;
    330         case BitOr:
    331             m_jit.or32(op1, op2, result);
    332             break;
    333         case BitXor:
    334             m_jit.xor32(op1, op2, result);
    335             break;
    336         default:
    337             ASSERT_NOT_REACHED();
    338         }
    339     }
    340     void shiftOp(NodeType op, MacroAssembler::RegisterID op1, int32_t shiftAmount, MacroAssembler::RegisterID result)
    341     {
    342         switch (op) {
    343         case BitRShift:
    344             m_jit.rshift32(op1, Imm32(shiftAmount), result);
    345             break;
    346         case BitLShift:
    347             m_jit.lshift32(op1, Imm32(shiftAmount), result);
    348             break;
    349         case BitURShift:
    350             m_jit.urshift32(op1, Imm32(shiftAmount), result);
    351             break;
    352         default:
    353             ASSERT_NOT_REACHED();
    354         }
    355     }
    356     void shiftOp(NodeType op, MacroAssembler::RegisterID op1, MacroAssembler::RegisterID shiftAmount, MacroAssembler::RegisterID result)
    357     {
    358         switch (op) {
    359         case BitRShift:
    360             m_jit.rshift32(op1, shiftAmount, result);
    361             break;
    362         case BitLShift:
    363             m_jit.lshift32(op1, shiftAmount, result);
    364             break;
    365         case BitURShift:
    366             m_jit.urshift32(op1, shiftAmount, result);
    367             break;
    368         default:
    369             ASSERT_NOT_REACHED();
    370         }
    371     }
    372 
    373     // Called once a node has completed code generation but prior to setting
    374     // its result, to free up its children. (This must happen prior to setting
    375     // the nodes result, since the node may have the same VirtualRegister as
    376     // a child, and as such will use the same GeneratioInfo).
    377     void useChildren(Node&);
    378 
    379     // These method called to initialize the the GenerationInfo
    380     // to describe the result of an operation.
    381     void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger)
    382     {
    383         Node& node = m_jit.graph()[nodeIndex];
    384         useChildren(node);
    385 
    386         VirtualRegister virtualRegister = node.virtualRegister;
    387         GenerationInfo& info = m_generationInfo[virtualRegister];
    388 
    389         if (format == DataFormatInteger) {
    390             m_jit.jitAssertIsInt32(reg);
    391             m_gprs.retain(reg, virtualRegister, SpillOrderInteger);
    392             info.initInteger(nodeIndex, node.refCount, reg);
    393         } else {
    394             ASSERT(format == DataFormatJSInteger);
    395             m_jit.jitAssertIsJSInt32(reg);
    396             m_gprs.retain(reg, virtualRegister, SpillOrderJS);
    397             info.initJSValue(nodeIndex, node.refCount, reg, format);
    398         }
    399     }
    400     void noResult(NodeIndex nodeIndex)
    401     {
    402         Node& node = m_jit.graph()[nodeIndex];
    403         useChildren(node);
    404 
    405         VirtualRegister virtualRegister = node.virtualRegister;
    406         GenerationInfo& info = m_generationInfo[virtualRegister];
    407         info.initNone(nodeIndex, node.refCount);
    408     }
    409     void cellResult(GPRReg reg, NodeIndex nodeIndex)
    410     {
    411         Node& node = m_jit.graph()[nodeIndex];
    412         useChildren(node);
    413 
    414         VirtualRegister virtualRegister = node.virtualRegister;
    415         m_gprs.retain(reg, virtualRegister, SpillOrderCell);
    416         GenerationInfo& info = m_generationInfo[virtualRegister];
    417         info.initCell(nodeIndex, node.refCount, reg);
    418     }
    419     void jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS)
    420     {
    421         if (format == DataFormatJSInteger)
    422             m_jit.jitAssertIsJSInt32(reg);
    423 
    424         Node& node = m_jit.graph()[nodeIndex];
    425         useChildren(node);
    426 
    427         VirtualRegister virtualRegister = node.virtualRegister;
    428         m_gprs.retain(reg, virtualRegister, SpillOrderJS);
    429         GenerationInfo& info = m_generationInfo[virtualRegister];
    430         info.initJSValue(nodeIndex, node.refCount, reg, format);
    431     }
    432     void doubleResult(FPRReg reg, NodeIndex nodeIndex)
    433     {
    434         Node& node = m_jit.graph()[nodeIndex];
    435         useChildren(node);
    436 
    437         VirtualRegister virtualRegister = node.virtualRegister;
    438         m_fprs.retain(reg, virtualRegister, SpillOrderDouble);
    439         GenerationInfo& info = m_generationInfo[virtualRegister];
    440         info.initDouble(nodeIndex, node.refCount, reg);
    441     }
    442     void initConstantInfo(NodeIndex nodeIndex)
    443     {
    444         ASSERT(isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex) || isJSConstant(nodeIndex));
    445         Node& node = m_jit.graph()[nodeIndex];
    446         m_generationInfo[node.virtualRegister].initConstant(nodeIndex, node.refCount);
    447     }
    448 
    449     // These methods used to sort arguments into the correct registers.
    450     template<GPRReg destA, GPRReg destB>
    451     void setupTwoStubArgs(GPRReg srcA, GPRReg srcB)
    452     {
    453         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
    454         // (1) both are already in arg regs, the right way around.
    455         // (2) both are already in arg regs, the wrong way around.
    456         // (3) neither are currently in arg registers.
    457         // (4) srcA in in its correct reg.
    458         // (5) srcA in in the incorrect reg.
    459         // (6) srcB in in its correct reg.
    460         // (7) srcB in in the incorrect reg.
    461         //
    462         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
    463         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
    464         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
    465         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
    466 
    467         if (srcB != destA) {
    468             // Handle the easy cases - two simple moves.
    469             m_jit.move(JITCompiler::gprToRegisterID(srcA), JITCompiler::gprToRegisterID(destA));
    470             m_jit.move(JITCompiler::gprToRegisterID(srcB), JITCompiler::gprToRegisterID(destB));
    471         } else if (srcA != destB) {
    472             // Handle the non-swap case - just put srcB in place first.
    473             m_jit.move(JITCompiler::gprToRegisterID(srcB), JITCompiler::gprToRegisterID(destB));
    474             m_jit.move(JITCompiler::gprToRegisterID(srcA), JITCompiler::gprToRegisterID(destA));
    475         } else
    476             m_jit.swap(JITCompiler::gprToRegisterID(destB), JITCompiler::gprToRegisterID(destB));
    477     }
    478     template<FPRReg destA, FPRReg destB>
    479     void setupTwoStubArgs(FPRReg srcA, FPRReg srcB)
    480     {
    481         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
    482         // (1) both are already in arg regs, the right way around.
    483         // (2) both are already in arg regs, the wrong way around.
    484         // (3) neither are currently in arg registers.
    485         // (4) srcA in in its correct reg.
    486         // (5) srcA in in the incorrect reg.
    487         // (6) srcB in in its correct reg.
    488         // (7) srcB in in the incorrect reg.
    489         //
    490         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
    491         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
    492         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
    493         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
    494 
    495         if (srcB != destA) {
    496             // Handle the easy cases - two simple moves.
    497             m_jit.moveDouble(JITCompiler::fprToRegisterID(srcA), JITCompiler::fprToRegisterID(destA));
    498             m_jit.moveDouble(JITCompiler::fprToRegisterID(srcB), JITCompiler::fprToRegisterID(destB));
    499             return;
    500         }
    501 
    502         if (srcA != destB) {
    503             // Handle the non-swap case - just put srcB in place first.
    504             m_jit.moveDouble(JITCompiler::fprToRegisterID(srcB), JITCompiler::fprToRegisterID(destB));
    505             m_jit.moveDouble(JITCompiler::fprToRegisterID(srcA), JITCompiler::fprToRegisterID(destA));
    506             return;
    507         }
    508 
    509         ASSERT(srcB == destA && srcA == destB);
    510         // Need to swap; pick a temporary register.
    511         FPRReg temp;
    512         if (destA != JITCompiler::argumentFPR3 && destA != JITCompiler::argumentFPR3)
    513             temp = JITCompiler::argumentFPR3;
    514         else if (destA != JITCompiler::argumentFPR2 && destA != JITCompiler::argumentFPR2)
    515             temp = JITCompiler::argumentFPR2;
    516         else {
    517             ASSERT(destA != JITCompiler::argumentFPR1 && destA != JITCompiler::argumentFPR1);
    518             temp = JITCompiler::argumentFPR1;
    519         }
    520         m_jit.moveDouble(JITCompiler::fprToRegisterID(destA), JITCompiler::fprToRegisterID(temp));
    521         m_jit.moveDouble(JITCompiler::fprToRegisterID(destB), JITCompiler::fprToRegisterID(destA));
    522         m_jit.moveDouble(JITCompiler::fprToRegisterID(temp), JITCompiler::fprToRegisterID(destB));
    523     }
    524     void setupStubArguments(GPRReg arg1, GPRReg arg2)
    525     {
    526         setupTwoStubArgs<JITCompiler::argumentGPR1, JITCompiler::argumentGPR2>(arg1, arg2);
    527     }
    528     void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3)
    529     {
    530         // If neither of arg2/arg3 are in our way, then we can move arg1 into place.
    531         // Then we can use setupTwoStubArgs to fix arg2/arg3.
    532         if (arg2 != JITCompiler::argumentGPR1 && arg3 != JITCompiler::argumentGPR1) {
    533             m_jit.move(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
    534             setupTwoStubArgs<JITCompiler::argumentGPR2, JITCompiler::argumentGPR3>(arg2, arg3);
    535             return;
    536         }
    537 
    538         // If neither of arg1/arg3 are in our way, then we can move arg2 into place.
    539         // Then we can use setupTwoStubArgs to fix arg1/arg3.
    540         if (arg1 != JITCompiler::argumentGPR2 && arg3 != JITCompiler::argumentGPR2) {
    541             m_jit.move(JITCompiler::gprToRegisterID(arg2), JITCompiler::argumentRegister2);
    542             setupTwoStubArgs<JITCompiler::argumentGPR1, JITCompiler::argumentGPR3>(arg1, arg3);
    543             return;
    544         }
    545 
    546         // If neither of arg1/arg2 are in our way, then we can move arg3 into place.
    547         // Then we can use setupTwoStubArgs to fix arg1/arg2.
    548         if (arg1 != JITCompiler::argumentGPR3 && arg2 != JITCompiler::argumentGPR3) {
    549             m_jit.move(JITCompiler::gprToRegisterID(arg3), JITCompiler::argumentRegister3);
    550             setupTwoStubArgs<JITCompiler::argumentGPR1, JITCompiler::argumentGPR2>(arg1, arg2);
    551             return;
    552         }
    553 
    554         // If we get here, we haven't been able to move any of arg1/arg2/arg3.
    555         // Since all three are blocked, then all three must already be in the argument register.
    556         // But are they in the right ones?
    557 
    558         // First, ensure arg1 is in place.
    559         if (arg1 != JITCompiler::argumentGPR1) {
    560             m_jit.swap(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
    561 
    562             // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be.
    563             ASSERT(arg2 == JITCompiler::argumentGPR1 || arg3 == JITCompiler::argumentGPR1);
    564             // If arg2 was in argumentGPR1 it no longer is (due to the swap).
    565             // Otherwise arg3 must have been. Mark him as moved.
    566             if (arg2 == JITCompiler::argumentGPR1)
    567                 arg2 = arg1;
    568             else
    569                 arg3 = arg1;
    570         }
    571 
    572         // Either arg2 & arg3 need swapping, or we're all done.
    573         ASSERT((arg2 == JITCompiler::argumentGPR2 || arg3 == JITCompiler::argumentGPR3)
    574             || (arg2 == JITCompiler::argumentGPR3 || arg3 == JITCompiler::argumentGPR2));
    575 
    576         if (arg2 != JITCompiler::argumentGPR2)
    577             m_jit.swap(JITCompiler::argumentRegister2, JITCompiler::argumentRegister3);
    578     }
    579 
    580     // These methods add calls to C++ helper functions.
    581     void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
    582     {
    583         ASSERT(isFlushed());
    584 
    585         m_jit.move(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
    586         m_jit.move(JITCompiler::TrustedImmPtr(pointer), JITCompiler::argumentRegister2);
    587         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    588 
    589         appendCallWithExceptionCheck(operation);
    590         m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
    591     }
    592     void callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
    593     {
    594         callOperation((J_DFGOperation_EJP)operation, result, arg1, identifier);
    595     }
    596     void callOperation(J_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
    597     {
    598         ASSERT(isFlushed());
    599 
    600         m_jit.move(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
    601         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    602 
    603         appendCallWithExceptionCheck(operation);
    604         m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
    605     }
    606     void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
    607     {
    608         ASSERT(isFlushed());
    609 
    610         m_jit.move(JITCompiler::gprToRegisterID(arg1), JITCompiler::argumentRegister1);
    611         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    612 
    613         appendCallWithExceptionCheck(operation);
    614         m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
    615     }
    616     void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    617     {
    618         ASSERT(isFlushed());
    619 
    620         setupStubArguments(arg1, arg2);
    621         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    622 
    623         appendCallWithExceptionCheck(operation);
    624         m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
    625     }
    626     void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
    627     {
    628         ASSERT(isFlushed());
    629 
    630         setupStubArguments(arg1, arg2);
    631         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    632 
    633         appendCallWithExceptionCheck(operation);
    634         m_jit.move(JITCompiler::returnValueRegister, JITCompiler::gprToRegisterID(result));
    635     }
    636     void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
    637     {
    638         ASSERT(isFlushed());
    639 
    640         setupStubArguments(arg1, arg2);
    641         m_jit.move(JITCompiler::TrustedImmPtr(pointer), JITCompiler::argumentRegister3);
    642         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    643 
    644         appendCallWithExceptionCheck(operation);
    645     }
    646     void callOperation(V_DFGOperation_EJJI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
    647     {
    648         callOperation((V_DFGOperation_EJJP)operation, arg1, arg2, identifier);
    649     }
    650     void callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
    651     {
    652         ASSERT(isFlushed());
    653 
    654         setupStubArguments(arg1, arg2, arg3);
    655         m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    656 
    657         appendCallWithExceptionCheck(operation);
    658     }
    659     void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
    660     {
    661         ASSERT(isFlushed());
    662 
    663         setupTwoStubArgs<JITCompiler::argumentFPR0, JITCompiler::argumentFPR1>(arg1, arg2);
    664 
    665         m_jit.appendCall(operation);
    666         m_jit.moveDouble(JITCompiler::fpReturnValueRegister, JITCompiler::fprToRegisterID(result));
    667     }
    668 
    669     void appendCallWithExceptionCheck(const FunctionPtr& function)
    670     {
    671         m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
    672     }
    673 
    674     void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
    675     {
    676         m_branches.append(BranchRecord(jump, destination));
    677     }
    678 
    679     void linkBranches()
    680     {
    681         for (size_t i = 0; i < m_branches.size(); ++i) {
    682             BranchRecord& branch = m_branches[i];
    683             branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
    684         }
    685     }
    686 
    687 #ifndef NDEBUG
    688     void dump(const char* label = 0);
    689 #endif
    690 
    691 #if DFG_CONSISTENCY_CHECK
    692     void checkConsistency();
    693 #else
    694     void checkConsistency() {}
    695 #endif
    696 
    697     // The JIT, while also provides MacroAssembler functionality.
    698     JITCompiler& m_jit;
    699     // This flag is used to distinguish speculative and non-speculative
    700     // code generation. This is significant when filling spilled values
    701     // from the RegisterFile. When spilling we attempt to store information
    702     // as to the type of boxed value being stored (int32, double, cell), and
    703     // when filling on the speculative path we will retrieve this type info
    704     // where available. On the non-speculative path, however, we cannot rely
    705     // on the spill format info, since the a value being loaded might have
    706     // been spilled by either the speculative or non-speculative paths (where
    707     // we entered the non-speculative path on an intervening bail-out), and
    708     // the value may have been boxed differently on the two paths.
    709     bool m_isSpeculative;
    710     // The current node being generated.
    711     BlockIndex m_block;
    712     NodeIndex m_compileIndex;
    713     // Virtual and physical register maps.
    714     Vector<GenerationInfo, 32> m_generationInfo;
    715     RegisterBank<GPRReg, numberOfGPRs, SpillOrder, SpillOrderNone, SpillOrderMax> m_gprs;
    716     RegisterBank<FPRReg, numberOfFPRs, SpillOrder, SpillOrderNone, SpillOrderMax> m_fprs;
    717 
    718     Vector<MacroAssembler::Label> m_blockHeads;
    719     struct BranchRecord {
    720         BranchRecord(MacroAssembler::Jump jump, BlockIndex destination)
    721             : jump(jump)
    722             , destination(destination)
    723         {
    724         }
    725 
    726         MacroAssembler::Jump jump;
    727         BlockIndex destination;
    728     };
    729     Vector<BranchRecord, 8> m_branches;
    730 };
    731 
    732 // === Operand types ===
    733 //
    734 // IntegerOperand, DoubleOperand and JSValueOperand.
    735 //
    736 // These classes are used to lock the operands to a node into machine
    737 // registers. These classes implement of pattern of locking a value
    738 // into register at the point of construction only if it is already in
    739 // registers, and otherwise loading it lazily at the point it is first
    740 // used. We do so in order to attempt to avoid spilling one operand
    741 // in order to make space available for another.
    742 
    743 class IntegerOperand {
    744 public:
    745     explicit IntegerOperand(JITCodeGenerator* jit, NodeIndex index)
    746         : m_jit(jit)
    747         , m_index(index)
    748         , m_gprOrInvalid(InvalidGPRReg)
    749 #ifndef NDEBUG
    750         , m_format(DataFormatNone)
    751 #endif
    752     {
    753         ASSERT(m_jit);
    754         if (jit->isFilled(index))
    755             gpr();
    756     }
    757 
    758     ~IntegerOperand()
    759     {
    760         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    761         m_jit->unlock(m_gprOrInvalid);
    762     }
    763 
    764     NodeIndex index() const
    765     {
    766         return m_index;
    767     }
    768 
    769     GPRReg gpr()
    770     {
    771         if (m_gprOrInvalid == InvalidGPRReg)
    772             m_gprOrInvalid = m_jit->fillInteger(index(), m_format);
    773         return m_gprOrInvalid;
    774     }
    775 
    776     DataFormat format()
    777     {
    778         gpr(); // m_format is set when m_gpr is locked.
    779         ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
    780         return m_format;
    781     }
    782 
    783     MacroAssembler::RegisterID registerID()
    784     {
    785         return JITCompiler::gprToRegisterID(gpr());
    786     }
    787 
    788 private:
    789     JITCodeGenerator* m_jit;
    790     NodeIndex m_index;
    791     GPRReg m_gprOrInvalid;
    792     DataFormat m_format;
    793 };
    794 
    795 class DoubleOperand {
    796 public:
    797     explicit DoubleOperand(JITCodeGenerator* jit, NodeIndex index)
    798         : m_jit(jit)
    799         , m_index(index)
    800         , m_fprOrInvalid(InvalidFPRReg)
    801     {
    802         ASSERT(m_jit);
    803         if (jit->isFilledDouble(index))
    804             fpr();
    805     }
    806 
    807     ~DoubleOperand()
    808     {
    809         ASSERT(m_fprOrInvalid != InvalidFPRReg);
    810         m_jit->unlock(m_fprOrInvalid);
    811     }
    812 
    813     NodeIndex index() const
    814     {
    815         return m_index;
    816     }
    817 
    818     FPRReg fpr()
    819     {
    820         if (m_fprOrInvalid == InvalidFPRReg)
    821             m_fprOrInvalid = m_jit->fillDouble(index());
    822         return m_fprOrInvalid;
    823     }
    824 
    825     MacroAssembler::FPRegisterID registerID()
    826     {
    827         return JITCompiler::fprToRegisterID(fpr());
    828     }
    829 
    830 private:
    831     JITCodeGenerator* m_jit;
    832     NodeIndex m_index;
    833     FPRReg m_fprOrInvalid;
    834 };
    835 
    836 class JSValueOperand {
    837 public:
    838     explicit JSValueOperand(JITCodeGenerator* jit, NodeIndex index)
    839         : m_jit(jit)
    840         , m_index(index)
    841         , m_gprOrInvalid(InvalidGPRReg)
    842     {
    843         ASSERT(m_jit);
    844         if (jit->isFilled(index))
    845             gpr();
    846     }
    847 
    848     ~JSValueOperand()
    849     {
    850         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    851         m_jit->unlock(m_gprOrInvalid);
    852     }
    853 
    854     NodeIndex index() const
    855     {
    856         return m_index;
    857     }
    858 
    859     GPRReg gpr()
    860     {
    861         if (m_gprOrInvalid == InvalidGPRReg)
    862             m_gprOrInvalid = m_jit->fillJSValue(index());
    863         return m_gprOrInvalid;
    864     }
    865 
    866     MacroAssembler::RegisterID registerID()
    867     {
    868         return JITCompiler::gprToRegisterID(gpr());
    869     }
    870 
    871 private:
    872     JITCodeGenerator* m_jit;
    873     NodeIndex m_index;
    874     GPRReg m_gprOrInvalid;
    875 };
    876 
    877 
    878 // === Temporaries ===
    879 //
    880 // These classes are used to allocate temporary registers.
    881 // A mechanism is provided to attempt to reuse the registers
    882 // currently allocated to child nodes whose value is consumed
    883 // by, and not live after, this operation.
    884 
    885 class GPRTemporary {
    886 public:
    887     GPRTemporary(JITCodeGenerator*);
    888     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&);
    889     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
    890     GPRTemporary(JITCodeGenerator*, IntegerOperand&);
    891     GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
    892     GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
    893     GPRTemporary(JITCodeGenerator*, JSValueOperand&);
    894 
    895     ~GPRTemporary()
    896     {
    897         m_jit->unlock(gpr());
    898     }
    899 
    900     GPRReg gpr() const
    901     {
    902         ASSERT(m_gpr != InvalidGPRReg);
    903         return m_gpr;
    904     }
    905 
    906     MacroAssembler::RegisterID registerID()
    907     {
    908         ASSERT(m_gpr != InvalidGPRReg);
    909         return JITCompiler::gprToRegisterID(m_gpr);
    910     }
    911 
    912 protected:
    913     GPRTemporary(JITCodeGenerator* jit, GPRReg lockedGPR)
    914         : m_jit(jit)
    915         , m_gpr(lockedGPR)
    916     {
    917     }
    918 
    919 private:
    920     JITCodeGenerator* m_jit;
    921     GPRReg m_gpr;
    922 };
    923 
    924 class FPRTemporary {
    925 public:
    926     FPRTemporary(JITCodeGenerator*);
    927     FPRTemporary(JITCodeGenerator*, DoubleOperand&);
    928     FPRTemporary(JITCodeGenerator*, DoubleOperand&, DoubleOperand&);
    929 
    930     ~FPRTemporary()
    931     {
    932         m_jit->unlock(fpr());
    933     }
    934 
    935     FPRReg fpr() const
    936     {
    937         ASSERT(m_fpr != InvalidFPRReg);
    938         return m_fpr;
    939     }
    940 
    941     MacroAssembler::FPRegisterID registerID()
    942     {
    943         ASSERT(m_fpr != InvalidFPRReg);
    944         return JITCompiler::fprToRegisterID(m_fpr);
    945     }
    946 
    947 protected:
    948     FPRTemporary(JITCodeGenerator* jit, FPRReg lockedFPR)
    949         : m_jit(jit)
    950         , m_fpr(lockedFPR)
    951     {
    952     }
    953 
    954 private:
    955     JITCodeGenerator* m_jit;
    956     FPRReg m_fpr;
    957 };
    958 
    959 
    960 // === Results ===
    961 //
    962 // These classes lock the result of a call to a C++ helper function.
    963 
    964 class GPRResult : public GPRTemporary {
    965 public:
    966     GPRResult(JITCodeGenerator* jit)
    967         : GPRTemporary(jit, lockedResult(jit))
    968     {
    969     }
    970 
    971 private:
    972     static GPRReg lockedResult(JITCodeGenerator* jit)
    973     {
    974         jit->lock(JITCompiler::returnValueGPR);
    975         return JITCompiler::returnValueGPR;
    976     }
    977 };
    978 
    979 class FPRResult : public FPRTemporary {
    980 public:
    981     FPRResult(JITCodeGenerator* jit)
    982         : FPRTemporary(jit, lockedResult(jit))
    983     {
    984     }
    985 
    986 private:
    987     static FPRReg lockedResult(JITCodeGenerator* jit)
    988     {
    989         jit->lock(JITCompiler::returnValueFPR);
    990         return JITCompiler::returnValueFPR;
    991     }
    992 };
    993 
    994 } } // namespace JSC::DFG
    995 
    996 #endif
    997 #endif
    998 
    999