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 #include "config.h"
     27 #include "DFGSpeculativeJIT.h"
     28 
     29 #if ENABLE(DFG_JIT)
     30 
     31 namespace JSC { namespace DFG {
     32 
     33 template<bool strict>
     34 GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
     35 {
     36     Node& node = m_jit.graph()[nodeIndex];
     37     VirtualRegister virtualRegister = node.virtualRegister;
     38     GenerationInfo& info = m_generationInfo[virtualRegister];
     39 
     40     switch (info.registerFormat()) {
     41     case DataFormatNone: {
     42         GPRReg gpr = allocate();
     43         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
     44 
     45         if (node.isConstant()) {
     46             m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
     47             if (isInt32Constant(nodeIndex)) {
     48                 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), reg);
     49                 info.fillInteger(gpr);
     50                 returnFormat = DataFormatInteger;
     51                 return gpr;
     52             }
     53             m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
     54         } else {
     55             DataFormat spillFormat = info.spillFormat();
     56             ASSERT(spillFormat & DataFormatJS);
     57 
     58             m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
     59 
     60             if (spillFormat == DataFormatJSInteger) {
     61                 // If we know this was spilled as an integer we can fill without checking.
     62                 if (strict) {
     63                     m_jit.load32(JITCompiler::addressFor(virtualRegister), reg);
     64                     info.fillInteger(gpr);
     65                     returnFormat = DataFormatInteger;
     66                     return gpr;
     67                 }
     68                 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
     69                 info.fillJSValue(gpr, DataFormatJSInteger);
     70                 returnFormat = DataFormatJSInteger;
     71                 return gpr;
     72             }
     73             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
     74         }
     75 
     76         // Fill as JSValue, and fall through.
     77         info.fillJSValue(gpr, DataFormatJSInteger);
     78         m_gprs.unlock(gpr);
     79     }
     80 
     81     case DataFormatJS: {
     82         // Check the value is an integer.
     83         GPRReg gpr = info.gpr();
     84         m_gprs.lock(gpr);
     85         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
     86         speculationCheck(m_jit.branchPtr(MacroAssembler::Below, reg, JITCompiler::tagTypeNumberRegister));
     87         info.fillJSValue(gpr, DataFormatJSInteger);
     88         // If !strict we're done, return.
     89         if (!strict) {
     90             returnFormat = DataFormatJSInteger;
     91             return gpr;
     92         }
     93         // else fall through & handle as DataFormatJSInteger.
     94         m_gprs.unlock(gpr);
     95     }
     96 
     97     case DataFormatJSInteger: {
     98         // In a strict fill we need to strip off the value tag.
     99         if (strict) {
    100             GPRReg gpr = info.gpr();
    101             GPRReg result;
    102             // If the register has already been locked we need to take a copy.
    103             // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
    104             if (m_gprs.isLocked(gpr))
    105                 result = allocate();
    106             else {
    107                 m_gprs.lock(gpr);
    108                 info.fillInteger(gpr);
    109                 result = gpr;
    110             }
    111             m_jit.zeroExtend32ToPtr(JITCompiler::gprToRegisterID(gpr), JITCompiler::gprToRegisterID(result));
    112             returnFormat = DataFormatInteger;
    113             return result;
    114         }
    115 
    116         GPRReg gpr = info.gpr();
    117         m_gprs.lock(gpr);
    118         returnFormat = DataFormatJSInteger;
    119         return gpr;
    120     }
    121 
    122     case DataFormatInteger: {
    123         GPRReg gpr = info.gpr();
    124         m_gprs.lock(gpr);
    125         returnFormat = DataFormatInteger;
    126         return gpr;
    127     }
    128 
    129     case DataFormatDouble:
    130     case DataFormatCell:
    131     case DataFormatJSDouble:
    132     case DataFormatJSCell: {
    133         terminateSpeculativeExecution();
    134         returnFormat = DataFormatInteger;
    135         return allocate();
    136     }
    137     }
    138 
    139     ASSERT_NOT_REACHED();
    140     return InvalidGPRReg;
    141 }
    142 
    143 SpeculationCheck::SpeculationCheck(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)
    144     : m_check(check)
    145     , m_nodeIndex(jit->m_compileIndex)
    146     , m_recoveryIndex(recoveryIndex)
    147 {
    148     for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    149         VirtualRegister virtualRegister = jit->m_gprs.name(gpr);
    150         if (virtualRegister != InvalidVirtualRegister) {
    151             GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
    152             m_gprInfo[gpr].nodeIndex = info.nodeIndex();
    153             m_gprInfo[gpr].format = info.registerFormat();
    154         } else
    155             m_gprInfo[gpr].nodeIndex = NoNode;
    156     }
    157     for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    158         VirtualRegister virtualRegister = jit->m_fprs.name(fpr);
    159         if (virtualRegister != InvalidVirtualRegister) {
    160             GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
    161             ASSERT(info.registerFormat() == DataFormatDouble);
    162             m_fprInfo[fpr] = info.nodeIndex();
    163         } else
    164             m_fprInfo[fpr] = NoNode;
    165     }
    166 }
    167 
    168 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
    169 {
    170     return fillSpeculateIntInternal<false>(nodeIndex, returnFormat);
    171 }
    172 
    173 GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
    174 {
    175     DataFormat mustBeDataFormatInteger;
    176     GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger);
    177     ASSERT(mustBeDataFormatInteger == DataFormatInteger);
    178     return result;
    179 }
    180 
    181 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
    182 {
    183     Node& node = m_jit.graph()[nodeIndex];
    184     VirtualRegister virtualRegister = node.virtualRegister;
    185     GenerationInfo& info = m_generationInfo[virtualRegister];
    186 
    187     switch (info.registerFormat()) {
    188     case DataFormatNone: {
    189         GPRReg gpr = allocate();
    190         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
    191 
    192         if (node.isConstant()) {
    193             m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
    194             JSValue jsValue = constantAsJSValue(nodeIndex);
    195             if (jsValue.isCell()) {
    196                 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), reg);
    197                 info.fillJSValue(gpr, DataFormatJSCell);
    198                 return gpr;
    199             }
    200             terminateSpeculativeExecution();
    201             return gpr;
    202         }
    203         ASSERT(info.spillFormat() & DataFormatJS);
    204         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
    205         m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
    206 
    207         if (info.spillFormat() != DataFormatJSCell)
    208             speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister));
    209         info.fillJSValue(gpr, DataFormatJSCell);
    210         return gpr;
    211     }
    212 
    213     case DataFormatCell:
    214     case DataFormatJSCell: {
    215         GPRReg gpr = info.gpr();
    216         m_gprs.lock(gpr);
    217         return gpr;
    218     }
    219 
    220     case DataFormatJS: {
    221         GPRReg gpr = info.gpr();
    222         m_gprs.lock(gpr);
    223         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
    224         speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister));
    225         info.fillJSValue(gpr, DataFormatJSCell);
    226         return gpr;
    227     }
    228 
    229     case DataFormatJSInteger:
    230     case DataFormatInteger:
    231     case DataFormatJSDouble:
    232     case DataFormatDouble: {
    233         terminateSpeculativeExecution();
    234         return allocate();
    235     }
    236     }
    237 
    238     ASSERT_NOT_REACHED();
    239     return InvalidGPRReg;
    240 }
    241 
    242 bool SpeculativeJIT::compile(Node& node)
    243 {
    244     checkConsistency();
    245     NodeType op = node.op;
    246 
    247     switch (op) {
    248     case Int32Constant:
    249     case DoubleConstant:
    250     case JSConstant:
    251         initConstantInfo(m_compileIndex);
    252         break;
    253 
    254     case GetLocal: {
    255         GPRTemporary result(this);
    256         m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID());
    257         jsValueResult(result.gpr(), m_compileIndex);
    258         break;
    259     }
    260 
    261     case SetLocal: {
    262         JSValueOperand value(this, node.child1);
    263         m_jit.storePtr(value.registerID(), JITCompiler::addressFor(node.local()));
    264         noResult(m_compileIndex);
    265         break;
    266     }
    267 
    268     case BitAnd:
    269     case BitOr:
    270     case BitXor:
    271         if (isInt32Constant(node.child1)) {
    272             SpeculateIntegerOperand op2(this, node.child2);
    273             GPRTemporary result(this, op2);
    274 
    275             bitOp(op, valueOfInt32Constant(node.child1), op2.registerID(), result.registerID());
    276 
    277             integerResult(result.gpr(), m_compileIndex);
    278         } else if (isInt32Constant(node.child2)) {
    279             SpeculateIntegerOperand op1(this, node.child1);
    280             GPRTemporary result(this, op1);
    281 
    282             bitOp(op, valueOfInt32Constant(node.child2), op1.registerID(), result.registerID());
    283 
    284             integerResult(result.gpr(), m_compileIndex);
    285         } else {
    286             SpeculateIntegerOperand op1(this, node.child1);
    287             SpeculateIntegerOperand op2(this, node.child2);
    288             GPRTemporary result(this, op1, op2);
    289 
    290             MacroAssembler::RegisterID reg1 = op1.registerID();
    291             MacroAssembler::RegisterID reg2 = op2.registerID();
    292             bitOp(op, reg1, reg2, result.registerID());
    293 
    294             integerResult(result.gpr(), m_compileIndex);
    295         }
    296         break;
    297 
    298     case BitRShift:
    299     case BitLShift:
    300     case BitURShift:
    301         if (isInt32Constant(node.child2)) {
    302             SpeculateIntegerOperand op1(this, node.child1);
    303             GPRTemporary result(this, op1);
    304 
    305             shiftOp(op, op1.registerID(), valueOfInt32Constant(node.child2) & 0x1f, result.registerID());
    306 
    307             integerResult(result.gpr(), m_compileIndex);
    308         } else {
    309             // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
    310             SpeculateIntegerOperand op1(this, node.child1);
    311             SpeculateIntegerOperand op2(this, node.child2);
    312             GPRTemporary result(this, op1);
    313 
    314             MacroAssembler::RegisterID reg1 = op1.registerID();
    315             MacroAssembler::RegisterID reg2 = op2.registerID();
    316             shiftOp(op, reg1, reg2, result.registerID());
    317 
    318             integerResult(result.gpr(), m_compileIndex);
    319         }
    320         break;
    321 
    322     case UInt32ToNumber: {
    323         IntegerOperand op1(this, node.child1);
    324         GPRTemporary result(this, op1);
    325 
    326         // Test the operand is positive.
    327         speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op1.registerID(), TrustedImm32(0)));
    328 
    329         m_jit.move(op1.registerID(), result.registerID());
    330         integerResult(result.gpr(), m_compileIndex, op1.format());
    331         break;
    332     }
    333 
    334     case NumberToInt32: {
    335         SpeculateIntegerOperand op1(this, node.child1);
    336         GPRTemporary result(this, op1);
    337         m_jit.move(op1.registerID(), result.registerID());
    338         integerResult(result.gpr(), m_compileIndex, op1.format());
    339         break;
    340     }
    341 
    342     case Int32ToNumber: {
    343         SpeculateIntegerOperand op1(this, node.child1);
    344         GPRTemporary result(this, op1);
    345         m_jit.move(op1.registerID(), result.registerID());
    346         integerResult(result.gpr(), m_compileIndex, op1.format());
    347         break;
    348     }
    349 
    350     case ValueToInt32: {
    351         SpeculateIntegerOperand op1(this, node.child1);
    352         GPRTemporary result(this, op1);
    353         m_jit.move(op1.registerID(), result.registerID());
    354         integerResult(result.gpr(), m_compileIndex, op1.format());
    355         break;
    356     }
    357 
    358     case ValueToNumber: {
    359         SpeculateIntegerOperand op1(this, node.child1);
    360         GPRTemporary result(this, op1);
    361         m_jit.move(op1.registerID(), result.registerID());
    362         integerResult(result.gpr(), m_compileIndex, op1.format());
    363         break;
    364     }
    365 
    366     case ValueAdd:
    367     case ArithAdd: {
    368         int32_t imm1;
    369         if (isDoubleConstantWithInt32Value(node.child1, imm1)) {
    370             SpeculateIntegerOperand op2(this, node.child2);
    371             GPRTemporary result(this);
    372 
    373             MacroAssembler::RegisterID reg = op2.registerID();
    374             speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, reg, Imm32(imm1), result.registerID()));
    375 
    376             integerResult(result.gpr(), m_compileIndex);
    377             break;
    378         }
    379 
    380         int32_t imm2;
    381         if (isDoubleConstantWithInt32Value(node.child2, imm2)) {
    382             SpeculateIntegerOperand op1(this, node.child1);
    383             GPRTemporary result(this);
    384 
    385             MacroAssembler::RegisterID reg = op1.registerID();
    386             speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, reg, Imm32(imm2), result.registerID()));
    387 
    388             integerResult(result.gpr(), m_compileIndex);
    389             break;
    390         }
    391 
    392         SpeculateIntegerOperand op1(this, node.child1);
    393         SpeculateIntegerOperand op2(this, node.child2);
    394         GPRTemporary result(this, op1, op2);
    395 
    396         GPRReg gpr1 = op1.gpr();
    397         GPRReg gpr2 = op2.gpr();
    398         GPRReg gprResult = result.gpr();
    399         MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, JITCompiler::gprToRegisterID(gpr1), JITCompiler::gprToRegisterID(gpr2), JITCompiler::gprToRegisterID(gprResult));
    400 
    401         if (gpr1 == gprResult)
    402             speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
    403         else if (gpr2 == gprResult)
    404             speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
    405         else
    406             speculationCheck(check);
    407 
    408         integerResult(gprResult, m_compileIndex);
    409         break;
    410     }
    411 
    412     case ArithSub: {
    413         int32_t imm2;
    414         if (isDoubleConstantWithInt32Value(node.child2, imm2)) {
    415             SpeculateIntegerOperand op1(this, node.child1);
    416             GPRTemporary result(this);
    417 
    418             MacroAssembler::RegisterID reg = op1.registerID();
    419             speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, reg, Imm32(imm2), result.registerID()));
    420 
    421             integerResult(result.gpr(), m_compileIndex);
    422             break;
    423         }
    424 
    425         SpeculateIntegerOperand op1(this, node.child1);
    426         SpeculateIntegerOperand op2(this, node.child2);
    427         GPRTemporary result(this);
    428 
    429         MacroAssembler::RegisterID reg1 = op1.registerID();
    430         MacroAssembler::RegisterID reg2 = op2.registerID();
    431         speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, reg1, reg2, result.registerID()));
    432 
    433         integerResult(result.gpr(), m_compileIndex);
    434         break;
    435     }
    436 
    437     case ArithMul: {
    438         SpeculateIntegerOperand op1(this, node.child1);
    439         SpeculateIntegerOperand op2(this, node.child2);
    440         GPRTemporary result(this);
    441 
    442         MacroAssembler::RegisterID reg1 = op1.registerID();
    443         MacroAssembler::RegisterID reg2 = op2.registerID();
    444         speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.registerID()));
    445 
    446         MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.registerID());
    447         speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));
    448         speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));
    449         resultNonZero.link(&m_jit);
    450 
    451         integerResult(result.gpr(), m_compileIndex);
    452         break;
    453     }
    454 
    455     case ArithDiv: {
    456         SpeculateIntegerOperand op1(this, node.child1);
    457         SpeculateIntegerOperand op2(this, node.child2);
    458         GPRTemporary result(this, op1, op2);
    459 
    460         terminateSpeculativeExecution();
    461 
    462         integerResult(result.gpr(), m_compileIndex);
    463         break;
    464     }
    465 
    466     case ArithMod: {
    467         SpeculateIntegerOperand op1(this, node.child1);
    468         SpeculateIntegerOperand op2(this, node.child2);
    469         GPRTemporary result(this, op1, op2);
    470 
    471         terminateSpeculativeExecution();
    472 
    473         integerResult(result.gpr(), m_compileIndex);
    474         break;
    475     }
    476 
    477     case LogicalNot: {
    478         JSValueOperand value(this, node.child1);
    479         GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
    480 
    481         m_jit.move(value.registerID(), result.registerID());
    482         m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.registerID());
    483         speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.registerID(), TrustedImm32(static_cast<int32_t>(~1))));
    484         m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.registerID());
    485 
    486         // If we add a DataFormatBool, we should use it here.
    487         jsValueResult(result.gpr(), m_compileIndex);
    488         break;
    489     }
    490 
    491     case CompareLess: {
    492         SpeculateIntegerOperand op1(this, node.child1);
    493         SpeculateIntegerOperand op2(this, node.child2);
    494         GPRTemporary result(this, op1, op2);
    495 
    496         m_jit.set32Compare32(JITCompiler::LessThan, op1.registerID(), op2.registerID(), result.registerID());
    497 
    498         // If we add a DataFormatBool, we should use it here.
    499         m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
    500         jsValueResult(result.gpr(), m_compileIndex);
    501         break;
    502     }
    503 
    504     case CompareLessEq: {
    505         SpeculateIntegerOperand op1(this, node.child1);
    506         SpeculateIntegerOperand op2(this, node.child2);
    507         GPRTemporary result(this, op1, op2);
    508 
    509         m_jit.set32Compare32(JITCompiler::LessThanOrEqual, op1.registerID(), op2.registerID(), result.registerID());
    510 
    511         // If we add a DataFormatBool, we should use it here.
    512         m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
    513         jsValueResult(result.gpr(), m_compileIndex);
    514         break;
    515     }
    516 
    517     case CompareEq: {
    518         SpeculateIntegerOperand op1(this, node.child1);
    519         SpeculateIntegerOperand op2(this, node.child2);
    520         GPRTemporary result(this, op1, op2);
    521 
    522         m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
    523 
    524         // If we add a DataFormatBool, we should use it here.
    525         m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
    526         jsValueResult(result.gpr(), m_compileIndex);
    527         break;
    528     }
    529 
    530     case CompareStrictEq: {
    531         SpeculateIntegerOperand op1(this, node.child1);
    532         SpeculateIntegerOperand op2(this, node.child2);
    533         GPRTemporary result(this, op1, op2);
    534 
    535         m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
    536 
    537         // If we add a DataFormatBool, we should use it here.
    538         m_jit.or32(TrustedImm32(ValueFalse), result.registerID());
    539         jsValueResult(result.gpr(), m_compileIndex);
    540         break;
    541     }
    542 
    543     case GetByVal: {
    544         NodeIndex alias = node.child3;
    545         if (alias != NoNode) {
    546             // FIXME: result should be able to reuse child1, child2. Should have an 'UnusedOperand' type.
    547             JSValueOperand aliasedValue(this, node.child3);
    548             GPRTemporary result(this, aliasedValue);
    549             m_jit.move(aliasedValue.registerID(), result.registerID());
    550             jsValueResult(result.gpr(), m_compileIndex);
    551             break;
    552         }
    553 
    554         SpeculateCellOperand base(this, node.child1);
    555         SpeculateStrictInt32Operand property(this, node.child2);
    556         GPRTemporary storage(this);
    557 
    558         MacroAssembler::RegisterID baseReg = base.registerID();
    559         MacroAssembler::RegisterID propertyReg = property.registerID();
    560         MacroAssembler::RegisterID storageReg = storage.registerID();
    561 
    562         // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if
    563         // an access with offset JSArray::storageOffset() is valid for all JSCells!
    564         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
    565 
    566         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
    567         speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
    568         speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
    569 
    570         // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
    571         // the storage pointer - especially if there happens to be another register free right now. If we do so,
    572         // then we'll need to allocate a new temporary for result.
    573         GPRTemporary& result = storage;
    574         m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.registerID());
    575         speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, result.registerID()));
    576 
    577         jsValueResult(result.gpr(), m_compileIndex);
    578         break;
    579     }
    580 
    581     case PutByVal: {
    582         SpeculateCellOperand base(this, node.child1);
    583         SpeculateStrictInt32Operand property(this, node.child2);
    584         JSValueOperand value(this, node.child3);
    585         GPRTemporary storage(this);
    586 
    587         // Map base, property & value into registers, allocate a register for storage.
    588         MacroAssembler::RegisterID baseReg = base.registerID();
    589         MacroAssembler::RegisterID propertyReg = property.registerID();
    590         MacroAssembler::RegisterID valueReg = value.registerID();
    591         MacroAssembler::RegisterID storageReg = storage.registerID();
    592 
    593         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
    594         speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
    595         speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
    596 
    597         // Get the array storage.
    598         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
    599 
    600         // Check if we're writing to a hole; if so increment m_numValuesInVector.
    601         MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
    602         m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
    603 
    604         // If we're writing to a hole we might be growing the array;
    605         MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
    606         m_jit.add32(TrustedImm32(1), propertyReg);
    607         m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
    608         m_jit.sub32(TrustedImm32(1), propertyReg);
    609 
    610         lengthDoesNotNeedUpdate.link(&m_jit);
    611         notHoleValue.link(&m_jit);
    612 
    613         // Store the value to the array.
    614         m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
    615 
    616         noResult(m_compileIndex);
    617         break;
    618     }
    619 
    620     case PutByValAlias: {
    621         SpeculateCellOperand base(this, node.child1);
    622         SpeculateStrictInt32Operand property(this, node.child2);
    623         JSValueOperand value(this, node.child3);
    624         GPRTemporary storage(this, base); // storage may overwrite base.
    625 
    626         // Get the array storage.
    627         MacroAssembler::RegisterID storageReg = storage.registerID();
    628         m_jit.loadPtr(MacroAssembler::Address(base.registerID(), JSArray::storageOffset()), storageReg);
    629 
    630         // Map property & value into registers.
    631         MacroAssembler::RegisterID propertyReg = property.registerID();
    632         MacroAssembler::RegisterID valueReg = value.registerID();
    633 
    634         // Store the value to the array.
    635         m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
    636 
    637         noResult(m_compileIndex);
    638         break;
    639     }
    640 
    641     case DFG::Jump: {
    642         BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
    643         if (taken != (m_block + 1))
    644             addBranch(m_jit.jump(), taken);
    645         noResult(m_compileIndex);
    646         break;
    647     }
    648 
    649     case Branch: {
    650         JSValueOperand value(this, node.child1);
    651         MacroAssembler::RegisterID valueReg = value.registerID();
    652 
    653         BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
    654         BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());
    655 
    656         // Integers
    657         addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken);
    658         MacroAssembler::Jump isNonZeroInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueReg, JITCompiler::tagTypeNumberRegister);
    659 
    660         // Booleans
    661         addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken);
    662         speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))));
    663 
    664         if (taken == (m_block + 1))
    665             isNonZeroInteger.link(&m_jit);
    666         else {
    667             addBranch(isNonZeroInteger, taken);
    668             addBranch(m_jit.jump(), taken);
    669         }
    670 
    671         noResult(m_compileIndex);
    672         break;
    673     }
    674 
    675     case Return: {
    676         ASSERT(JITCompiler::callFrameRegister != JITCompiler::regT1);
    677         ASSERT(JITCompiler::regT1 != JITCompiler::returnValueRegister);
    678         ASSERT(JITCompiler::returnValueRegister != JITCompiler::callFrameRegister);
    679 
    680 #if DFG_SUCCESS_STATS
    681         static SamplingCounter counter("SpeculativeJIT");
    682         m_jit.emitCount(counter);
    683 #endif
    684 
    685         // Return the result in returnValueRegister.
    686         JSValueOperand op1(this, node.child1);
    687         m_jit.move(op1.registerID(), JITCompiler::returnValueRegister);
    688 
    689         // Grab the return address.
    690         m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, JITCompiler::regT1);
    691         // Restore our caller's "r".
    692         m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, JITCompiler::callFrameRegister);
    693         // Return.
    694         m_jit.restoreReturnAddressBeforeReturn(JITCompiler::regT1);
    695         m_jit.ret();
    696 
    697         noResult(m_compileIndex);
    698         break;
    699     }
    700 
    701     case ConvertThis: {
    702         SpeculateCellOperand thisValue(this, node.child1);
    703         GPRTemporary temp(this);
    704 
    705         m_jit.loadPtr(JITCompiler::Address(thisValue.registerID(), JSCell::structureOffset()), temp.registerID());
    706         speculationCheck(m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(temp.registerID(), Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(NeedsThisConversion)));
    707 
    708         cellResult(thisValue.gpr(), m_compileIndex);
    709         break;
    710     }
    711 
    712     case GetById: {
    713         JSValueOperand base(this, node.child1);
    714         GPRReg baseGPR = base.gpr();
    715         flushRegisters();
    716 
    717         GPRResult result(this);
    718         callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
    719         jsValueResult(result.gpr(), m_compileIndex);
    720         break;
    721     }
    722 
    723     case PutById: {
    724         JSValueOperand base(this, node.child1);
    725         JSValueOperand value(this, node.child2);
    726         GPRReg valueGPR = value.gpr();
    727         GPRReg baseGPR = base.gpr();
    728         flushRegisters();
    729 
    730         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
    731         noResult(m_compileIndex);
    732         break;
    733     }
    734 
    735     case PutByIdDirect: {
    736         JSValueOperand base(this, node.child1);
    737         JSValueOperand value(this, node.child2);
    738         GPRReg valueGPR = value.gpr();
    739         GPRReg baseGPR = base.gpr();
    740         flushRegisters();
    741 
    742         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
    743         noResult(m_compileIndex);
    744         break;
    745     }
    746 
    747     case GetGlobalVar: {
    748         GPRTemporary result(this);
    749 
    750         JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
    751         m_jit.loadPtr(globalObject->addressOfRegisters(), result.registerID());
    752         m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.registerID(), node.varNumber()), result.registerID());
    753 
    754         jsValueResult(result.gpr(), m_compileIndex);
    755         break;
    756     }
    757 
    758     case PutGlobalVar: {
    759         JSValueOperand value(this, node.child1);
    760         GPRTemporary temp(this);
    761 
    762         JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
    763         m_jit.loadPtr(globalObject->addressOfRegisters(), temp.registerID());
    764         m_jit.storePtr(value.registerID(), JITCompiler::addressForGlobalVar(temp.registerID(), node.varNumber()));
    765 
    766         noResult(m_compileIndex);
    767         break;
    768     }
    769     }
    770 
    771     // Check if generation for the speculative path has failed catastrophically. :-)
    772     // In the future, we may want to throw away the code we've generated in this case.
    773     // For now, there is no point generating any further code, return immediately.
    774     if (m_didTerminate)
    775         return false;
    776 
    777     if (node.mustGenerate())
    778         use(m_compileIndex);
    779 
    780     checkConsistency();
    781 
    782     return true;
    783 }
    784 
    785 bool SpeculativeJIT::compile(BasicBlock& block)
    786 {
    787     ASSERT(m_compileIndex == block.begin);
    788     m_blockHeads[m_block] = m_jit.label();
    789 #if DFG_JIT_BREAK_ON_EVERY_BLOCK
    790     m_jit.breakpoint();
    791 #endif
    792 
    793     for (; m_compileIndex < block.end; ++m_compileIndex) {
    794         Node& node = m_jit.graph()[m_compileIndex];
    795         if (!node.refCount)
    796             continue;
    797 
    798 #if DFG_DEBUG_VERBOSE
    799         fprintf(stderr, "SpeculativeJIT generating Node @%d at JIT offset 0x%x\n", (int)m_compileIndex, m_jit.debugOffset());
    800 #endif
    801 #if DFG_JIT_BREAK_ON_EVERY_NODE
    802     m_jit.breakpoint();
    803 #endif
    804         if (!compile(node))
    805             return false;
    806     }
    807     return true;
    808 }
    809 
    810 bool SpeculativeJIT::compile()
    811 {
    812     ASSERT(!m_compileIndex);
    813     Vector<BasicBlock> blocks = m_jit.graph().m_blocks;
    814     for (m_block = 0; m_block < blocks.size(); ++m_block) {
    815         if (!compile(blocks[m_block]))
    816             return false;
    817     }
    818     linkBranches();
    819     return true;
    820 }
    821 
    822 } } // namespace JSC::DFG
    823 
    824 #endif
    825