diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 546 |
1 files changed, 442 insertions, 104 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 03f5d4f..1d4c36a 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -34,6 +34,13 @@ namespace JSC { namespace DFG { +#if ENABLE(DFG_JIT_RESTRICTIONS) +// FIXME: Temporarily disable arithmetic, until we fix associated performance regressions. +#define ARITHMETIC_OP() m_parseFailed = true +#else +#define ARITHMETIC_OP() ((void)0) +#endif + // === ByteCodeParser === // // This class is used to compile the dataflow graph from a CodeBlock. @@ -44,93 +51,137 @@ public: , m_codeBlock(codeBlock) , m_graph(graph) , m_currentIndex(0) - , m_noArithmetic(true) + , m_parseFailed(false) , m_constantUndefined(UINT_MAX) + , m_constantNull(UINT_MAX) , m_constant1(UINT_MAX) + , m_constants(codeBlock->numberOfConstantRegisters()) + , m_arguments(codeBlock->m_numParameters) + , m_variables(codeBlock->m_numVars) + , m_temporaries(codeBlock->m_numCalleeRegisters - codeBlock->m_numVars) { - unsigned numberOfConstants = codeBlock->numberOfConstantRegisters(); - m_constantRecords.grow(numberOfConstants); - - unsigned numberOfParameters = codeBlock->m_numParameters; - m_arguments.grow(numberOfParameters); - for (unsigned i = 0; i < numberOfParameters; ++i) - m_arguments[i] = NoNode; - - unsigned numberOfRegisters = codeBlock->m_numCalleeRegisters; - m_calleeRegisters.grow(numberOfRegisters); - for (unsigned i = 0; i < numberOfRegisters; ++i) - m_calleeRegisters[i] = NoNode; + for (unsigned i = 0; i < m_temporaries.size(); ++i) + m_temporaries[i] = NoNode; } + // Parse a full CodeBlock of bytecode. bool parse(); private: + // Parse a single basic block of bytecode instructions. + bool parseBlock(unsigned limit); + // Get/Set the operands/result of a bytecode instruction. NodeIndex get(int operand) { // Is this a constant? if (operand >= FirstConstantRegisterIndex) { unsigned constant = operand - FirstConstantRegisterIndex; - ASSERT(constant < m_constantRecords.size()); + ASSERT(constant < m_constants.size()); return getJSConstant(constant); } // Is this an argument? - if (operand < 0) { - unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize; - ASSERT(argument < m_arguments.size()); - return getArgument(argument); - } - - // Must be a local or temporary. - ASSERT((unsigned)operand < m_calleeRegisters.size()); - return getRegister((unsigned)operand); + if (operand < 0) + return getArgument(operand); + + // Is this a variable? + unsigned numVariables = m_variables.size(); + if ((unsigned)operand < numVariables) + return getVariable((unsigned)operand); + + // Must be a temporary. + unsigned temporary = (unsigned)operand - numVariables; + ASSERT(temporary < m_temporaries.size()); + return getTemporary(temporary); } void set(int operand, NodeIndex value) { // Is this an argument? if (operand < 0) { - unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize; - ASSERT(argument < m_arguments.size()); - return setArgument(argument, value); + setArgument(operand, value); + return; + } + + // Is this a variable? + unsigned numVariables = m_variables.size(); + if ((unsigned)operand < numVariables) { + setVariable((unsigned)operand, value); + return; } + + // Must be a temporary. + unsigned temporary = (unsigned)operand - numVariables; + ASSERT(temporary < m_temporaries.size()); + setTemporary(temporary, value); + } - // Must be a local or temporary. - ASSERT((unsigned)operand < m_calleeRegisters.size()); - return setRegister((unsigned)operand, value); + // Used in implementing get/set, above, where the operand is a local variable. + NodeIndex getVariable(unsigned operand) + { + NodeIndex setNode = m_variables[operand].set; + if (setNode != NoNode) + return m_graph[setNode].child1; + + NodeIndex getNode = m_variables[operand].get; + if (getNode != NoNode) + return getNode; + + getNode = addToGraph(GetLocal, OpInfo(operand)); + m_variables[operand].get = getNode; + return getNode; + } + void setVariable(unsigned operand, NodeIndex value) + { + NodeIndex priorSet = m_variables[operand].set; + m_variables[operand].set = addToGraph(SetLocal, OpInfo(operand), value); + if (priorSet != NoNode) + m_graph.deref(priorSet); } - // Used in implementing get/set, above, where the operand is a local or temporary. - NodeIndex getRegister(unsigned operand) + // Used in implementing get/set, above, where the operand is a temporary. + NodeIndex getTemporary(unsigned operand) { - NodeIndex index = m_calleeRegisters[operand]; + NodeIndex index = m_temporaries[operand]; if (index != NoNode) return index; - // We have not yet seen a definition for this value in this block. - // For now, since we are only generating single block functions, - // this value must be undefined. - // For example: - // function f() { var x; return x; } + + // Detect a read of an temporary that is not a yet defined within this block (e.g. use of ?:). + m_parseFailed = true; return constantUndefined(); } - void setRegister(int operand, NodeIndex value) + void setTemporary(unsigned operand, NodeIndex value) { - m_calleeRegisters[operand] = value; + m_temporaries[operand] = value; } // Used in implementing get/set, above, where the operand is an argument. - NodeIndex getArgument(unsigned argument) + NodeIndex getArgument(unsigned operand) { - NodeIndex index = m_arguments[argument]; - if (index != NoNode) - return index; - NodeIndex resultIndex = (NodeIndex)m_graph.size(); - m_graph.append(Node(Argument, m_currentIndex, OpInfo(argument))); - return m_arguments[argument] = resultIndex; + unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize; + ASSERT(argument < m_arguments.size()); + + NodeIndex setNode = m_arguments[argument].set; + if (setNode != NoNode) + return m_graph[setNode].child1; + + NodeIndex getNode = m_arguments[argument].get; + if (getNode != NoNode) + return getNode; + + getNode = addToGraph(GetLocal, OpInfo(operand)); + m_arguments[argument].get = getNode; + return getNode; } void setArgument(int operand, NodeIndex value) { - m_arguments[operand] = value; + unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize; + ASSERT(argument < m_arguments.size()); + + NodeIndex priorSet = m_arguments[argument].set; + m_arguments[argument].set = addToGraph(SetLocal, OpInfo(operand), value); + if (priorSet != NoNode) + m_graph.deref(priorSet); } // Get an operand, and perform a ToInt32/ToNumber conversion on it. @@ -229,46 +280,43 @@ private: // Used in implementing get, above, where the operand is a constant. NodeIndex getInt32Constant(int32_t value, unsigned constant) { - NodeIndex index = m_constantRecords[constant].asInt32; + NodeIndex index = m_constants[constant].asInt32; if (index != NoNode) return index; - NodeIndex resultIndex = (NodeIndex)m_graph.size(); - m_graph.append(Node(Int32Constant, m_currentIndex, OpInfo(constant))); + NodeIndex resultIndex = addToGraph(Int32Constant, OpInfo(constant)); m_graph[resultIndex].setInt32Constant(value); - m_constantRecords[constant].asInt32 = resultIndex; + m_constants[constant].asInt32 = resultIndex; return resultIndex; } NodeIndex getDoubleConstant(double value, unsigned constant) { - NodeIndex index = m_constantRecords[constant].asNumeric; + NodeIndex index = m_constants[constant].asNumeric; if (index != NoNode) return index; - NodeIndex resultIndex = (NodeIndex)m_graph.size(); - m_graph.append(Node(DoubleConstant, m_currentIndex, OpInfo(constant))); + NodeIndex resultIndex = addToGraph(DoubleConstant, OpInfo(constant)); m_graph[resultIndex].setDoubleConstant(value); - m_constantRecords[constant].asNumeric = resultIndex; + m_constants[constant].asNumeric = resultIndex; return resultIndex; } NodeIndex getJSConstant(unsigned constant) { - NodeIndex index = m_constantRecords[constant].asJSValue; + NodeIndex index = m_constants[constant].asJSValue; if (index != NoNode) return index; - NodeIndex resultIndex = (NodeIndex)m_graph.size(); - m_graph.append(Node(JSConstant, m_currentIndex, OpInfo(constant))); - m_constantRecords[constant].asJSValue = resultIndex; + NodeIndex resultIndex = addToGraph(JSConstant, OpInfo(constant)); + m_constants[constant].asJSValue = resultIndex; return resultIndex; } // Helper functions to get/set the this value. NodeIndex getThis() { - return getArgument(0); + return getArgument(m_codeBlock->thisRegister()); } void setThis(NodeIndex value) { - setArgument(0, value); + setArgument(m_codeBlock->thisRegister(), value); } // Convenience methods for checking nodes for constants. @@ -315,11 +363,11 @@ private: return getJSConstant(m_constantUndefined); } - // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constantRecords. - ASSERT(m_constantRecords.size() == numberOfConstants); + // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants. + ASSERT(m_constants.size() == numberOfConstants); m_codeBlock->addConstant(jsUndefined()); - m_constantRecords.append(ConstantRecord()); - ASSERT(m_constantRecords.size() == m_codeBlock->numberOfConstantRegisters()); + m_constants.append(ConstantRecord()); + ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); } // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'. @@ -327,6 +375,31 @@ private: return getJSConstant(m_constantUndefined); } + // This method returns a JSConstant with the value 'null'. + NodeIndex constantNull() + { + // Has m_constantNull been set up yet? + if (m_constantNull == UINT_MAX) { + // Search the constant pool for null, if we find it, we can just reuse this! + unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); + for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) { + JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull); + if (testMe.isNull()) + return getJSConstant(m_constantNull); + } + + // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants. + ASSERT(m_constants.size() == numberOfConstants); + m_codeBlock->addConstant(jsNull()); + m_constants.append(ConstantRecord()); + ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); + } + + // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'. + ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull()); + return getJSConstant(m_constantNull); + } + // This method returns a DoubleConstant with the value 1. NodeIndex one() { @@ -340,11 +413,11 @@ private: return getDoubleConstant(1, m_constant1); } - // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constantRecords. - ASSERT(m_constantRecords.size() == numberOfConstants); + // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants. + ASSERT(m_constants.size() == numberOfConstants); m_codeBlock->addConstant(jsNumber(1)); - m_constantRecords.append(ConstantRecord()); - ASSERT(m_constantRecords.size() == m_codeBlock->numberOfConstantRegisters()); + m_constants.append(ConstantRecord()); + ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); } // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1. @@ -374,6 +447,15 @@ private: m_graph.ref(resultIndex); return resultIndex; } + NodeIndex addToGraph(NodeType op, OpInfo info1, OpInfo info2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) + { + NodeIndex resultIndex = (NodeIndex)m_graph.size(); + m_graph.append(Node(op, m_currentIndex, info1, info2, child1, child2, child3)); + + if (op & NodeMustGenerate) + m_graph.ref(resultIndex); + return resultIndex; + } JSGlobalData* m_globalData; CodeBlock* m_codeBlock; @@ -382,8 +464,8 @@ private: // The bytecode index of the current instruction being generated. unsigned m_currentIndex; - // FIXME: used to temporarily disable arithmetic, until we fix associated performance regressions. - bool m_noArithmetic; + // Record failures due to unimplemented functionality or regressions. + bool m_parseFailed; // We use these values during code generation, and to avoid the need for // special handling we make sure they are available as constants in the @@ -391,6 +473,7 @@ private: // UINT_MAX, and lazily updated to hold an index into the CodeBlock's // constant pool, as necessary. unsigned m_constantUndefined; + unsigned m_constantNull; unsigned m_constant1; // A constant in the constant pool may be represented by more than one @@ -407,12 +490,27 @@ private: NodeIndex asNumeric; NodeIndex asJSValue; }; - Vector <ConstantRecord, 32> m_constantRecords; + + // For every local variable we track any existing get or set of the value. + // We track the get so that these may be shared, and we track the set to + // retrieve the current value, and to reference the final definition. + struct VariableRecord { + VariableRecord() + : get(NoNode) + , set(NoNode) + { + } + + NodeIndex get; + NodeIndex set; + }; // Track the index of the node whose result is the current value for every // register value in the bytecode - argument, local, and temporary. - Vector <NodeIndex, 32> m_arguments; - Vector <NodeIndex, 32> m_calleeRegisters; + Vector <ConstantRecord, 32> m_constants; + Vector <VariableRecord, 32> m_arguments; + Vector <VariableRecord, 32> m_variables; + Vector <NodeIndex, 32> m_temporaries; // These maps are used to unique ToNumber and ToInt32 operations. typedef HashMap<NodeIndex, NodeIndex> UnaryOpMap; @@ -422,15 +520,37 @@ private: #define NEXT_OPCODE(name) \ m_currentIndex += OPCODE_LENGTH(name); \ - continue; + continue -bool ByteCodeParser::parse() +#define LAST_OPCODE(name) \ + m_currentIndex += OPCODE_LENGTH(name); \ + return !m_parseFailed + +bool ByteCodeParser::parseBlock(unsigned limit) { + // No need to reset state initially, since it has been set by the constructor. + if (m_currentIndex) { + for (unsigned i = 0; i < m_constants.size(); ++i) + m_constants[i] = ConstantRecord(); + for (unsigned i = 0; i < m_variables.size(); ++i) + m_variables[i] = VariableRecord(); + for (unsigned i = 0; i < m_arguments.size(); ++i) + m_arguments[i] = VariableRecord(); + for (unsigned i = 0; i < m_temporaries.size(); ++i) + m_temporaries[i] = NoNode; + } + AliasTracker aliases(m_graph); Interpreter* interpreter = m_globalData->interpreter; Instruction* instructionsBegin = m_codeBlock->instructions().begin(); while (true) { + // Don't extend over jump destinations. + if (m_currentIndex == limit) { + addToGraph(Jump, OpInfo(m_currentIndex)); + return !m_parseFailed; + } + // Switch on the current bytecode opcode. Instruction* currentInstruction = instructionsBegin + m_currentIndex; switch (interpreter->getOpcodeID(currentInstruction->u.opcode)) { @@ -438,8 +558,9 @@ bool ByteCodeParser::parse() // === Function entry opcodes === case op_enter: - // This is a no-op for now - may need to initialize locals, if - // DCE analysis cannot determine that the values are never read. + // Initialize all locals to undefined. + for (int i = 0; i < m_codeBlock->m_numVars; ++i) + set(i, constantUndefined()); NEXT_OPCODE(op_enter); case op_convert_this: { @@ -561,7 +682,7 @@ bool ByteCodeParser::parse() // === Arithmetic operations === case op_add: { - m_noArithmetic = false; + ARITHMETIC_OP(); NodeIndex op1 = get(currentInstruction[2].u.operand); NodeIndex op2 = get(currentInstruction[3].u.operand); // If both operands can statically be determined to the numbers, then this is an arithmetic add. @@ -574,7 +695,7 @@ bool ByteCodeParser::parse() } case op_sub: { - m_noArithmetic = false; + ARITHMETIC_OP(); NodeIndex op1 = getToNumber(currentInstruction[2].u.operand); NodeIndex op2 = getToNumber(currentInstruction[3].u.operand); set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2)); @@ -582,7 +703,7 @@ bool ByteCodeParser::parse() } case op_mul: { - m_noArithmetic = false; + ARITHMETIC_OP(); NodeIndex op1 = getToNumber(currentInstruction[2].u.operand); NodeIndex op2 = getToNumber(currentInstruction[3].u.operand); set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2)); @@ -590,7 +711,7 @@ bool ByteCodeParser::parse() } case op_mod: { - m_noArithmetic = false; + ARITHMETIC_OP(); NodeIndex op1 = getToNumber(currentInstruction[2].u.operand); NodeIndex op2 = getToNumber(currentInstruction[3].u.operand); set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2)); @@ -598,7 +719,7 @@ bool ByteCodeParser::parse() } case op_div: { - m_noArithmetic = false; + ARITHMETIC_OP(); NodeIndex op1 = getToNumber(currentInstruction[2].u.operand); NodeIndex op2 = getToNumber(currentInstruction[3].u.operand); set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2)); @@ -613,6 +734,75 @@ bool ByteCodeParser::parse() NEXT_OPCODE(op_mov); } + case op_not: { + ARITHMETIC_OP(); + NodeIndex value = get(currentInstruction[2].u.operand); + set(currentInstruction[1].u.operand, addToGraph(LogicalNot, value)); + NEXT_OPCODE(op_not); + } + + case op_less: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(CompareLess, op1, op2)); + NEXT_OPCODE(op_less); + } + + case op_lesseq: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(CompareLessEq, op1, op2)); + NEXT_OPCODE(op_lesseq); + } + + case op_eq: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2)); + NEXT_OPCODE(op_eq); + } + + case op_eq_null: { + ARITHMETIC_OP(); + NodeIndex value = get(currentInstruction[2].u.operand); + set(currentInstruction[1].u.operand, addToGraph(CompareEq, value, constantNull())); + NEXT_OPCODE(op_eq_null); + } + + case op_stricteq: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2)); + NEXT_OPCODE(op_stricteq); + } + + case op_neq: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2))); + NEXT_OPCODE(op_neq); + } + + case op_neq_null: { + ARITHMETIC_OP(); + NodeIndex value = get(currentInstruction[2].u.operand); + set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, value, constantNull()))); + NEXT_OPCODE(op_neq_null); + } + + case op_nstricteq: { + ARITHMETIC_OP(); + NodeIndex op1 = get(currentInstruction[2].u.operand); + NodeIndex op2 = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2))); + NEXT_OPCODE(op_nstricteq); + } + // === Property access operations === case op_get_by_val: { @@ -624,7 +814,7 @@ bool ByteCodeParser::parse() aliases.recordGetByVal(getByVal); NEXT_OPCODE(op_get_by_val); - }; + } case op_put_by_val: { NodeIndex base = get(currentInstruction[1].u.operand); @@ -636,7 +826,7 @@ bool ByteCodeParser::parse() aliases.recordPutByVal(putByVal); NEXT_OPCODE(op_put_by_val); - }; + } case op_get_by_id: { NodeIndex base = get(currentInstruction[2].u.operand); @@ -680,35 +870,169 @@ bool ByteCodeParser::parse() // === Block terminators. === + case op_jmp: { + unsigned relativeOffset = currentInstruction[1].u.operand; + addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); + LAST_OPCODE(op_jmp); + } + + case op_loop: { + unsigned relativeOffset = currentInstruction[1].u.operand; + addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); + LAST_OPCODE(op_loop); + } + + case op_jtrue: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex condition = get(currentInstruction[1].u.operand); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jtrue)), condition); + LAST_OPCODE(op_jtrue); + } + + case op_jfalse: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex condition = get(currentInstruction[1].u.operand); + addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jfalse)), OpInfo(m_currentIndex + relativeOffset), condition); + LAST_OPCODE(op_jfalse); + } + + case op_loop_if_true: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex condition = get(currentInstruction[1].u.operand); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_true)), condition); + LAST_OPCODE(op_loop_if_true); + } + + case op_loop_if_false: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex condition = get(currentInstruction[1].u.operand); + addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_false)), OpInfo(m_currentIndex + relativeOffset), condition); + LAST_OPCODE(op_loop_if_false); + } + + case op_jeq_null: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex value = get(currentInstruction[1].u.operand); + NodeIndex condition = addToGraph(CompareEq, value, constantNull()); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jeq_null)), condition); + LAST_OPCODE(op_jeq_null); + } + + case op_jneq_null: { + unsigned relativeOffset = currentInstruction[2].u.operand; + NodeIndex value = get(currentInstruction[1].u.operand); + NodeIndex condition = addToGraph(CompareEq, value, constantNull()); + addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_null)), OpInfo(m_currentIndex + relativeOffset), condition); + LAST_OPCODE(op_jneq_null); + } + + case op_jnless: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLess, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnless)), OpInfo(m_currentIndex + relativeOffset), condition); + LAST_OPCODE(op_jnless); + } + + case op_jnlesseq: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLessEq, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnlesseq)), OpInfo(m_currentIndex + relativeOffset), condition); + LAST_OPCODE(op_jnlesseq); + } + + case op_jless: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLess, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jless)), condition); + LAST_OPCODE(op_jless); + } + + case op_jlesseq: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLessEq, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jlesseq)), condition); + LAST_OPCODE(op_jlesseq); + } + + case op_loop_if_less: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLess, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_less)), condition); + LAST_OPCODE(op_loop_if_less); + } + + case op_loop_if_lesseq: { + unsigned relativeOffset = currentInstruction[3].u.operand; + NodeIndex op1 = get(currentInstruction[1].u.operand); + NodeIndex op2 = get(currentInstruction[2].u.operand); + NodeIndex condition = addToGraph(CompareLessEq, op1, op2); + addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_lesseq)), condition); + LAST_OPCODE(op_loop_if_lesseq); + } + case op_ret: { addToGraph(Return, get(currentInstruction[1].u.operand)); - m_currentIndex += OPCODE_LENGTH(op_ret); -#if ENABLE(DFG_JIT_RESTRICTIONS) - // FIXME: temporarily disabling the DFG JIT for functions containing arithmetic. - return m_noArithmetic; -#else - return true; -#endif + + // FIXME: throw away terminal definitions of variables; + // should not be necessary once we have proper DCE! + for (unsigned i = 0; i < m_variables.size(); ++i) { + NodeIndex priorSet = m_variables[i].set; + if (priorSet != NoNode) + m_graph.deref(priorSet); + } + + LAST_OPCODE(op_ret); } default: - // parse failed! + // Parse failed! return false; } } } -bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock) +bool ByteCodeParser::parse() { - // Call ByteCodeParser::parse to build the dataflow for the basic block at 'startIndex'. - ByteCodeParser state(globalData, codeBlock, graph); - if (!state.parse()) - return false; + // Set during construction. + ASSERT(!m_currentIndex); + + for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= m_codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) { + // The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions. + unsigned limit = jumpTargetIndex < m_codeBlock->numberOfJumpTargets() ? m_codeBlock->jumpTarget(jumpTargetIndex) : m_codeBlock->instructions().size(); + ASSERT(m_currentIndex < limit); + + // Loop until we reach the current limit (i.e. next jump target). + do { + unsigned bytecodeBegin = m_currentIndex; + NodeIndex begin = m_graph.size(); + + if (!parseBlock(limit)) + return false; + // We should not have gone beyond the limit. + ASSERT(m_currentIndex <= limit); + + NodeIndex end = m_graph.size(); + m_graph.m_blocks.append(BasicBlock(bytecodeBegin, begin, end)); + } while (m_currentIndex < limit); + } + + // Should have reached the end of the instructions. + ASSERT(m_currentIndex == m_codeBlock->instructions().size()); // Assign VirtualRegisters. - ScoreBoard scoreBoard(graph); - Node* nodes = graph.begin(); - size_t size = graph.size(); + ScoreBoard scoreBoard(m_graph, m_variables.size()); + Node* nodes = m_graph.begin(); + size_t size = m_graph.size(); for (size_t i = 0; i < size; ++i) { Node& node = nodes[i]; if (node.refCount) { @@ -730,15 +1054,29 @@ bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock) // 'm_numCalleeRegisters' is the number of locals and temporaries allocated // for the function (and checked for on entry). Since we perform a new and // different allocation of temporaries, more registers may now be required. - if ((unsigned)codeBlock->m_numCalleeRegisters < scoreBoard.allocatedCount()) - codeBlock->m_numCalleeRegisters = scoreBoard.allocatedCount(); + unsigned calleeRegisters = scoreBoard.allocatedCount() + m_variables.size(); + if ((unsigned)m_codeBlock->m_numCalleeRegisters < calleeRegisters) + m_codeBlock->m_numCalleeRegisters = calleeRegisters; #if DFG_DEBUG_VERBOSE - graph.dump(codeBlock); + m_graph.dump(m_codeBlock); #endif + return true; } +bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock) +{ +#if DFG_DEBUG_LOCAL_DISBALE + UNUSED_PARAM(graph); + UNUSED_PARAM(globalData); + UNUSED_PARAM(codeBlock); + return false; +#else + return ByteCodeParser(globalData, codeBlock, graph).parse(); +#endif +} + } } // namespace JSC::DFG #endif |