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 "DFGByteCodeParser.h"
     28 
     29 #if ENABLE(DFG_JIT)
     30 
     31 #include "DFGAliasTracker.h"
     32 #include "DFGScoreBoard.h"
     33 #include "CodeBlock.h"
     34 
     35 namespace JSC { namespace DFG {
     36 
     37 #if ENABLE(DFG_JIT_RESTRICTIONS)
     38 // FIXME: Temporarily disable arithmetic, until we fix associated performance regressions.
     39 #define ARITHMETIC_OP() m_parseFailed = true
     40 #else
     41 #define ARITHMETIC_OP() ((void)0)
     42 #endif
     43 
     44 // === ByteCodeParser ===
     45 //
     46 // This class is used to compile the dataflow graph from a CodeBlock.
     47 class ByteCodeParser {
     48 public:
     49     ByteCodeParser(JSGlobalData* globalData, CodeBlock* codeBlock, Graph& graph)
     50         : m_globalData(globalData)
     51         , m_codeBlock(codeBlock)
     52         , m_graph(graph)
     53         , m_currentIndex(0)
     54         , m_parseFailed(false)
     55         , m_constantUndefined(UINT_MAX)
     56         , m_constantNull(UINT_MAX)
     57         , m_constant1(UINT_MAX)
     58         , m_constants(codeBlock->numberOfConstantRegisters())
     59         , m_arguments(codeBlock->m_numParameters)
     60         , m_variables(codeBlock->m_numVars)
     61         , m_temporaries(codeBlock->m_numCalleeRegisters - codeBlock->m_numVars)
     62     {
     63         for (unsigned i = 0; i < m_temporaries.size(); ++i)
     64             m_temporaries[i] = NoNode;
     65     }
     66 
     67     // Parse a full CodeBlock of bytecode.
     68     bool parse();
     69 
     70 private:
     71     // Parse a single basic block of bytecode instructions.
     72     bool parseBlock(unsigned limit);
     73 
     74     // Get/Set the operands/result of a bytecode instruction.
     75     NodeIndex get(int operand)
     76     {
     77         // Is this a constant?
     78         if (operand >= FirstConstantRegisterIndex) {
     79             unsigned constant = operand - FirstConstantRegisterIndex;
     80             ASSERT(constant < m_constants.size());
     81             return getJSConstant(constant);
     82         }
     83 
     84         // Is this an argument?
     85         if (operand < 0)
     86             return getArgument(operand);
     87 
     88         // Is this a variable?
     89         unsigned numVariables = m_variables.size();
     90         if ((unsigned)operand < numVariables)
     91             return getVariable((unsigned)operand);
     92 
     93         // Must be a temporary.
     94         unsigned temporary = (unsigned)operand - numVariables;
     95         ASSERT(temporary < m_temporaries.size());
     96         return getTemporary(temporary);
     97     }
     98     void set(int operand, NodeIndex value)
     99     {
    100         // Is this an argument?
    101         if (operand < 0) {
    102             setArgument(operand, value);
    103             return;
    104         }
    105 
    106         // Is this a variable?
    107         unsigned numVariables = m_variables.size();
    108         if ((unsigned)operand < numVariables) {
    109             setVariable((unsigned)operand, value);
    110             return;
    111         }
    112 
    113         // Must be a temporary.
    114         unsigned temporary = (unsigned)operand - numVariables;
    115         ASSERT(temporary < m_temporaries.size());
    116         setTemporary(temporary, value);
    117     }
    118 
    119     // Used in implementing get/set, above, where the operand is a local variable.
    120     NodeIndex getVariable(unsigned operand)
    121     {
    122         NodeIndex setNode = m_variables[operand].set;
    123         if (setNode != NoNode)
    124             return m_graph[setNode].child1;
    125 
    126         NodeIndex getNode = m_variables[operand].get;
    127         if (getNode != NoNode)
    128             return getNode;
    129 
    130         getNode = addToGraph(GetLocal, OpInfo(operand));
    131         m_variables[operand].get = getNode;
    132         return getNode;
    133     }
    134     void setVariable(unsigned operand, NodeIndex value)
    135     {
    136         NodeIndex priorSet = m_variables[operand].set;
    137         m_variables[operand].set = addToGraph(SetLocal, OpInfo(operand), value);
    138         if (priorSet != NoNode)
    139             m_graph.deref(priorSet);
    140     }
    141 
    142     // Used in implementing get/set, above, where the operand is a temporary.
    143     NodeIndex getTemporary(unsigned operand)
    144     {
    145         NodeIndex index = m_temporaries[operand];
    146         if (index != NoNode)
    147             return index;
    148 
    149         // Detect a read of an temporary that is not a yet defined within this block (e.g. use of ?:).
    150         m_parseFailed = true;
    151         return constantUndefined();
    152     }
    153     void setTemporary(unsigned operand, NodeIndex value)
    154     {
    155         m_temporaries[operand] = value;
    156     }
    157 
    158     // Used in implementing get/set, above, where the operand is an argument.
    159     NodeIndex getArgument(unsigned operand)
    160     {
    161         unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
    162         ASSERT(argument < m_arguments.size());
    163 
    164         NodeIndex setNode = m_arguments[argument].set;
    165         if (setNode != NoNode)
    166             return m_graph[setNode].child1;
    167 
    168         NodeIndex getNode = m_arguments[argument].get;
    169         if (getNode != NoNode)
    170             return getNode;
    171 
    172         getNode = addToGraph(GetLocal, OpInfo(operand));
    173         m_arguments[argument].get = getNode;
    174         return getNode;
    175     }
    176     void setArgument(int operand, NodeIndex value)
    177     {
    178         unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
    179         ASSERT(argument < m_arguments.size());
    180 
    181         NodeIndex priorSet = m_arguments[argument].set;
    182         m_arguments[argument].set = addToGraph(SetLocal, OpInfo(operand), value);
    183         if (priorSet != NoNode)
    184             m_graph.deref(priorSet);
    185     }
    186 
    187     // Get an operand, and perform a ToInt32/ToNumber conversion on it.
    188     NodeIndex getToInt32(int operand)
    189     {
    190         // Avoid wastefully adding a JSConstant node to the graph, only to
    191         // replace it with a Int32Constant (which is what would happen if
    192         // we called 'toInt32(get(operand))' in this case).
    193         if (operand >= FirstConstantRegisterIndex) {
    194             JSValue v = m_codeBlock->getConstant(operand);
    195             if (v.isInt32())
    196                 return getInt32Constant(v.asInt32(), operand - FirstConstantRegisterIndex);
    197         }
    198         return toInt32(get(operand));
    199     }
    200     NodeIndex getToNumber(int operand)
    201     {
    202         // Avoid wastefully adding a JSConstant node to the graph, only to
    203         // replace it with a DoubleConstant (which is what would happen if
    204         // we called 'toNumber(get(operand))' in this case).
    205         if (operand >= FirstConstantRegisterIndex) {
    206             JSValue v = m_codeBlock->getConstant(operand);
    207             if (v.isNumber())
    208                 return getDoubleConstant(v.uncheckedGetNumber(), operand - FirstConstantRegisterIndex);
    209         }
    210         return toNumber(get(operand));
    211     }
    212 
    213     // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
    214     NodeIndex toInt32(NodeIndex index)
    215     {
    216         Node& node = m_graph[index];
    217 
    218         if (node.hasInt32Result())
    219             return index;
    220 
    221         if (node.hasDoubleResult()) {
    222             if (node.op == DoubleConstant)
    223                 return getInt32Constant(JSC::toInt32(valueOfDoubleConstant(index)), node.constantNumber());
    224             // 'NumberToInt32(Int32ToNumber(X))' == X, and 'NumberToInt32(UInt32ToNumber(X)) == X'
    225             if (node.op == Int32ToNumber || node.op == UInt32ToNumber)
    226                 return node.child1;
    227 
    228             // We unique NumberToInt32 nodes in a map to prevent duplicate conversions.
    229             pair<UnaryOpMap::iterator, bool> result = m_numberToInt32Nodes.add(index, NoNode);
    230             // Either we added a new value, or the existing value in the map is non-zero.
    231             ASSERT(result.second == (result.first->second == NoNode));
    232             if (result.second)
    233                 result.first->second = addToGraph(NumberToInt32, index);
    234             return result.first->second;
    235         }
    236 
    237         // Check for numeric constants boxed as JSValues.
    238         if (node.op == JSConstant) {
    239             JSValue v = valueOfJSConstant(index);
    240             if (v.isInt32())
    241                 return getInt32Constant(v.asInt32(), node.constantNumber());
    242             if (v.isNumber())
    243                 return getInt32Constant(JSC::toInt32(v.uncheckedGetNumber()), node.constantNumber());
    244         }
    245 
    246         return addToGraph(ValueToInt32, index);
    247     }
    248 
    249     // Perform an ES5 ToNumber operation - returns a node of type NodeResultDouble.
    250     NodeIndex toNumber(NodeIndex index)
    251     {
    252         Node& node = m_graph[index];
    253 
    254         if (node.hasDoubleResult())
    255             return index;
    256 
    257         if (node.hasInt32Result()) {
    258             if (node.op == Int32Constant)
    259                 return getDoubleConstant(valueOfInt32Constant(index), node.constantNumber());
    260 
    261             // We unique Int32ToNumber nodes in a map to prevent duplicate conversions.
    262             pair<UnaryOpMap::iterator, bool> result = m_int32ToNumberNodes.add(index, NoNode);
    263             // Either we added a new value, or the existing value in the map is non-zero.
    264             ASSERT(result.second == (result.first->second == NoNode));
    265             if (result.second)
    266                 result.first->second = addToGraph(Int32ToNumber, index);
    267             return result.first->second;
    268         }
    269 
    270         if (node.op == JSConstant) {
    271             JSValue v = valueOfJSConstant(index);
    272             if (v.isNumber())
    273                 return getDoubleConstant(v.uncheckedGetNumber(), node.constantNumber());
    274         }
    275 
    276         return addToGraph(ValueToNumber, index);
    277     }
    278 
    279 
    280     // Used in implementing get, above, where the operand is a constant.
    281     NodeIndex getInt32Constant(int32_t value, unsigned constant)
    282     {
    283         NodeIndex index = m_constants[constant].asInt32;
    284         if (index != NoNode)
    285             return index;
    286         NodeIndex resultIndex = addToGraph(Int32Constant, OpInfo(constant));
    287         m_graph[resultIndex].setInt32Constant(value);
    288         m_constants[constant].asInt32 = resultIndex;
    289         return resultIndex;
    290     }
    291     NodeIndex getDoubleConstant(double value, unsigned constant)
    292     {
    293         NodeIndex index = m_constants[constant].asNumeric;
    294         if (index != NoNode)
    295             return index;
    296         NodeIndex resultIndex = addToGraph(DoubleConstant, OpInfo(constant));
    297         m_graph[resultIndex].setDoubleConstant(value);
    298         m_constants[constant].asNumeric = resultIndex;
    299         return resultIndex;
    300     }
    301     NodeIndex getJSConstant(unsigned constant)
    302     {
    303         NodeIndex index = m_constants[constant].asJSValue;
    304         if (index != NoNode)
    305             return index;
    306 
    307         NodeIndex resultIndex = addToGraph(JSConstant, OpInfo(constant));
    308         m_constants[constant].asJSValue = resultIndex;
    309         return resultIndex;
    310     }
    311 
    312     // Helper functions to get/set the this value.
    313     NodeIndex getThis()
    314     {
    315         return getArgument(m_codeBlock->thisRegister());
    316     }
    317     void setThis(NodeIndex value)
    318     {
    319         setArgument(m_codeBlock->thisRegister(), value);
    320     }
    321 
    322     // Convenience methods for checking nodes for constants.
    323     bool isInt32Constant(NodeIndex index)
    324     {
    325         return m_graph[index].op == Int32Constant;
    326     }
    327     bool isDoubleConstant(NodeIndex index)
    328     {
    329         return m_graph[index].op == DoubleConstant;
    330     }
    331     bool isJSConstant(NodeIndex index)
    332     {
    333         return m_graph[index].op == JSConstant;
    334     }
    335 
    336     // Convenience methods for getting constant values.
    337     int32_t valueOfInt32Constant(NodeIndex index)
    338     {
    339         ASSERT(isInt32Constant(index));
    340         return m_graph[index].int32Constant();
    341     }
    342     double valueOfDoubleConstant(NodeIndex index)
    343     {
    344         ASSERT(isDoubleConstant(index));
    345         return m_graph[index].numericConstant();
    346     }
    347     JSValue valueOfJSConstant(NodeIndex index)
    348     {
    349         ASSERT(isJSConstant(index));
    350         return m_codeBlock->getConstant(FirstConstantRegisterIndex + m_graph[index].constantNumber());
    351     }
    352 
    353     // This method returns a JSConstant with the value 'undefined'.
    354     NodeIndex constantUndefined()
    355     {
    356         // Has m_constantUndefined been set up yet?
    357         if (m_constantUndefined == UINT_MAX) {
    358             // Search the constant pool for undefined, if we find it, we can just reuse this!
    359             unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
    360             for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) {
    361                 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined);
    362                 if (testMe.isUndefined())
    363                     return getJSConstant(m_constantUndefined);
    364             }
    365 
    366             // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants.
    367             ASSERT(m_constants.size() == numberOfConstants);
    368             m_codeBlock->addConstant(jsUndefined());
    369             m_constants.append(ConstantRecord());
    370             ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
    371         }
    372 
    373         // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'.
    374         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined());
    375         return getJSConstant(m_constantUndefined);
    376     }
    377 
    378     // This method returns a JSConstant with the value 'null'.
    379     NodeIndex constantNull()
    380     {
    381         // Has m_constantNull been set up yet?
    382         if (m_constantNull == UINT_MAX) {
    383             // Search the constant pool for null, if we find it, we can just reuse this!
    384             unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
    385             for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) {
    386                 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull);
    387                 if (testMe.isNull())
    388                     return getJSConstant(m_constantNull);
    389             }
    390 
    391             // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants.
    392             ASSERT(m_constants.size() == numberOfConstants);
    393             m_codeBlock->addConstant(jsNull());
    394             m_constants.append(ConstantRecord());
    395             ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
    396         }
    397 
    398         // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'.
    399         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull());
    400         return getJSConstant(m_constantNull);
    401     }
    402 
    403     // This method returns a DoubleConstant with the value 1.
    404     NodeIndex one()
    405     {
    406         // Has m_constant1 been set up yet?
    407         if (m_constant1 == UINT_MAX) {
    408             // Search the constant pool for the value 1, if we find it, we can just reuse this!
    409             unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
    410             for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) {
    411                 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1);
    412                 if (testMe.isInt32() && testMe.asInt32() == 1)
    413                     return getDoubleConstant(1, m_constant1);
    414             }
    415 
    416             // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants.
    417             ASSERT(m_constants.size() == numberOfConstants);
    418             m_codeBlock->addConstant(jsNumber(1));
    419             m_constants.append(ConstantRecord());
    420             ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
    421         }
    422 
    423         // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1.
    424         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32());
    425         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1);
    426         return getDoubleConstant(1, m_constant1);
    427     }
    428 
    429 
    430     // These methods create a node and add it to the graph. If nodes of this type are
    431     // 'mustGenerate' then the node  will implicitly be ref'ed to ensure generation.
    432     NodeIndex addToGraph(NodeType op, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
    433     {
    434         NodeIndex resultIndex = (NodeIndex)m_graph.size();
    435         m_graph.append(Node(op, m_currentIndex, child1, child2, child3));
    436 
    437         if (op & NodeMustGenerate)
    438             m_graph.ref(resultIndex);
    439         return resultIndex;
    440     }
    441     NodeIndex addToGraph(NodeType op, OpInfo info, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
    442     {
    443         NodeIndex resultIndex = (NodeIndex)m_graph.size();
    444         m_graph.append(Node(op, m_currentIndex, info, child1, child2, child3));
    445 
    446         if (op & NodeMustGenerate)
    447             m_graph.ref(resultIndex);
    448         return resultIndex;
    449     }
    450     NodeIndex addToGraph(NodeType op, OpInfo info1, OpInfo info2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
    451     {
    452         NodeIndex resultIndex = (NodeIndex)m_graph.size();
    453         m_graph.append(Node(op, m_currentIndex, info1, info2, child1, child2, child3));
    454 
    455         if (op & NodeMustGenerate)
    456             m_graph.ref(resultIndex);
    457         return resultIndex;
    458     }
    459 
    460     JSGlobalData* m_globalData;
    461     CodeBlock* m_codeBlock;
    462     Graph& m_graph;
    463 
    464     // The bytecode index of the current instruction being generated.
    465     unsigned m_currentIndex;
    466 
    467     // Record failures due to unimplemented functionality or regressions.
    468     bool m_parseFailed;
    469 
    470     // We use these values during code generation, and to avoid the need for
    471     // special handling we make sure they are available as constants in the
    472     // CodeBlock's constant pool. These variables are initialized to
    473     // UINT_MAX, and lazily updated to hold an index into the CodeBlock's
    474     // constant pool, as necessary.
    475     unsigned m_constantUndefined;
    476     unsigned m_constantNull;
    477     unsigned m_constant1;
    478 
    479     // A constant in the constant pool may be represented by more than one
    480     // node in the graph, depending on the context in which it is being used.
    481     struct ConstantRecord {
    482         ConstantRecord()
    483             : asInt32(NoNode)
    484             , asNumeric(NoNode)
    485             , asJSValue(NoNode)
    486         {
    487         }
    488 
    489         NodeIndex asInt32;
    490         NodeIndex asNumeric;
    491         NodeIndex asJSValue;
    492     };
    493 
    494     // For every local variable we track any existing get or set of the value.
    495     // We track the get so that these may be shared, and we track the set to
    496     // retrieve the current value, and to reference the final definition.
    497     struct VariableRecord {
    498         VariableRecord()
    499             : get(NoNode)
    500             , set(NoNode)
    501         {
    502         }
    503 
    504         NodeIndex get;
    505         NodeIndex set;
    506     };
    507 
    508     // Track the index of the node whose result is the current value for every
    509     // register value in the bytecode - argument, local, and temporary.
    510     Vector <ConstantRecord, 32> m_constants;
    511     Vector <VariableRecord, 32> m_arguments;
    512     Vector <VariableRecord, 32> m_variables;
    513     Vector <NodeIndex, 32> m_temporaries;
    514 
    515     // These maps are used to unique ToNumber and ToInt32 operations.
    516     typedef HashMap<NodeIndex, NodeIndex> UnaryOpMap;
    517     UnaryOpMap m_int32ToNumberNodes;
    518     UnaryOpMap m_numberToInt32Nodes;
    519 };
    520 
    521 #define NEXT_OPCODE(name) \
    522     m_currentIndex += OPCODE_LENGTH(name); \
    523     continue
    524 
    525 #define LAST_OPCODE(name) \
    526     m_currentIndex += OPCODE_LENGTH(name); \
    527     return !m_parseFailed
    528 
    529 bool ByteCodeParser::parseBlock(unsigned limit)
    530 {
    531     // No need to reset state initially, since it has been set by the constructor.
    532     if (m_currentIndex) {
    533         for (unsigned i = 0; i < m_constants.size(); ++i)
    534             m_constants[i] = ConstantRecord();
    535         for (unsigned i = 0; i < m_variables.size(); ++i)
    536             m_variables[i] = VariableRecord();
    537         for (unsigned i = 0; i < m_arguments.size(); ++i)
    538             m_arguments[i] = VariableRecord();
    539         for (unsigned i = 0; i < m_temporaries.size(); ++i)
    540             m_temporaries[i] = NoNode;
    541     }
    542 
    543     AliasTracker aliases(m_graph);
    544 
    545     Interpreter* interpreter = m_globalData->interpreter;
    546     Instruction* instructionsBegin = m_codeBlock->instructions().begin();
    547     while (true) {
    548         // Don't extend over jump destinations.
    549         if (m_currentIndex == limit) {
    550             addToGraph(Jump, OpInfo(m_currentIndex));
    551             return !m_parseFailed;
    552         }
    553 
    554         // Switch on the current bytecode opcode.
    555         Instruction* currentInstruction = instructionsBegin + m_currentIndex;
    556         switch (interpreter->getOpcodeID(currentInstruction->u.opcode)) {
    557 
    558         // === Function entry opcodes ===
    559 
    560         case op_enter:
    561             // Initialize all locals to undefined.
    562             for (int i = 0; i < m_codeBlock->m_numVars; ++i)
    563                 set(i, constantUndefined());
    564             NEXT_OPCODE(op_enter);
    565 
    566         case op_convert_this: {
    567             NodeIndex op1 = getThis();
    568             setThis(addToGraph(ConvertThis, op1));
    569             NEXT_OPCODE(op_convert_this);
    570         }
    571 
    572         // === Bitwise operations ===
    573 
    574         case op_bitand: {
    575             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    576             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    577             set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2));
    578             NEXT_OPCODE(op_bitand);
    579         }
    580 
    581         case op_bitor: {
    582             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    583             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    584             set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2));
    585             NEXT_OPCODE(op_bitor);
    586         }
    587 
    588         case op_bitxor: {
    589             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    590             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    591             set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2));
    592             NEXT_OPCODE(op_bitxor);
    593         }
    594 
    595         case op_rshift: {
    596             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    597             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    598             NodeIndex result;
    599             // Optimize out shifts by zero.
    600             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
    601                 result = op1;
    602             else
    603                 result = addToGraph(BitRShift, op1, op2);
    604             set(currentInstruction[1].u.operand, result);
    605             NEXT_OPCODE(op_rshift);
    606         }
    607 
    608         case op_lshift: {
    609             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    610             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    611             NodeIndex result;
    612             // Optimize out shifts by zero.
    613             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
    614                 result = op1;
    615             else
    616                 result = addToGraph(BitLShift, op1, op2);
    617             set(currentInstruction[1].u.operand, result);
    618             NEXT_OPCODE(op_lshift);
    619         }
    620 
    621         case op_urshift: {
    622             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
    623             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
    624             NodeIndex result;
    625             // The result of a zero-extending right shift is treated as an unsigned value.
    626             // This means that if the top bit is set, the result is not in the int32 range,
    627             // and as such must be stored as a double. If the shift amount is a constant,
    628             // we may be able to optimize.
    629             if (isInt32Constant(op2)) {
    630                 // If we know we are shifting by a non-zero amount, then since the operation
    631                 // zero fills we know the top bit of the result must be zero, and as such the
    632                 // result must be within the int32 range. Conversely, if this is a shift by
    633                 // zero, then the result may be changed by the conversion to unsigned, but it
    634                 // is not necessary to perform the shift!
    635                 if (valueOfInt32Constant(op2) & 0x1f)
    636                     result = addToGraph(BitURShift, op1, op2);
    637                 else
    638                     result = addToGraph(UInt32ToNumber, op1);
    639             }  else {
    640                 // Cannot optimize at this stage; shift & potentially rebox as a double.
    641                 result = addToGraph(BitURShift, op1, op2);
    642                 result = addToGraph(UInt32ToNumber, result);
    643             }
    644             set(currentInstruction[1].u.operand, result);
    645             NEXT_OPCODE(op_urshift);
    646         }
    647 
    648         // === Increment/Decrement opcodes ===
    649 
    650         case op_pre_inc: {
    651             unsigned srcDst = currentInstruction[1].u.operand;
    652             NodeIndex op = getToNumber(srcDst);
    653             set(srcDst, addToGraph(ArithAdd, op, one()));
    654             NEXT_OPCODE(op_pre_inc);
    655         }
    656 
    657         case op_post_inc: {
    658             unsigned result = currentInstruction[1].u.operand;
    659             unsigned srcDst = currentInstruction[2].u.operand;
    660             NodeIndex op = getToNumber(srcDst);
    661             set(result, op);
    662             set(srcDst, addToGraph(ArithAdd, op, one()));
    663             NEXT_OPCODE(op_post_inc);
    664         }
    665 
    666         case op_pre_dec: {
    667             unsigned srcDst = currentInstruction[1].u.operand;
    668             NodeIndex op = getToNumber(srcDst);
    669             set(srcDst, addToGraph(ArithSub, op, one()));
    670             NEXT_OPCODE(op_pre_dec);
    671         }
    672 
    673         case op_post_dec: {
    674             unsigned result = currentInstruction[1].u.operand;
    675             unsigned srcDst = currentInstruction[2].u.operand;
    676             NodeIndex op = getToNumber(srcDst);
    677             set(result, op);
    678             set(srcDst, addToGraph(ArithSub, op, one()));
    679             NEXT_OPCODE(op_post_dec);
    680         }
    681 
    682         // === Arithmetic operations ===
    683 
    684         case op_add: {
    685             ARITHMETIC_OP();
    686             NodeIndex op1 = get(currentInstruction[2].u.operand);
    687             NodeIndex op2 = get(currentInstruction[3].u.operand);
    688             // If both operands can statically be determined to the numbers, then this is an arithmetic add.
    689             // Otherwise, we must assume this may be performing a concatenation to a string.
    690             if (m_graph[op1].hasNumericResult() && m_graph[op2].hasNumericResult())
    691                 set(currentInstruction[1].u.operand, addToGraph(ArithAdd, toNumber(op1), toNumber(op2)));
    692             else
    693                 set(currentInstruction[1].u.operand, addToGraph(ValueAdd, op1, op2));
    694             NEXT_OPCODE(op_add);
    695         }
    696 
    697         case op_sub: {
    698             ARITHMETIC_OP();
    699             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
    700             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
    701             set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
    702             NEXT_OPCODE(op_sub);
    703         }
    704 
    705         case op_mul: {
    706             ARITHMETIC_OP();
    707             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
    708             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
    709             set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2));
    710             NEXT_OPCODE(op_mul);
    711         }
    712 
    713         case op_mod: {
    714             ARITHMETIC_OP();
    715             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
    716             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
    717             set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2));
    718             NEXT_OPCODE(op_mod);
    719         }
    720 
    721         case op_div: {
    722             ARITHMETIC_OP();
    723             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
    724             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
    725             set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2));
    726             NEXT_OPCODE(op_div);
    727         }
    728 
    729         // === Misc operations ===
    730 
    731         case op_mov: {
    732             NodeIndex op = get(currentInstruction[2].u.operand);
    733             set(currentInstruction[1].u.operand, op);
    734             NEXT_OPCODE(op_mov);
    735         }
    736 
    737         case op_not: {
    738             ARITHMETIC_OP();
    739             NodeIndex value = get(currentInstruction[2].u.operand);
    740             set(currentInstruction[1].u.operand, addToGraph(LogicalNot, value));
    741             NEXT_OPCODE(op_not);
    742         }
    743 
    744         case op_less: {
    745             ARITHMETIC_OP();
    746             NodeIndex op1 = get(currentInstruction[2].u.operand);
    747             NodeIndex op2 = get(currentInstruction[3].u.operand);
    748             set(currentInstruction[1].u.operand, addToGraph(CompareLess, op1, op2));
    749             NEXT_OPCODE(op_less);
    750         }
    751 
    752         case op_lesseq: {
    753             ARITHMETIC_OP();
    754             NodeIndex op1 = get(currentInstruction[2].u.operand);
    755             NodeIndex op2 = get(currentInstruction[3].u.operand);
    756             set(currentInstruction[1].u.operand, addToGraph(CompareLessEq, op1, op2));
    757             NEXT_OPCODE(op_lesseq);
    758         }
    759 
    760         case op_eq: {
    761             ARITHMETIC_OP();
    762             NodeIndex op1 = get(currentInstruction[2].u.operand);
    763             NodeIndex op2 = get(currentInstruction[3].u.operand);
    764             set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2));
    765             NEXT_OPCODE(op_eq);
    766         }
    767 
    768         case op_eq_null: {
    769             ARITHMETIC_OP();
    770             NodeIndex value = get(currentInstruction[2].u.operand);
    771             set(currentInstruction[1].u.operand, addToGraph(CompareEq, value, constantNull()));
    772             NEXT_OPCODE(op_eq_null);
    773         }
    774 
    775         case op_stricteq: {
    776             ARITHMETIC_OP();
    777             NodeIndex op1 = get(currentInstruction[2].u.operand);
    778             NodeIndex op2 = get(currentInstruction[3].u.operand);
    779             set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2));
    780             NEXT_OPCODE(op_stricteq);
    781         }
    782 
    783         case op_neq: {
    784             ARITHMETIC_OP();
    785             NodeIndex op1 = get(currentInstruction[2].u.operand);
    786             NodeIndex op2 = get(currentInstruction[3].u.operand);
    787             set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2)));
    788             NEXT_OPCODE(op_neq);
    789         }
    790 
    791         case op_neq_null: {
    792             ARITHMETIC_OP();
    793             NodeIndex value = get(currentInstruction[2].u.operand);
    794             set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, value, constantNull())));
    795             NEXT_OPCODE(op_neq_null);
    796         }
    797 
    798         case op_nstricteq: {
    799             ARITHMETIC_OP();
    800             NodeIndex op1 = get(currentInstruction[2].u.operand);
    801             NodeIndex op2 = get(currentInstruction[3].u.operand);
    802             set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2)));
    803             NEXT_OPCODE(op_nstricteq);
    804         }
    805 
    806         // === Property access operations ===
    807 
    808         case op_get_by_val: {
    809             NodeIndex base = get(currentInstruction[2].u.operand);
    810             NodeIndex property = get(currentInstruction[3].u.operand);
    811 
    812             NodeIndex getByVal = addToGraph(GetByVal, base, property, aliases.lookupGetByVal(base, property));
    813             set(currentInstruction[1].u.operand, getByVal);
    814             aliases.recordGetByVal(getByVal);
    815 
    816             NEXT_OPCODE(op_get_by_val);
    817         }
    818 
    819         case op_put_by_val: {
    820             NodeIndex base = get(currentInstruction[1].u.operand);
    821             NodeIndex property = get(currentInstruction[2].u.operand);
    822             NodeIndex value = get(currentInstruction[3].u.operand);
    823 
    824             NodeIndex aliasedGet = aliases.lookupGetByVal(base, property);
    825             NodeIndex putByVal = addToGraph(aliasedGet != NoNode ? PutByValAlias : PutByVal, base, property, value);
    826             aliases.recordPutByVal(putByVal);
    827 
    828             NEXT_OPCODE(op_put_by_val);
    829         }
    830 
    831         case op_get_by_id: {
    832             NodeIndex base = get(currentInstruction[2].u.operand);
    833             unsigned identifier = currentInstruction[3].u.operand;
    834 
    835             NodeIndex getById = addToGraph(GetById, OpInfo(identifier), base);
    836             set(currentInstruction[1].u.operand, getById);
    837             aliases.recordGetById(getById);
    838 
    839             NEXT_OPCODE(op_get_by_id);
    840         }
    841 
    842         case op_put_by_id: {
    843             NodeIndex value = get(currentInstruction[3].u.operand);
    844             NodeIndex base = get(currentInstruction[1].u.operand);
    845             unsigned identifier = currentInstruction[2].u.operand;
    846             bool direct = currentInstruction[8].u.operand;
    847 
    848             if (direct) {
    849                 NodeIndex putByIdDirect = addToGraph(PutByIdDirect, OpInfo(identifier), base, value);
    850                 aliases.recordPutByIdDirect(putByIdDirect);
    851             } else {
    852                 NodeIndex putById = addToGraph(PutById, OpInfo(identifier), base, value);
    853                 aliases.recordPutById(putById);
    854             }
    855 
    856             NEXT_OPCODE(op_put_by_id);
    857         }
    858 
    859         case op_get_global_var: {
    860             NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand));
    861             set(currentInstruction[1].u.operand, getGlobalVar);
    862             NEXT_OPCODE(op_get_global_var);
    863         }
    864 
    865         case op_put_global_var: {
    866             NodeIndex value = get(currentInstruction[2].u.operand);
    867             addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value);
    868             NEXT_OPCODE(op_put_global_var);
    869         }
    870 
    871         // === Block terminators. ===
    872 
    873         case op_jmp: {
    874             unsigned relativeOffset = currentInstruction[1].u.operand;
    875             addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
    876             LAST_OPCODE(op_jmp);
    877         }
    878 
    879         case op_loop: {
    880             unsigned relativeOffset = currentInstruction[1].u.operand;
    881             addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
    882             LAST_OPCODE(op_loop);
    883         }
    884 
    885         case op_jtrue: {
    886             unsigned relativeOffset = currentInstruction[2].u.operand;
    887             NodeIndex condition = get(currentInstruction[1].u.operand);
    888             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jtrue)), condition);
    889             LAST_OPCODE(op_jtrue);
    890         }
    891 
    892         case op_jfalse: {
    893             unsigned relativeOffset = currentInstruction[2].u.operand;
    894             NodeIndex condition = get(currentInstruction[1].u.operand);
    895             addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jfalse)), OpInfo(m_currentIndex + relativeOffset), condition);
    896             LAST_OPCODE(op_jfalse);
    897         }
    898 
    899         case op_loop_if_true: {
    900             unsigned relativeOffset = currentInstruction[2].u.operand;
    901             NodeIndex condition = get(currentInstruction[1].u.operand);
    902             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_true)), condition);
    903             LAST_OPCODE(op_loop_if_true);
    904         }
    905 
    906         case op_loop_if_false: {
    907             unsigned relativeOffset = currentInstruction[2].u.operand;
    908             NodeIndex condition = get(currentInstruction[1].u.operand);
    909             addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_false)), OpInfo(m_currentIndex + relativeOffset), condition);
    910             LAST_OPCODE(op_loop_if_false);
    911         }
    912 
    913         case op_jeq_null: {
    914             unsigned relativeOffset = currentInstruction[2].u.operand;
    915             NodeIndex value = get(currentInstruction[1].u.operand);
    916             NodeIndex condition = addToGraph(CompareEq, value, constantNull());
    917             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jeq_null)), condition);
    918             LAST_OPCODE(op_jeq_null);
    919         }
    920 
    921         case op_jneq_null: {
    922             unsigned relativeOffset = currentInstruction[2].u.operand;
    923             NodeIndex value = get(currentInstruction[1].u.operand);
    924             NodeIndex condition = addToGraph(CompareEq, value, constantNull());
    925             addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_null)), OpInfo(m_currentIndex + relativeOffset), condition);
    926             LAST_OPCODE(op_jneq_null);
    927         }
    928 
    929         case op_jnless: {
    930             unsigned relativeOffset = currentInstruction[3].u.operand;
    931             NodeIndex op1 = get(currentInstruction[1].u.operand);
    932             NodeIndex op2 = get(currentInstruction[2].u.operand);
    933             NodeIndex condition = addToGraph(CompareLess, op1, op2);
    934             addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnless)), OpInfo(m_currentIndex + relativeOffset), condition);
    935             LAST_OPCODE(op_jnless);
    936         }
    937 
    938         case op_jnlesseq: {
    939             unsigned relativeOffset = currentInstruction[3].u.operand;
    940             NodeIndex op1 = get(currentInstruction[1].u.operand);
    941             NodeIndex op2 = get(currentInstruction[2].u.operand);
    942             NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
    943             addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnlesseq)), OpInfo(m_currentIndex + relativeOffset), condition);
    944             LAST_OPCODE(op_jnlesseq);
    945         }
    946 
    947         case op_jless: {
    948             unsigned relativeOffset = currentInstruction[3].u.operand;
    949             NodeIndex op1 = get(currentInstruction[1].u.operand);
    950             NodeIndex op2 = get(currentInstruction[2].u.operand);
    951             NodeIndex condition = addToGraph(CompareLess, op1, op2);
    952             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jless)), condition);
    953             LAST_OPCODE(op_jless);
    954         }
    955 
    956         case op_jlesseq: {
    957             unsigned relativeOffset = currentInstruction[3].u.operand;
    958             NodeIndex op1 = get(currentInstruction[1].u.operand);
    959             NodeIndex op2 = get(currentInstruction[2].u.operand);
    960             NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
    961             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jlesseq)), condition);
    962             LAST_OPCODE(op_jlesseq);
    963         }
    964 
    965         case op_loop_if_less: {
    966             unsigned relativeOffset = currentInstruction[3].u.operand;
    967             NodeIndex op1 = get(currentInstruction[1].u.operand);
    968             NodeIndex op2 = get(currentInstruction[2].u.operand);
    969             NodeIndex condition = addToGraph(CompareLess, op1, op2);
    970             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_less)), condition);
    971             LAST_OPCODE(op_loop_if_less);
    972         }
    973 
    974         case op_loop_if_lesseq: {
    975             unsigned relativeOffset = currentInstruction[3].u.operand;
    976             NodeIndex op1 = get(currentInstruction[1].u.operand);
    977             NodeIndex op2 = get(currentInstruction[2].u.operand);
    978             NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
    979             addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_lesseq)), condition);
    980             LAST_OPCODE(op_loop_if_lesseq);
    981         }
    982 
    983         case op_ret: {
    984             addToGraph(Return, get(currentInstruction[1].u.operand));
    985 
    986             // FIXME: throw away terminal definitions of variables;
    987             // should not be necessary once we have proper DCE!
    988             for (unsigned i = 0; i < m_variables.size(); ++i) {
    989                 NodeIndex priorSet = m_variables[i].set;
    990                 if (priorSet != NoNode)
    991                     m_graph.deref(priorSet);
    992             }
    993 
    994             LAST_OPCODE(op_ret);
    995         }
    996 
    997         default:
    998             // Parse failed!
    999             return false;
   1000         }
   1001     }
   1002 }
   1003 
   1004 bool ByteCodeParser::parse()
   1005 {
   1006     // Set during construction.
   1007     ASSERT(!m_currentIndex);
   1008 
   1009     for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= m_codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) {
   1010         // The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions.
   1011         unsigned limit = jumpTargetIndex < m_codeBlock->numberOfJumpTargets() ? m_codeBlock->jumpTarget(jumpTargetIndex) : m_codeBlock->instructions().size();
   1012         ASSERT(m_currentIndex < limit);
   1013 
   1014         // Loop until we reach the current limit (i.e. next jump target).
   1015         do {
   1016             unsigned bytecodeBegin = m_currentIndex;
   1017             NodeIndex begin = m_graph.size();
   1018 
   1019             if (!parseBlock(limit))
   1020                 return false;
   1021             // We should not have gone beyond the limit.
   1022             ASSERT(m_currentIndex <= limit);
   1023 
   1024             NodeIndex end = m_graph.size();
   1025             m_graph.m_blocks.append(BasicBlock(bytecodeBegin, begin, end));
   1026         } while (m_currentIndex < limit);
   1027     }
   1028 
   1029     // Should have reached the end of the instructions.
   1030     ASSERT(m_currentIndex == m_codeBlock->instructions().size());
   1031 
   1032     // Assign VirtualRegisters.
   1033     ScoreBoard scoreBoard(m_graph, m_variables.size());
   1034     Node* nodes = m_graph.begin();
   1035     size_t size = m_graph.size();
   1036     for (size_t i = 0; i < size; ++i) {
   1037         Node& node = nodes[i];
   1038         if (node.refCount) {
   1039             // First, call use on all of the current node's children, then
   1040             // allocate a VirtualRegister for this node. We do so in this
   1041             // order so that if a child is on its last use, and a
   1042             // VirtualRegister is freed, then it may be reused for node.
   1043             scoreBoard.use(node.child1);
   1044             scoreBoard.use(node.child2);
   1045             scoreBoard.use(node.child3);
   1046             node.virtualRegister = scoreBoard.allocate();
   1047             // 'mustGenerate' nodes have their useCount artificially elevated,
   1048             // call use now to account for this.
   1049             if (node.mustGenerate())
   1050                 scoreBoard.use(i);
   1051         }
   1052     }
   1053 
   1054     // 'm_numCalleeRegisters' is the number of locals and temporaries allocated
   1055     // for the function (and checked for on entry). Since we perform a new and
   1056     // different allocation of temporaries, more registers may now be required.
   1057     unsigned calleeRegisters = scoreBoard.allocatedCount() + m_variables.size();
   1058     if ((unsigned)m_codeBlock->m_numCalleeRegisters < calleeRegisters)
   1059         m_codeBlock->m_numCalleeRegisters = calleeRegisters;
   1060 
   1061 #if DFG_DEBUG_VERBOSE
   1062     m_graph.dump(m_codeBlock);
   1063 #endif
   1064 
   1065     return true;
   1066 }
   1067 
   1068 bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock)
   1069 {
   1070 #if DFG_DEBUG_LOCAL_DISBALE
   1071     UNUSED_PARAM(graph);
   1072     UNUSED_PARAM(globalData);
   1073     UNUSED_PARAM(codeBlock);
   1074     return false;
   1075 #else
   1076     return ByteCodeParser(globalData, codeBlock, graph).parse();
   1077 #endif
   1078 }
   1079 
   1080 } } // namespace JSC::DFG
   1081 
   1082 #endif
   1083