Commit ec40baf6 authored by ggaren@apple.com's avatar ggaren@apple.com
Browse files

Source/JavaScriptCore: Filled out more cases of branch folding in bytecode when emitting

expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057

Reviewed by Filip Pizlo.

This covers a few cases like:

    - while (true) { }
    - while (1) { }
    - if (x) break;
    - if (x) continue;
    - if (boolean_expr == boolean_const) { }
    - if (boolean_expr == 1_or_0) { }
    - if (bitop == 1_or_0) { }

This also works, but will bring shame on your family:

    - while ("hello world") { }

No change on the benchmarks we track, but a 2.5X speedup on a microbenchmark
that uses these techniques.

* JavaScriptCore.order: Order!

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewArray):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::shouldEmitDebugHooks): Updated ancillary code
for interface simplifications.

* bytecompiler/NodesCodegen.cpp:
(JSC::ConstantNode::emitBytecodeInConditionContext): Constants can
jump unconditionally when used within a condition context.

(JSC::ConstantNode::emitBytecode):
(JSC::StringNode::jsValue): Gave constants a common base class so I
could implement their codegen just once.

(JSC::BinaryOpNode::emitBytecodeInConditionContext):
(JSC::canFoldToBranch):
(JSC::BinaryOpNode::tryFoldToBranch): Fold (!/=)= and (!/=)== where
appropriate. A lot of cases are not appropriate because of the surprising
type conversion semantics of ==. For example, if (number == true) { } is
not the same as if (number) { } because the former will up-convert true
to number and then do numeric comparison.

(JSC::singleStatement):
(JSC::IfElseNode::tryFoldBreakAndContinue):
(JSC::IfElseNode::emitBytecode):
(JSC::ContinueNode::trivialTarget):
(JSC::BreakNode::trivialTarget): Fold "if (expression) break" and
"if (expression) continue" into direct jumps from expression.

* parser/ASTBuilder.h:
(ASTBuilder):
(JSC::ASTBuilder::createIfStatement):
* parser/NodeConstructors.h:
(JSC::ConstantNode::ConstantNode):
(JSC):
(JSC::NullNode::NullNode):
(JSC::BooleanNode::BooleanNode):
(JSC::NumberNode::NumberNode):
(JSC::StringNode::StringNode):
(JSC::IfElseNode::IfElseNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isConstant):
(JSC::ExpressionNode::isBoolean):
(JSC::StatementNode::isBreak):
(JSC::StatementNode::isContinue):
(ConstantNode):
(JSC::ConstantNode::isPure):
(JSC::ConstantNode::isConstant):
(NullNode):
(JSC::NullNode::jsValue):
(JSC::BooleanNode::value):
(JSC::BooleanNode::isBoolean):
(JSC::BooleanNode::jsValue):
(JSC::NumberNode::value):
(NumberNode):
(JSC::NumberNode::jsValue):
(StringNode):
(BinaryOpNode):
(IfElseNode):
(ContinueNode):
(JSC::ContinueNode::isContinue):
(BreakNode):
(JSC::BreakNode::isBreak):
* parser/Parser.cpp:
(JSC::::parseIfStatement):
* parser/ResultType.h:
(JSC::ResultType::definitelyIsBoolean):
(ResultType):
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::pureToBoolean):
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::pureToBoolean): Updated for interface changes above.

Source/WTF: Filled out more cases of branch folding in bytecode when emitting expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057

Reviewed by Filip Pizlo.

Added a helper constructor for TriState so clients can make one without
branching or making assumptions about the integer values of TriStates.

* wtf/TriState.h:
(WTF::triState):
(WTF):

LayoutTests: Filled out more cases of branch folding in bytecode when emitting expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057

Reviewed by Filip Pizlo.

Added a performance test for interesting branch types.

* fast/js/regress/branch-fold-expected.txt: Added.
* fast/js/regress/branch-fold.html: Added.
* fast/js/regress/script-tests/branch-fold.js: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@148999 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent cdd758c0
2013-04-23 Geoffrey Garen <ggaren@apple.com>
Filled out more cases of branch folding in bytecode when emitting expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057
Reviewed by Filip Pizlo.
Added a performance test for interesting branch types.
* fast/js/regress/branch-fold-expected.txt: Added.
* fast/js/regress/branch-fold.html: Added.
* fast/js/regress/script-tests/branch-fold.js: Added.
2013-04-23 Simon Fraser <simon.fraser@apple.com>
 
Don't create compositing layers for sticky position unless using the ScrollingCoordinator
JSRegress/branch-fold
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/branch-fold.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
function f()
{
var i;
var limit = 150000;
for (i = 0; (i < limit) == true; ++i) {
}
if (i != limit)
throw "bad result";
for (i = 0; (i < limit) === true; ++i) {
}
if (i != limit)
throw "bad result";
i = 0;
for (var done = false; done == false; ) {
if (!(++i < limit))
done = true;
}
if (i != limit)
throw "bad result";
i = 0;
while (true) {
if ((++i < limit) == false)
break;
}
if (i != limit)
throw "bad result";
i = 0;
while (1) {
if ((++i < limit) != true)
break;
}
if (i != limit)
throw "bad result";
i = limit;
while (--i) {
if ((i & 1) == 0)
continue;
}
if (i != 0)
throw "bad result";
}
f();
2013-04-23 Geoffrey Garen <ggaren@apple.com>
Filled out more cases of branch folding in bytecode when emitting
expressions into a branching context
https://bugs.webkit.org/show_bug.cgi?id=115057
Reviewed by Filip Pizlo.
This covers a few cases like:
- while (true) { }
- while (1) { }
- if (x) break;
- if (x) continue;
- if (boolean_expr == boolean_const) { }
- if (boolean_expr == 1_or_0) { }
- if (bitop == 1_or_0) { }
This also works, but will bring shame on your family:
- while ("hello world") { }
No change on the benchmarks we track, but a 2.5X speedup on a microbenchmark
that uses these techniques.
* JavaScriptCore.order: Order!
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewArray):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::shouldEmitDebugHooks): Updated ancillary code
for interface simplifications.
* bytecompiler/NodesCodegen.cpp:
(JSC::ConstantNode::emitBytecodeInConditionContext): Constants can
jump unconditionally when used within a condition context.
(JSC::ConstantNode::emitBytecode):
(JSC::StringNode::jsValue): Gave constants a common base class so I
could implement their codegen just once.
(JSC::BinaryOpNode::emitBytecodeInConditionContext):
(JSC::canFoldToBranch):
(JSC::BinaryOpNode::tryFoldToBranch): Fold (!/=)= and (!/=)== where
appropriate. A lot of cases are not appropriate because of the surprising
type conversion semantics of ==. For example, if (number == true) { } is
not the same as if (number) { } because the former will up-convert true
to number and then do numeric comparison.
(JSC::singleStatement):
(JSC::IfElseNode::tryFoldBreakAndContinue):
(JSC::IfElseNode::emitBytecode):
(JSC::ContinueNode::trivialTarget):
(JSC::BreakNode::trivialTarget): Fold "if (expression) break" and
"if (expression) continue" into direct jumps from expression.
* parser/ASTBuilder.h:
(ASTBuilder):
(JSC::ASTBuilder::createIfStatement):
* parser/NodeConstructors.h:
(JSC::ConstantNode::ConstantNode):
(JSC):
(JSC::NullNode::NullNode):
(JSC::BooleanNode::BooleanNode):
(JSC::NumberNode::NumberNode):
(JSC::StringNode::StringNode):
(JSC::IfElseNode::IfElseNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isConstant):
(JSC::ExpressionNode::isBoolean):
(JSC::StatementNode::isBreak):
(JSC::StatementNode::isContinue):
(ConstantNode):
(JSC::ConstantNode::isPure):
(JSC::ConstantNode::isConstant):
(NullNode):
(JSC::NullNode::jsValue):
(JSC::BooleanNode::value):
(JSC::BooleanNode::isBoolean):
(JSC::BooleanNode::jsValue):
(JSC::NumberNode::value):
(NumberNode):
(JSC::NumberNode::jsValue):
(StringNode):
(BinaryOpNode):
(IfElseNode):
(ContinueNode):
(JSC::ContinueNode::isContinue):
(BreakNode):
(JSC::BreakNode::isBreak):
* parser/Parser.cpp:
(JSC::::parseIfStatement):
* parser/ResultType.h:
(JSC::ResultType::definitelyIsBoolean):
(ResultType):
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::pureToBoolean):
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::pureToBoolean): Updated for interface changes above.
2013-04-23 Mark Lam <mark.lam@apple.com>
 
Simplify the baseline JIT loop hint call site.
......@@ -717,7 +717,6 @@ __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()->isNumber() && !n->value()->isString()) {
if (!n->value()->isConstant()) {
hadVariableExpression = true;
break;
}
......@@ -1644,12 +1644,8 @@ 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()) {
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());
}
ASSERT(n->value()->isConstant());
constantBuffer[index++] = static_cast<ConstantNode*>(n->value())->jsValue(*this);
}
emitOpcode(op_new_array_buffer);
instructions().append(dst->index());
......@@ -2365,7 +2361,7 @@ RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID*
void BytecodeGenerator::emitThrowReferenceError(const String& message)
{
emitOpcode(op_throw_static_error);
instructions().append(addConstantValue(jsString(vm(), message))->index());
instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, message)))->index());
instructions().append(true);
}
......@@ -2523,7 +2519,7 @@ void BytecodeGenerator::emitReadOnlyExceptionIfNeeded()
if (!isStrictMode())
return;
emitOpcode(op_throw_static_error);
instructions().append(addConstantValue(jsString(vm(), StrictModeReadonlyPropertyWriteError))->index());
instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, StrictModeReadonlyPropertyWriteError)))->index());
instructions().append(false);
}
......
......@@ -553,6 +553,7 @@ 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(); }
......@@ -646,8 +647,6 @@ 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());
......@@ -656,6 +655,8 @@ namespace JSC {
RegisterID* emitInitLazyRegister(RegisterID*);
public:
JSString* addStringConstant(const Identifier&);
Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; }
SharedSymbolTable& symbolTable() { return *m_symbolTable; }
......
......@@ -92,40 +92,31 @@ RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator&
return generator.newTemporary();
}
// ------------------------------ NullNode -------------------------------------
// ------------------------------ ConstantNode ----------------------------------
RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, jsNull());
}
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);
// ------------------------------ BooleanNode ----------------------------------
RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
// All other cases are unconditional fall-throughs, like "if (true)".
}
// ------------------------------ NumberNode -----------------------------------
RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
return generator.emitLoad(dst, jsValue(generator));
}
// ------------------------------ StringNode -----------------------------------
RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
JSValue StringNode::jsValue(BytecodeGenerator& generator) const
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
return generator.addStringConstant(m_value);
}
// ------------------------------ RegExpNode -----------------------------------
......@@ -1042,6 +1033,64 @@ 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();
......@@ -1504,41 +1553,71 @@ void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
generator.emitNode(m_expr);
}
// ------------------------------ IfNode ---------------------------------------
// ------------------------------ IfElseNode ---------------------------------------
void IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
static inline StatementNode* singleStatement(StatementNode* statementNode)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), charPosition());
RefPtr<Label> afterThen = generator.newLabel();
if (statementNode->isBlock())
return static_cast<BlockNode*>(statementNode)->singleStatement();
return statementNode;
}
RefPtr<Label> beforeThen = generator.newLabel();
generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), FallThroughMeansTrue);
generator.emitLabel(beforeThen.get());
bool IfElseNode::tryFoldBreakAndContinue(BytecodeGenerator& generator, StatementNode* ifBlock,
Label*& trueTarget, FallThroughMode& fallThroughMode)
{
StatementNode* singleStatement = JSC::singleStatement(ifBlock);
if (!singleStatement)
return false;
generator.emitNode(dst, m_ifBlock);
generator.emitLabel(afterThen.get());
}
if (singleStatement->isBreak()) {
BreakNode* breakNode = static_cast<BreakNode*>(singleStatement);
Label* target = breakNode->trivialTarget(generator);
if (!target)
return false;
trueTarget = target;
fallThroughMode = FallThroughMeansFalse;
return true;
}
// ------------------------------ IfElseNode ---------------------------------------
if (singleStatement->isContinue()) {
ContinueNode* continueNode = static_cast<ContinueNode*>(singleStatement);
Label* target = continueNode->trivialTarget(generator);
if (!target)
return false;
trueTarget = target;
fallThroughMode = FallThroughMeansFalse;
return true;
}
return false;
}
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();
RefPtr<Label> beforeThen = generator.newLabel();
generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue);
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);
generator.emitLabel(beforeThen.get());
generator.emitNode(dst, m_ifBlock);
generator.emitJump(afterElse.get());
if (!didFoldIfBlock) {
generator.emitNode(dst, m_ifBlock);
if (m_elseBlock)
generator.emitJump(afterElse.get());
}
generator.emitLabel(beforeElse.get());
generator.emitNode(dst, m_elseBlock);
if (m_elseBlock)
generator.emitNode(dst, m_elseBlock);
generator.emitLabel(afterElse.get());
}
......@@ -1700,6 +1779,20 @@ 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());
......@@ -1713,6 +1806,20 @@ 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,16 +344,9 @@ 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)
{
IfNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
IfElseNode* result = new (m_vm) IfElseNode(location, condition, trueBlock, falseBlock);
result->setLoc(start, end, location.charPosition);
return result;
}
......
......@@ -60,25 +60,30 @@ namespace JSC {
{
}
inline ConstantNode::ConstantNode(const JSTokenLocation& location, ResultType resultType)
: ExpressionNode(location, resultType)
{
}
inline NullNode::NullNode(const JSTokenLocation& location)
: ExpressionNode(location, ResultType::nullType())
: ConstantNode(location, ResultType::nullType())
{
}
inline BooleanNode::BooleanNode(const JSTokenLocation& location, bool value)
: ExpressionNode(location, ResultType::booleanType())
: ConstantNode(location, ResultType::booleanType())
, m_value(value)
{
}
inline NumberNode::NumberNode(const JSTokenLocation& location, double value)
: ExpressionNode(location, ResultType::numberType())
: ConstantNode(location, ResultType::numberType())
, m_value(value)
{
}
inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value)
: ExpressionNode(location, ResultType::stringType())
: ConstantNode(location, ResultType::stringType())
, m_value(value)
{
}
......@@ -631,15 +636,10 @@ namespace JSC {
{
}