Commit 335ba39b authored by fpizlo@apple.com's avatar fpizlo@apple.com
Browse files

Unreviewed, roll out http://trac.webkit.org/changeset/148999

It broke http://kripken.github.io/ammo.js/examples/new/ammo.html

Source/JavaScriptCore: 

* JavaScriptCore.order:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewArray):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::shouldEmitProfileHooks):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC):
(JSC::NullNode::emitBytecode):
(JSC::BooleanNode::emitBytecode):
(JSC::NumberNode::emitBytecode):
(JSC::StringNode::emitBytecode):
(JSC::IfNode::emitBytecode):
(JSC::IfElseNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createIfStatement):
(ASTBuilder):
* parser/NodeConstructors.h:
(JSC):
(JSC::NullNode::NullNode):
(JSC::BooleanNode::BooleanNode):
(JSC::NumberNode::NumberNode):
(JSC::StringNode::StringNode):
(JSC::IfNode::IfNode):
(JSC::IfElseNode::IfElseNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isPure):
(JSC::ExpressionNode::isSubtract):
(StatementNode):
(NullNode):
(JSC::NullNode::isNull):
(BooleanNode):
(JSC::BooleanNode::isPure):
(NumberNode):
(JSC::NumberNode::value):
(JSC::NumberNode::isPure):
(StringNode):
(JSC::StringNode::isPure):
(JSC::StringNode::isString):
(BinaryOpNode):
(IfNode):
(JSC):
(IfElseNode):
(ContinueNode):
(BreakNode):
* parser/Parser.cpp:
(JSC::::parseIfStatement):
* parser/ResultType.h:
(ResultType):
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::pureToBoolean):
* runtime/JSCell.h:
(JSCell):
* runtime/JSCellInlines.h:
(JSC):

Source/WTF: 

* wtf/TriState.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149158 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 63f8fca7
2013-04-25 Filip Pizlo <fpizlo@apple.com>
Unreviewed, roll out http://trac.webkit.org/changeset/148999
It broke http://kripken.github.io/ammo.js/examples/new/ammo.html
* JavaScriptCore.order:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewArray):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::shouldEmitProfileHooks):
(BytecodeGenerator):
* bytecompiler/NodesCodegen.cpp:
(JSC):
(JSC::NullNode::emitBytecode):
(JSC::BooleanNode::emitBytecode):
(JSC::NumberNode::emitBytecode):
(JSC::StringNode::emitBytecode):
(JSC::IfNode::emitBytecode):
(JSC::IfElseNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createIfStatement):
(ASTBuilder):
* parser/NodeConstructors.h:
(JSC):
(JSC::NullNode::NullNode):
(JSC::BooleanNode::BooleanNode):
(JSC::NumberNode::NumberNode):
(JSC::StringNode::StringNode):
(JSC::IfNode::IfNode):
(JSC::IfElseNode::IfElseNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isPure):
(JSC::ExpressionNode::isSubtract):
(StatementNode):
(NullNode):
(JSC::NullNode::isNull):
(BooleanNode):
(JSC::BooleanNode::isPure):
(NumberNode):
(JSC::NumberNode::value):
(JSC::NumberNode::isPure):
(StringNode):
(JSC::StringNode::isPure):
(JSC::StringNode::isString):
(BinaryOpNode):
(IfNode):
(JSC):
(IfElseNode):
(ContinueNode):
(BreakNode):
* parser/Parser.cpp:
(JSC::::parseIfStatement):
* parser/ResultType.h:
(ResultType):
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::pureToBoolean):
* runtime/JSCell.h:
(JSCell):
* runtime/JSCellInlines.h:
(JSC):
2013-04-25 Filip Pizlo <fpizlo@apple.com>
PreciseJumpTargets should treat loop_hint as a jump target
......
......@@ -717,6 +717,7 @@ __ZNK3JSC14ExpressionNode13isResolveNodeEv
__ZNK3JSC14ExpressionNode21isBracketAccessorNodeEv
__ZN3JSC9CodeBlock25createRareDataIfNecessaryEv
__ZN3WTF6VectorIN3JSC8LineInfoELm0EE14expandCapacityEm
__ZN3JSC6IfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator8newLabelEv
__ZNK3JSC14ExpressionNode26hasConditionContextCodegenEv
__ZN3WTF6VectorIN3JSC19ExpressionRangeInfoELm0EE14expandCapacityEm
......
......@@ -1628,7 +1628,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
bool hadVariableExpression = false;
if (length) {
for (ElementNode* n = elements; n; n = n->next()) {
if (!n->value()->isConstant()) {
if (!n->value()->isNumber() && !n->value()->isString()) {
hadVariableExpression = true;
break;
}
......@@ -1644,8 +1644,12 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex).data();
unsigned index = 0;
for (ElementNode* n = elements; index < length; n = n->next()) {
ASSERT(n->value()->isConstant());
constantBuffer[index++] = static_cast<ConstantNode*>(n->value())->jsValue(*this);
if (n->value()->isNumber())
constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
else {
ASSERT(n->value()->isString());
constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value());
}
}
emitOpcode(op_new_array_buffer);
instructions().append(dst->index());
......@@ -2361,7 +2365,7 @@ RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID*
void BytecodeGenerator::emitThrowReferenceError(const String& message)
{
emitOpcode(op_throw_static_error);
instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, message)))->index());
instructions().append(addConstantValue(jsString(vm(), message))->index());
instructions().append(true);
}
......@@ -2519,7 +2523,7 @@ void BytecodeGenerator::emitReadOnlyExceptionIfNeeded()
if (!isStrictMode())
return;
emitOpcode(op_throw_static_error);
instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, StrictModeReadonlyPropertyWriteError)))->index());
instructions().append(addConstantValue(jsString(vm(), StrictModeReadonlyPropertyWriteError))->index());
instructions().append(false);
}
......
......@@ -553,7 +553,6 @@ namespace JSC {
CodeType codeType() const { return m_codeType; }
bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; }
bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
......@@ -647,6 +646,8 @@ namespace JSC {
return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body);
}
JSString* addStringConstant(const Identifier&);
void addLineInfo(unsigned lineNo)
{
m_codeBlock->addLineInfo(instructions().size(), lineNo - m_scopeNode->firstLine());
......@@ -655,8 +656,6 @@ namespace JSC {
RegisterID* emitInitLazyRegister(RegisterID*);
public:
JSString* addStringConstant(const Identifier&);
Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; }
SharedSymbolTable& symbolTable() { return *m_symbolTable; }
......
......@@ -92,31 +92,40 @@ RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator&
return generator.newTemporary();
}
// ------------------------------ ConstantNode ----------------------------------
// ------------------------------ NullNode -------------------------------------
void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
TriState value = jsValue(generator).pureToBoolean();
if (value == MixedTriState)
ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse)
generator.emitJump(trueTarget);
else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue)
generator.emitJump(falseTarget);
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, jsNull());
}
// All other cases are unconditional fall-throughs, like "if (true)".
// ------------------------------ BooleanNode ----------------------------------
RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
}
RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
// ------------------------------ NumberNode -----------------------------------
RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, jsValue(generator));
return generator.emitLoad(dst, m_value);
}
JSValue StringNode::jsValue(BytecodeGenerator& generator) const
// ------------------------------ StringNode -----------------------------------
RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
return generator.addStringConstant(m_value);
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
}
// ------------------------------ RegExpNode -----------------------------------
......@@ -1033,64 +1042,6 @@ RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* d
return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size());
}
void BinaryOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
{
TriState branchCondition;
ExpressionNode* branchExpression;
tryFoldToBranch(generator, branchCondition, branchExpression);
if (branchCondition == MixedTriState)
ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
else if (branchCondition == TrueTriState)
generator.emitNodeInConditionContext(branchExpression, trueTarget, falseTarget, fallThroughMode);
else
generator.emitNodeInConditionContext(branchExpression, falseTarget, trueTarget, invert(fallThroughMode));
}
static inline bool canFoldToBranch(OpcodeID opcodeID, ExpressionNode* branchExpression, JSValue constant)
{
ResultType expressionType = branchExpression->resultDescriptor();
if (expressionType.definitelyIsBoolean() && constant.isBoolean())
return true;
else if (expressionType.isInt32() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1))
return true;
else if (expressionType.definitelyIsBoolean() && constant.isInt32() && (constant.asInt32() == 0 || constant.asInt32() == 1))
return opcodeID == op_eq || opcodeID == op_neq; // Strict equality is false in the case of type mismatch, so we can't fold to a branch based on truthiness.
return false;
}
void BinaryOpNode::tryFoldToBranch(BytecodeGenerator& generator, TriState& branchCondition, ExpressionNode*& branchExpression)
{
branchCondition = MixedTriState;
branchExpression = 0;
ConstantNode* constant = 0;
if (m_expr1->isConstant()) {
constant = static_cast<ConstantNode*>(m_expr1);
branchExpression = m_expr2;
} else if (m_expr2->isConstant()) {
constant = static_cast<ConstantNode*>(m_expr2);
branchExpression = m_expr1;
}
if (!constant)
return;
ASSERT(branchExpression);
OpcodeID opcodeID = this->opcodeID();
JSValue value = constant->jsValue(generator);
bool canFoldToBranch = JSC::canFoldToBranch(opcodeID, branchExpression, value);
if (!canFoldToBranch)
return;
if (opcodeID == op_eq || opcodeID == op_stricteq)
branchCondition = triState(value.pureToBoolean());
else if (opcodeID == op_neq || opcodeID == op_nstricteq)
branchCondition = triState(!value.pureToBoolean());
}
RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
OpcodeID opcodeID = this->opcodeID();
......@@ -1553,71 +1504,41 @@ void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
generator.emitNode(m_expr);
}
// ------------------------------ IfElseNode ---------------------------------------
// ------------------------------ IfNode ---------------------------------------
static inline StatementNode* singleStatement(StatementNode* statementNode)
void IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (statementNode->isBlock())
return static_cast<BlockNode*>(statementNode)->singleStatement();
return statementNode;
}
bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock,
Label*& trueTarget, FallThroughMode& fallThroughMode)
{
StatementNode* singleStatement = JSC::singleStatement(ifBlock);
if (!singleStatement)
return false;
if (singleStatement->isBreak()) {
BreakNode* breakNode = static_cast<BreakNode*>(singleStatement);
Label* target = breakNode->trivialTarget(generator);
if (!target)
return false;
trueTarget = target;
fallThroughMode = FallThroughMeansFalse;
return true;
}
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
RefPtr<Label> afterThen = generator.newLabel();
if (singleStatement->isContinue()) {
ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement);
Label* target = continueNode->trivialTarget(generator);
if (!target)
return false;
trueTarget = target;
fallThroughMode = FallThroughMeansFalse;
return true;
}
RefPtr<Label> beforeThen = generator.newLabel();
generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), FallThroughMeansTrue);
generator.emitLabel(beforeThen.get());
return false;
generator.emitNode(dst, m_ifBlock);
generator.emitLabel(afterThen.get());
}
// ------------------------------ IfElseNode ---------------------------------------
void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
RefPtr<Label> beforeThen = generator.newLabel();
RefPtr<Label> beforeElse = generator.newLabel();
RefPtr<Label> afterElse = generator.newLabel();
Label* trueTarget = beforeThen.get();
Label* falseTarget = beforeElse.get();
FallThroughMode fallThroughMode = FallThroughMeansTrue;
bool didFoldIfBlock = tryFoldBreakAndContinue(generator, m_ifBlock, trueTarget, fallThroughMode);
generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode);
RefPtr<Label> beforeThen = generator.newLabel();
generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue);
generator.emitLabel(beforeThen.get());
if (!didFoldIfBlock) {
generator.emitNode(dst, m_ifBlock);
if (m_elseBlock)
generator.emitJump(afterElse.get());
}
generator.emitNode(dst, m_ifBlock);
generator.emitJump(afterElse.get());
generator.emitLabel(beforeElse.get());
if (m_elseBlock)
generator.emitNode(dst, m_elseBlock);
generator.emitNode(dst, m_elseBlock);
generator.emitLabel(afterElse.get());
}
......@@ -1779,20 +1700,6 @@ void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
// ------------------------------ ContinueNode ---------------------------------
Label* ContinueNode::trivialTarget(BytecodeGenerator& generator)
{
if (generator.shouldEmitDebugHooks())
return 0;
LabelScope* scope = generator.continueTarget(m_ident);
ASSERT(scope);
if (generator.scopeDepth() != scope->scopeDepth())
return 0;
return scope->continueTarget();
}
void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
......@@ -1806,20 +1713,6 @@ void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
// ------------------------------ BreakNode ------------------------------------
Label* BreakNode::trivialTarget(BytecodeGenerator& generator)
{
if (generator.shouldEmitDebugHooks())
return 0;
LabelScope* scope = generator.breakTarget(m_ident);
ASSERT(scope);
if (generator.scopeDepth() != scope->scopeDepth())
return 0;
return scope->breakTarget();
}
void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
......
......@@ -344,9 +344,16 @@ public:
return result;
}
StatementNode* createIfStatement(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* trueBlock, int start, int end)
{
IfNode* result = new (m_vm) IfNode(location, condition, trueBlock);
result->setLoc(start, end, location.charPosition);
return result;
}
StatementNode* createIfStatement(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
{
IfElseNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
IfNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
result->setLoc(start, end, location.charPosition);
return result;
}
......
......@@ -60,30 +60,25 @@ namespace JSC {
{
}
inline ConstantNode::ConstantNode(const JSTokenLocation& location, ResultType resultType)
: ExpressionNode(location, resultType)
{
}
inline NullNode::NullNode(const JSTokenLocation& location)
: ConstantNode(location, ResultType::nullType())
: ExpressionNode(location, ResultType::nullType())
{
}
inline BooleanNode::BooleanNode(const JSTokenLocation& location, bool value)
: ConstantNode(location, ResultType::booleanType())
: ExpressionNode(location, ResultType::booleanType())
, m_value(value)
{
}
inline NumberNode::NumberNode(const JSTokenLocation& location, double value)
: ConstantNode(location, ResultType::numberType())
: ExpressionNode(location, ResultType::numberType())
, m_value(value)
{
}
inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value)
: ConstantNode(location, ResultType::stringType())
: ExpressionNode(location, ResultType::stringType())
, m_value(value)
{
}
......@@ -636,10 +631,15 @@ namespace JSC {
{
}
inline IfElseNode::IfElseNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
inline IfNode::IfNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock)
: StatementNode(location)
, m_condition(condition)
, m_ifBlock(ifBlock)
{
}
inline IfElseNode::IfElseNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
: IfNode(location, condition, ifBlock)
, m_elseBlock(elseBlock)
{
}
......
......@@ -149,7 +149,6 @@ namespace JSC {
virtual bool isString() const { return false; }
virtual bool isNull() const { return false; }
virtual bool isPure(BytecodeGenerator&) const { return false; }
virtual bool isConstant() const { return false; }
virtual bool isLocation() const { return false; }
virtual bool isResolveNode() const { return false; }
virtual bool isBracketAccessorNode() const { return false; }
......@@ -159,7 +158,6 @@ namespace JSC {
virtual bool isSimpleArray() const { return false; }
virtual bool isAdd() const { return false; }
virtual bool isSubtract() const { return false; }
virtual bool isBoolean() const { return false; }
virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, FallThroughMode);
......@@ -185,67 +183,63 @@ namespace JSC {
virtual bool isEmptyStatement() const { return false; }
virtual bool isReturnNode() const { return false; }
virtual bool isExprStatement() const { return false; }
virtual bool isBreak() const { return false; }
virtual bool isContinue() const { return false; }
virtual bool isBlock() const { return false; }
private:
int m_lastLine;
};
class ConstantNode : public ExpressionNode {
public:
ConstantNode(const JSTokenLocation&, ResultType);
virtual bool isPure(BytecodeGenerator&) const { return true; }
virtual bool isConstant() const { return true; }
virtual JSValue jsValue(BytecodeGenerator&) const = 0;
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode);
};
class NullNode : public ConstantNode {
class NullNode : public ExpressionNode {
public:
NullNode(const JSTokenLocation&);
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
virtual bool isNull() const { return true; }
virtual JSValue jsValue(BytecodeGenerator&) const { return jsNull(); }
};
class BooleanNode : public ConstantNode {
class BooleanNode : public ExpressionNode {
public:
BooleanNode(const JSTokenLocation&, bool value);
bool value() { return m_value; }
private:
virtual bool isBoolean() const { return true; }
virtual JSValue jsValue(BytecodeGenerator&) const { return jsBoolean(m_value); }
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
virtual bool isPure(BytecodeGenerator&) const { return true; }
bool m_value;
};
class NumberNode : public ConstantNode {
class NumberNode : public ExpressionNode {
public:
NumberNode(const JSTokenLocation&, double value);
double value() { return m_value; }
double value() const { return m_value; }
void setValue(double value) { m_value = value; }
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
virtual bool isNumber() const { return true; }
virtual JSValue jsValue(BytecodeGenerator&) const { return jsNumber(m_value); }
virtual bool isPure(BytecodeGenerator&) const { return true; }
double m_value;
};
class StringNode : public ConstantNode {
class StringNode : public ExpressionNode {
public:
StringNode(const JSTokenLocation&, const Identifier&);
const Identifier& value() { return m_value; }
private:
virtual bool isPure(BytecodeGenerator&) const { return true; }
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
virtual bool isString() const { return true; }
virtual JSValue jsValue(BytecodeGenerator&) const;
const Identifier& m_value;
};
......@@ -751,13 +745,11 @@ namespace JSC {
BinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0);
void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode);
ExpressionNode* lhs() { return m_expr1; };
ExpressionNode* rhs() { return m_expr2; };
private:
void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression);
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
protected:
......@@ -1132,17 +1124,24 @@ namespace JSC {
ExpressionNode* m_expr;
};