<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[180813] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/180813">180813</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-02-27 19:21:37 -0800 (Fri, 27 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Use the way number constants are written to help type speculation
https://bugs.webkit.org/show_bug.cgi?id=142072

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2015-02-27
Reviewed by Filip Pizlo.

This patch changes how we interpret numeric constant based on how they appear
in the source.

Constants that are integers but written with a decimal point now carry that information
to the optimizating tiers. From there, we use that to be more aggressive about typing
math operations toward double operations.

For example, in:
    var a = x + 1.0;
    var b = y + 1;
The Add for a would be biased toward doubles, the Add for b would speculate
integer as usual.


The gains are tiny but this is a prerequisite to make my next patch useful:
-SunSpider's access-fannkuch: definitely 1.0661x faster
-SunSpider's math-cordic: definitely 1.0266x slower
    overal: might be 1.0066x slower.
-Kraken's imaging-darkroom: definitely 1.0333x faster.

* parser/Lexer.cpp:
(JSC::tokenTypeForIntegerLikeToken):
(JSC::Lexer&lt;T&gt;::lex):
The lexer now create two types of tokens for number: INTEGER and DOUBLE.
Those token types only carry information about how the values were
entered, an INTEGER does not have to be an integer, it is only written like one.
Large integer still end up represented as double in memory.

One trap I fell into was typing numbers like 12e3 as double. This kind of literal
is frequently used in integer-typed code, while 12.e3 would appear in double-typed
code.
Because of that, the only signals for double are: decimal point, negative zero,
and ridiculously large values.

* parser/NodeConstructors.h:
(JSC::DoubleNode::DoubleNode):
(JSC::IntegerNode::IntegerNode):
* parser/Nodes.h:
(JSC::NumberNode::value):
(JSC::NumberNode::setValue): Deleted.
Number get specialized in two new kind of nodes in the AST: IntegerNode and DoubleNode.

* bytecompiler/NodesCodegen.cpp:
(JSC::NumberNode::emitBytecode):

* parser/ASTBuilder.h:
(JSC::ASTBuilder::createDoubleExpr):
(JSC::ASTBuilder::createIntegerExpr):
(JSC::ASTBuilder::createIntegerLikeNumber):
(JSC::ASTBuilder::createDoubleLikeNumber):
(JSC::ASTBuilder::createNumberFromBinaryOperation):
(JSC::ASTBuilder::createNumberFromUnaryOperation):
(JSC::ASTBuilder::makeNegateNode):
(JSC::ASTBuilder::makeBitwiseNotNode):
(JSC::ASTBuilder::makeMultNode):
(JSC::ASTBuilder::makeDivNode):
(JSC::ASTBuilder::makeModNode):
(JSC::ASTBuilder::makeAddNode):
(JSC::ASTBuilder::makeSubNode):
(JSC::ASTBuilder::makeLeftShiftNode):
(JSC::ASTBuilder::makeRightShiftNode):
(JSC::ASTBuilder::makeURightShiftNode):
(JSC::ASTBuilder::makeBitOrNode):
(JSC::ASTBuilder::makeBitAndNode):
(JSC::ASTBuilder::makeBitXOrNode):
(JSC::ASTBuilder::createNumberExpr): Deleted.
(JSC::ASTBuilder::createNumber): Deleted.
The AST has some optimization to resolve constants before emitting bytecode.
In the new code, the intger representation is kept if both operands where
also represented as integers.

* parser/Parser.cpp:
(JSC::Parser&lt;LexerType&gt;::parseDeconstructionPattern):
(JSC::Parser&lt;LexerType&gt;::parseProperty):
(JSC::Parser&lt;LexerType&gt;::parseGetterSetter):
(JSC::Parser&lt;LexerType&gt;::parsePrimaryExpression):
(JSC::Parser&lt;LexerType&gt;::printUnexpectedTokenText):
* parser/ParserTokens.h:
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createDoubleExpr):
(JSC::SyntaxChecker::createIntegerExpr):
(JSC::SyntaxChecker::createNumberExpr): Deleted.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::registerName):
(JSC::CodeBlock::constantName):
Change constantName(r, getConstant(r)) -&gt; constantName(r) to simplify
the dump code.

(JSC::CodeBlock::dumpBytecode):
Dump thre soure representation information we have with each constant.

(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::shrinkToFit):
(JSC::constantName): Deleted.
* bytecode/CodeBlock.h:
(JSC::CodeBlock::constantsSourceCodeRepresentation):
(JSC::CodeBlock::addConstant):
(JSC::CodeBlock::addConstantLazily):
(JSC::CodeBlock::constantSourceCodeRepresentation):
(JSC::CodeBlock::setConstantRegisters):

* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addConstant):
(JSC::UnlinkedCodeBlock::constantsSourceCodeRepresentation):
(JSC::UnlinkedCodeBlock::shrinkToFit):

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addConstantValue):
(JSC::BytecodeGenerator::emitLoad):
* bytecompiler/BytecodeGenerator.h:
We have to differentiate between constants that have the same values but are
represented differently in the source. Values like 1.0 and 1 now end up
as different constants.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::get):
(JSC::DFG::ByteCodeParser::addConstantToGraph):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::registerFrozenValues):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addSpeculationMode):
(JSC::DFG::Graph::addImmediateShouldSpeculateInt32):
ArithAdd is very aggressive toward using Int52, which is quite useful
in many benchmarks.

Here we need to specialize to make sure we don't force our literals
to Int52 if there were represented as double.

There is one exception to that rule: when the other operand is guaranteed
to come from a NodeResultInt32. This is because there is some weird code
doing stuff like:
    var b = a|0;
    var c = b*2.0;

* dfg/DFGNode.h:
(JSC::DFG::Node::Node):
(JSC::DFG::Node::setOpAndDefaultFlags):
(JSC::DFG::Node::sourceCodeRepresentation):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* runtime/JSCJSValue.h:
(JSC::EncodedJSValueWithRepresentationHashTraits::emptyValue):
(JSC::EncodedJSValueWithRepresentationHashTraits::constructDeletedValue):
(JSC::EncodedJSValueWithRepresentationHashTraits::isDeletedValue):
(JSC::EncodedJSValueWithRepresentationHash::hash):
(JSC::EncodedJSValueWithRepresentationHash::equal):
* tests/stress/arith-add-with-constants.js: Added.
* tests/stress/arith-mul-with-constants.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockh">trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonh">trunk/Source/JavaScriptCore/dfg/DFGCommon.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserASTBuilderh">trunk/Source/JavaScriptCore/parser/ASTBuilder.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserLexercpp">trunk/Source/JavaScriptCore/parser/Lexer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodeConstructorsh">trunk/Source/JavaScriptCore/parser/NodeConstructors.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodesh">trunk/Source/JavaScriptCore/parser/Nodes.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParserTokensh">trunk/Source/JavaScriptCore/parser/ParserTokens.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserSyntaxCheckerh">trunk/Source/JavaScriptCore/parser/SyntaxChecker.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueh">trunk/Source/JavaScriptCore/runtime/JSCJSValue.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressarithaddwithconstantsjs">trunk/Source/JavaScriptCore/tests/stress/arith-add-with-constants.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressarithmulwithconstantsjs">trunk/Source/JavaScriptCore/tests/stress/arith-mul-with-constants.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -1,3 +1,160 @@
</span><ins>+2015-02-27  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Use the way number constants are written to help type speculation
+        https://bugs.webkit.org/show_bug.cgi?id=142072
+
+        Reviewed by Filip Pizlo.
+
+        This patch changes how we interpret numeric constant based on how they appear
+        in the source.
+
+        Constants that are integers but written with a decimal point now carry that information
+        to the optimizating tiers. From there, we use that to be more aggressive about typing
+        math operations toward double operations.
+
+        For example, in:
+            var a = x + 1.0;
+            var b = y + 1;
+        The Add for a would be biased toward doubles, the Add for b would speculate
+        integer as usual.
+
+
+        The gains are tiny but this is a prerequisite to make my next patch useful:
+        -SunSpider's access-fannkuch: definitely 1.0661x faster
+        -SunSpider's math-cordic: definitely 1.0266x slower
+            overal: might be 1.0066x slower.
+        -Kraken's imaging-darkroom: definitely 1.0333x faster.
+
+        * parser/Lexer.cpp:
+        (JSC::tokenTypeForIntegerLikeToken):
+        (JSC::Lexer&lt;T&gt;::lex):
+        The lexer now create two types of tokens for number: INTEGER and DOUBLE.
+        Those token types only carry information about how the values were
+        entered, an INTEGER does not have to be an integer, it is only written like one.
+        Large integer still end up represented as double in memory.
+
+        One trap I fell into was typing numbers like 12e3 as double. This kind of literal
+        is frequently used in integer-typed code, while 12.e3 would appear in double-typed
+        code.
+        Because of that, the only signals for double are: decimal point, negative zero,
+        and ridiculously large values.
+
+        * parser/NodeConstructors.h:
+        (JSC::DoubleNode::DoubleNode):
+        (JSC::IntegerNode::IntegerNode):
+        * parser/Nodes.h:
+        (JSC::NumberNode::value):
+        (JSC::NumberNode::setValue): Deleted.
+        Number get specialized in two new kind of nodes in the AST: IntegerNode and DoubleNode.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::NumberNode::emitBytecode):
+
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createDoubleExpr):
+        (JSC::ASTBuilder::createIntegerExpr):
+        (JSC::ASTBuilder::createIntegerLikeNumber):
+        (JSC::ASTBuilder::createDoubleLikeNumber):
+        (JSC::ASTBuilder::createNumberFromBinaryOperation):
+        (JSC::ASTBuilder::createNumberFromUnaryOperation):
+        (JSC::ASTBuilder::makeNegateNode):
+        (JSC::ASTBuilder::makeBitwiseNotNode):
+        (JSC::ASTBuilder::makeMultNode):
+        (JSC::ASTBuilder::makeDivNode):
+        (JSC::ASTBuilder::makeModNode):
+        (JSC::ASTBuilder::makeAddNode):
+        (JSC::ASTBuilder::makeSubNode):
+        (JSC::ASTBuilder::makeLeftShiftNode):
+        (JSC::ASTBuilder::makeRightShiftNode):
+        (JSC::ASTBuilder::makeURightShiftNode):
+        (JSC::ASTBuilder::makeBitOrNode):
+        (JSC::ASTBuilder::makeBitAndNode):
+        (JSC::ASTBuilder::makeBitXOrNode):
+        (JSC::ASTBuilder::createNumberExpr): Deleted.
+        (JSC::ASTBuilder::createNumber): Deleted.
+        The AST has some optimization to resolve constants before emitting bytecode.
+        In the new code, the intger representation is kept if both operands where
+        also represented as integers.
+
+        * parser/Parser.cpp:
+        (JSC::Parser&lt;LexerType&gt;::parseDeconstructionPattern):
+        (JSC::Parser&lt;LexerType&gt;::parseProperty):
+        (JSC::Parser&lt;LexerType&gt;::parseGetterSetter):
+        (JSC::Parser&lt;LexerType&gt;::parsePrimaryExpression):
+        (JSC::Parser&lt;LexerType&gt;::printUnexpectedTokenText):
+        * parser/ParserTokens.h:
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createDoubleExpr):
+        (JSC::SyntaxChecker::createIntegerExpr):
+        (JSC::SyntaxChecker::createNumberExpr): Deleted.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::registerName):
+        (JSC::CodeBlock::constantName):
+        Change constantName(r, getConstant(r)) -&gt; constantName(r) to simplify
+        the dump code.
+
+        (JSC::CodeBlock::dumpBytecode):
+        Dump thre soure representation information we have with each constant.
+
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::shrinkToFit):
+        (JSC::constantName): Deleted.
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::constantsSourceCodeRepresentation):
+        (JSC::CodeBlock::addConstant):
+        (JSC::CodeBlock::addConstantLazily):
+        (JSC::CodeBlock::constantSourceCodeRepresentation):
+        (JSC::CodeBlock::setConstantRegisters):
+
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::addConstant):
+        (JSC::UnlinkedCodeBlock::constantsSourceCodeRepresentation):
+        (JSC::UnlinkedCodeBlock::shrinkToFit):
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::addConstantValue):
+        (JSC::BytecodeGenerator::emitLoad):
+        * bytecompiler/BytecodeGenerator.h:
+        We have to differentiate between constants that have the same values but are
+        represented differently in the source. Values like 1.0 and 1 now end up
+        as different constants.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::get):
+        (JSC::DFG::ByteCodeParser::addConstantToGraph):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::registerFrozenValues):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::addSpeculationMode):
+        (JSC::DFG::Graph::addImmediateShouldSpeculateInt32):
+        ArithAdd is very aggressive toward using Int52, which is quite useful
+        in many benchmarks.
+
+        Here we need to specialize to make sure we don't force our literals
+        to Int52 if there were represented as double.
+
+        There is one exception to that rule: when the other operand is guaranteed
+        to come from a NodeResultInt32. This is because there is some weird code
+        doing stuff like:
+            var b = a|0;
+            var c = b*2.0;
+
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::Node):
+        (JSC::DFG::Node::setOpAndDefaultFlags):
+        (JSC::DFG::Node::sourceCodeRepresentation):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * runtime/JSCJSValue.h:
+        (JSC::EncodedJSValueWithRepresentationHashTraits::emptyValue):
+        (JSC::EncodedJSValueWithRepresentationHashTraits::constructDeletedValue):
+        (JSC::EncodedJSValueWithRepresentationHashTraits::isDeletedValue):
+        (JSC::EncodedJSValueWithRepresentationHash::hash):
+        (JSC::EncodedJSValueWithRepresentationHash::equal):
+        * tests/stress/arith-add-with-constants.js: Added.
+        * tests/stress/arith-mul-with-constants.js: Added.
+
</ins><span class="cx"> 2015-02-26  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, roll out r180723. It broke a bunch of tests.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -172,11 +172,6 @@
</span><span class="cx">     dumpAssumingJITType(out, jitType());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static CString constantName(int k, JSValue value)
-{
-    return toCString(value, &quot;(&quot;, VirtualRegister(k), &quot;)&quot;);
-}
-
</del><span class="cx"> static CString idName(int id0, const Identifier&amp; ident)
</span><span class="cx"> {
</span><span class="cx">     return toCString(ident.impl(), &quot;(@id&quot;, id0, &quot;)&quot;);
</span><span class="lines">@@ -185,11 +180,17 @@
</span><span class="cx"> CString CodeBlock::registerName(int r) const
</span><span class="cx"> {
</span><span class="cx">     if (isConstantRegisterIndex(r))
</span><del>-        return constantName(r, getConstant(r));
</del><ins>+        return constantName(r);
</ins><span class="cx"> 
</span><span class="cx">     return toCString(VirtualRegister(r));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CString CodeBlock::constantName(int index) const
+{
+    JSValue value = getConstant(index);
+    return toCString(value, &quot;(&quot;, VirtualRegister(index), &quot;)&quot;);
+}
+
</ins><span class="cx"> static CString regexpToSourceString(RegExp* regExp)
</span><span class="cx"> {
</span><span class="cx">     char postfix[5] = { '/', 0, 0, 0, 0 };
</span><span class="lines">@@ -606,7 +607,19 @@
</span><span class="cx">         out.printf(&quot;\nConstants:\n&quot;);
</span><span class="cx">         size_t i = 0;
</span><span class="cx">         do {
</span><del>-            out.printf(&quot;   k%u = %s\n&quot;, static_cast&lt;unsigned&gt;(i), toCString(m_constantRegisters[i].get()).data());
</del><ins>+            const char* sourceCodeRepresentationDescription;
+            switch (m_constantsSourceCodeRepresentation[i]) {
+            case SourceCodeRepresentation::Double:
+                sourceCodeRepresentationDescription = &quot;: in source as double&quot;;
+                break;
+            case SourceCodeRepresentation::Integer:
+                sourceCodeRepresentationDescription = &quot;: in source as integer&quot;;
+                break;
+            case SourceCodeRepresentation::Other:
+                sourceCodeRepresentationDescription = &quot;&quot;;
+                break;
+            }
+            out.printf(&quot;   k%u = %s%s\n&quot;, static_cast&lt;unsigned&gt;(i), toCString(m_constantRegisters[i].get()).data(), sourceCodeRepresentationDescription);
</ins><span class="cx">             ++i;
</span><span class="cx">         } while (i &lt; m_constantRegisters.size());
</span><span class="cx">     }
</span><span class="lines">@@ -1449,7 +1462,7 @@
</span><span class="cx">             int k0 = (++it)-&gt;u.operand;
</span><span class="cx">             JSNameScope::Type scopeType = (JSNameScope::Type)(++it)-&gt;u.operand;
</span><span class="cx">             printLocationAndOp(out, exec, location, it, &quot;push_name_scope&quot;);
</span><del>-            out.printf(&quot;%s, %s, %s, %s&quot;, registerName(dst).data(), registerName(r1).data(), constantName(k0, getConstant(k0)).data(), (scopeType == JSNameScope::FunctionNameScope) ? &quot;functionScope&quot; : ((scopeType == JSNameScope::CatchScope) ? &quot;catchScope&quot; : &quot;unknownScopeType&quot;));
</del><ins>+            out.printf(&quot;%s, %s, %s, %s&quot;, registerName(dst).data(), registerName(r1).data(), constantName(k0).data(), (scopeType == JSNameScope::FunctionNameScope) ? &quot;functionScope&quot; : ((scopeType == JSNameScope::CatchScope) ? &quot;catchScope&quot; : &quot;unknownScopeType&quot;));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_catch: {
</span><span class="lines">@@ -1466,7 +1479,7 @@
</span><span class="cx">             int k0 = (++it)-&gt;u.operand;
</span><span class="cx">             int k1 = (++it)-&gt;u.operand;
</span><span class="cx">             printLocationAndOp(out, exec, location, it, &quot;throw_static_error&quot;);
</span><del>-            out.printf(&quot;%s, %s&quot;, constantName(k0, getConstant(k0)).data(), k1 ? &quot;true&quot; : &quot;false&quot;);
</del><ins>+            out.printf(&quot;%s, %s&quot;, constantName(k0).data(), k1 ? &quot;true&quot; : &quot;false&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_debug: {
</span><span class="lines">@@ -1639,6 +1652,7 @@
</span><span class="cx">     , m_firstLineColumnOffset(other.m_firstLineColumnOffset)
</span><span class="cx">     , m_codeType(other.m_codeType)
</span><span class="cx">     , m_constantRegisters(other.m_constantRegisters)
</span><ins>+    , m_constantsSourceCodeRepresentation(other.m_constantsSourceCodeRepresentation)
</ins><span class="cx">     , m_functionDecls(other.m_functionDecls)
</span><span class="cx">     , m_functionExprs(other.m_functionExprs)
</span><span class="cx">     , m_osrExitCounter(0)
</span><span class="lines">@@ -1730,7 +1744,7 @@
</span><span class="cx">     if (vm()-&gt;typeProfiler() || vm()-&gt;controlFlowProfiler())
</span><span class="cx">         vm()-&gt;functionHasExecutedCache()-&gt;removeUnexecutedRange(m_ownerExecutable-&gt;sourceID(), m_ownerExecutable-&gt;typeProfilingStartOffset(), m_ownerExecutable-&gt;typeProfilingEndOffset());
</span><span class="cx"> 
</span><del>-    setConstantRegisters(unlinkedCodeBlock-&gt;constantRegisters());
</del><ins>+    setConstantRegisters(unlinkedCodeBlock-&gt;constantRegisters(), unlinkedCodeBlock-&gt;constantsSourceCodeRepresentation());
</ins><span class="cx">     if (unlinkedCodeBlock-&gt;usesGlobalObject())
</span><span class="cx">         m_constantRegisters[unlinkedCodeBlock-&gt;globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get());
</span><span class="cx">     m_functionDecls.resizeToFit(unlinkedCodeBlock-&gt;numberOfFunctionDecls());
</span><span class="lines">@@ -2980,6 +2994,7 @@
</span><span class="cx">     
</span><span class="cx">     if (shrinkMode == EarlyShrink) {
</span><span class="cx">         m_constantRegisters.shrinkToFit();
</span><ins>+        m_constantsSourceCodeRepresentation.shrinkToFit();
</ins><span class="cx">         
</span><span class="cx">         if (m_rareData) {
</span><span class="cx">             m_rareData-&gt;m_switchJumpTables.shrinkToFit();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -628,12 +628,14 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;WriteBarrier&lt;Unknown&gt;&gt;&amp; constants() { return m_constantRegisters; }
</span><ins>+    Vector&lt;SourceCodeRepresentation&gt;&amp; constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
</ins><span class="cx">     size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
</span><span class="cx">     unsigned addConstant(JSValue v)
</span><span class="cx">     {
</span><span class="cx">         unsigned result = m_constantRegisters.size();
</span><span class="cx">         m_constantRegisters.append(WriteBarrier&lt;Unknown&gt;());
</span><span class="cx">         m_constantRegisters.last().set(m_globalObject-&gt;vm(), m_ownerExecutable.get(), v);
</span><ins>+        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -641,6 +643,7 @@
</span><span class="cx">     {
</span><span class="cx">         unsigned result = m_constantRegisters.size();
</span><span class="cx">         m_constantRegisters.append(WriteBarrier&lt;Unknown&gt;());
</span><ins>+        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -649,6 +652,7 @@
</span><span class="cx">     WriteBarrier&lt;Unknown&gt;&amp; constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
</span><span class="cx">     ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index &gt;= FirstConstantRegisterIndex; }
</span><span class="cx">     ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
</span><ins>+    ALWAYS_INLINE SourceCodeRepresentation constantSourceCodeRepresentation(int index) const { return m_constantsSourceCodeRepresentation[index - FirstConstantRegisterIndex]; }
</ins><span class="cx"> 
</span><span class="cx">     FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
</span><span class="cx">     int numberOfFunctionDecls() { return m_functionDecls.size(); }
</span><span class="lines">@@ -983,12 +987,14 @@
</span><span class="cx"> 
</span><span class="cx">     void updateAllPredictionsAndCountLiveness(unsigned&amp; numberOfLiveNonArgumentValueProfiles, unsigned&amp; numberOfSamplesInProfiles);
</span><span class="cx"> 
</span><del>-    void setConstantRegisters(const Vector&lt;WriteBarrier&lt;Unknown&gt;&gt;&amp; constants)
</del><ins>+    void setConstantRegisters(const Vector&lt;WriteBarrier&lt;Unknown&gt;&gt;&amp; constants, const Vector&lt;SourceCodeRepresentation&gt;&amp; constantsSourceCodeRepresentation)
</ins><span class="cx">     {
</span><ins>+        ASSERT(constants.size() == constantsSourceCodeRepresentation.size());
</ins><span class="cx">         size_t count = constants.size();
</span><span class="cx">         m_constantRegisters.resize(count);
</span><span class="cx">         for (size_t i = 0; i &lt; count; i++)
</span><span class="cx">             m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get());
</span><ins>+        m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void dumpBytecode(
</span><span class="lines">@@ -996,6 +1002,7 @@
</span><span class="cx">         const StubInfoMap&amp; = StubInfoMap(), const CallLinkInfoMap&amp; = CallLinkInfoMap());
</span><span class="cx"> 
</span><span class="cx">     CString registerName(int r) const;
</span><ins>+    CString constantName(int index) const;
</ins><span class="cx">     void printUnaryOp(PrintStream&amp;, ExecState*, int location, const Instruction*&amp;, const char* op);
</span><span class="cx">     void printBinaryOp(PrintStream&amp;, ExecState*, int location, const Instruction*&amp;, const char* op);
</span><span class="cx">     void printConditionalJump(PrintStream&amp;, ExecState*, const Instruction*, const Instruction*&amp;, int location, const char* op);
</span><span class="lines">@@ -1093,6 +1100,7 @@
</span><span class="cx">     // TODO: This could just be a pointer to m_unlinkedCodeBlock's data, but the DFG mutates
</span><span class="cx">     // it, so we're stuck with it for now.
</span><span class="cx">     Vector&lt;WriteBarrier&lt;Unknown&gt;&gt; m_constantRegisters;
</span><ins>+    Vector&lt;SourceCodeRepresentation&gt; m_constantsSourceCodeRepresentation;
</ins><span class="cx">     Vector&lt;WriteBarrier&lt;FunctionExecutable&gt;&gt; m_functionDecls;
</span><span class="cx">     Vector&lt;WriteBarrier&lt;FunctionExecutable&gt;&gt; m_functionExprs;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -318,11 +318,12 @@
</span><span class="cx">     const Vector&lt;Identifier&gt;&amp; identifiers() const { return m_identifiers; }
</span><span class="cx"> 
</span><span class="cx">     size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
</span><del>-    unsigned addConstant(JSValue v)
</del><ins>+    unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
</ins><span class="cx">     {
</span><span class="cx">         unsigned result = m_constantRegisters.size();
</span><span class="cx">         m_constantRegisters.append(WriteBarrier&lt;Unknown&gt;());
</span><span class="cx">         m_constantRegisters.last().set(*m_vm, this, v);
</span><ins>+        m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx">     unsigned addOrFindConstant(JSValue);
</span><span class="lines">@@ -330,6 +331,7 @@
</span><span class="cx">     const WriteBarrier&lt;Unknown&gt;&amp; constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
</span><span class="cx">     ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index &gt;= FirstConstantRegisterIndex; }
</span><span class="cx">     ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
</span><ins>+    const Vector&lt;SourceCodeRepresentation&gt;&amp; constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
</ins><span class="cx"> 
</span><span class="cx">     // Jumps
</span><span class="cx">     size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
</span><span class="lines">@@ -347,6 +349,7 @@
</span><span class="cx">         m_jumpTargets.shrinkToFit();
</span><span class="cx">         m_identifiers.shrinkToFit();
</span><span class="cx">         m_constantRegisters.shrinkToFit();
</span><ins>+        m_constantsSourceCodeRepresentation.shrinkToFit();
</ins><span class="cx">         m_functionDecls.shrinkToFit();
</span><span class="cx">         m_functionExprs.shrinkToFit();
</span><span class="cx">         m_propertyAccessInstructions.shrinkToFit();
</span><span class="lines">@@ -544,6 +547,7 @@
</span><span class="cx">     // Constant Pools
</span><span class="cx">     Vector&lt;Identifier&gt; m_identifiers;
</span><span class="cx">     Vector&lt;WriteBarrier&lt;Unknown&gt;&gt; m_constantRegisters;
</span><ins>+    Vector&lt;SourceCodeRepresentation&gt; m_constantsSourceCodeRepresentation;
</ins><span class="cx">     typedef Vector&lt;WriteBarrier&lt;UnlinkedFunctionExecutable&gt;&gt; FunctionExpressionVector;
</span><span class="cx">     FunctionExpressionVector m_functionDecls;
</span><span class="cx">     FunctionExpressionVector m_functionExprs;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -979,17 +979,19 @@
</span><span class="cx">     return m_emptyValueRegister;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::addConstantValue(JSValue v)
</del><ins>+RegisterID* BytecodeGenerator::addConstantValue(JSValue v, SourceCodeRepresentation sourceCodeRepresentation)
</ins><span class="cx"> {
</span><span class="cx">     if (!v)
</span><span class="cx">         return addConstantEmptyValue();
</span><span class="cx"> 
</span><span class="cx">     int index = m_nextConstantOffset;
</span><del>-    JSValueMap::AddResult result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset);
</del><ins>+
+    EncodedJSValueWithRepresentation valueMapKey { JSValue::encode(v), sourceCodeRepresentation };
+    JSValueMap::AddResult result = m_jsValueMap.add(valueMapKey, m_nextConstantOffset);
</ins><span class="cx">     if (result.isNewEntry) {
</span><span class="cx">         m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
</span><span class="cx">         ++m_nextConstantOffset;
</span><del>-        m_codeBlock-&gt;addConstant(v);
</del><ins>+        m_codeBlock-&gt;addConstant(v, sourceCodeRepresentation);
</ins><span class="cx">     } else
</span><span class="cx">         index = result.iterator-&gt;value;
</span><span class="cx">     return &amp;m_constantPoolRegisters[index];
</span><span class="lines">@@ -1162,9 +1164,9 @@
</span><span class="cx">     return emitLoad(dst, JSValue(stringInMap));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
</del><ins>+RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v, SourceCodeRepresentation sourceCodeRepresentation)
</ins><span class="cx"> {
</span><del>-    RegisterID* constantID = addConstantValue(v);
</del><ins>+    RegisterID* constantID = addConstantValue(v, sourceCodeRepresentation);
</ins><span class="cx">     if (dst)
</span><span class="cx">         return emitMove(dst, constantID);
</span><span class="cx">     return constantID;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -443,7 +443,7 @@
</span><span class="cx"> 
</span><span class="cx">         RegisterID* emitLoad(RegisterID* dst, bool);
</span><span class="cx">         RegisterID* emitLoad(RegisterID* dst, const Identifier&amp;);
</span><del>-        RegisterID* emitLoad(RegisterID* dst, JSValue);
</del><ins>+        RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
</ins><span class="cx">         RegisterID* emitLoadGlobalObject(RegisterID* dst);
</span><span class="cx"> 
</span><span class="cx">         RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
</span><span class="lines">@@ -646,7 +646,7 @@
</span><span class="cx"> 
</span><span class="cx">         bool hasConstant(const Identifier&amp;) const;
</span><span class="cx">         unsigned addConstant(const Identifier&amp;);
</span><del>-        RegisterID* addConstantValue(JSValue);
</del><ins>+        RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
</ins><span class="cx">         RegisterID* addConstantEmptyValue();
</span><span class="cx">         unsigned addRegExp(RegExp*);
</span><span class="cx"> 
</span><span class="lines">@@ -792,6 +792,8 @@
</span><span class="cx">         
</span><span class="cx">         // Constant pool
</span><span class="cx">         IdentifierMap m_identifierMap;
</span><ins>+
+        typedef HashMap&lt;EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits&gt; JSValueMap;
</ins><span class="cx">         JSValueMap m_jsValueMap;
</span><span class="cx">         IdentifierStringMap m_stringMap;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -122,6 +122,15 @@
</span><span class="cx">     return generator.addStringConstant(m_value);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// ------------------------------ NumberNode ----------------------------------
+
+RegisterID* NumberNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst)
+{
+    if (dst == generator.ignoredResult())
+        return nullptr;
+    return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double);
+}
+
</ins><span class="cx"> // ------------------------------ RegExpNode -----------------------------------
</span><span class="cx"> 
</span><span class="cx"> RegisterID* RegExpNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">     template&lt;int power&gt;
</span><span class="cx">     bool isWithinPowerOfTwoNonRecursive(Node* node)
</span><span class="cx">     {
</span><del>-        if (node-&gt;op() != JSConstant)
</del><ins>+        if (!node-&gt;isNumberConstant())
</ins><span class="cx">             return false;
</span><span class="cx">         return isWithinPowerOfTwoForConstant&lt;power&gt;(node);
</span><span class="cx">     }
</span><span class="lines">@@ -104,7 +104,9 @@
</span><span class="cx">     bool isWithinPowerOfTwo(Node* node)
</span><span class="cx">     {
</span><span class="cx">         switch (node-&gt;op()) {
</span><del>-        case JSConstant: {
</del><ins>+        case DoubleConstant:
+        case JSConstant:
+        case Int52Constant: {
</ins><span class="cx">             return isWithinPowerOfTwoForConstant&lt;power&gt;(node);
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="lines">@@ -128,7 +130,7 @@
</span><span class="cx">                 return true;
</span><span class="cx">             
</span><span class="cx">             Node* shiftAmount = node-&gt;child2().node();
</span><del>-            if (shiftAmount-&gt;op() != JSConstant)
</del><ins>+            if (!node-&gt;isNumberConstant())
</ins><span class="cx">                 return false;
</span><span class="cx">             JSValue immediateValue = shiftAmount-&gt;asJSValue();
</span><span class="cx">             if (!immediateValue.isInt32())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -252,14 +252,21 @@
</span><span class="cx">             unsigned constantIndex = operand.toConstantIndex();
</span><span class="cx">             unsigned oldSize = m_constants.size();
</span><span class="cx">             if (constantIndex &gt;= oldSize || !m_constants[constantIndex]) {
</span><del>-                JSValue value = m_inlineStackTop-&gt;m_codeBlock-&gt;getConstant(operand.offset());
</del><ins>+                const CodeBlock&amp; codeBlock = *m_inlineStackTop-&gt;m_codeBlock;
+                JSValue value = codeBlock.getConstant(operand.offset());
+                SourceCodeRepresentation sourceCodeRepresentation = codeBlock.constantSourceCodeRepresentation(operand.offset());
</ins><span class="cx">                 if (constantIndex &gt;= oldSize) {
</span><span class="cx">                     m_constants.grow(constantIndex + 1);
</span><span class="cx">                     for (unsigned i = oldSize; i &lt; m_constants.size(); ++i)
</span><span class="cx">                         m_constants[i] = nullptr;
</span><span class="cx">                 }
</span><del>-                m_constants[constantIndex] =
-                    addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value)));
</del><ins>+
+                Node* constantNode = nullptr;
+                if (sourceCodeRepresentation == SourceCodeRepresentation::Double)
+                    constantNode = addToGraph(DoubleConstant, OpInfo(m_graph.freezeStrong(jsDoubleNumber(value.asNumber()))));
+                else
+                    constantNode = addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value)));
+                m_constants[constantIndex] = constantNode;
</ins><span class="cx">             }
</span><span class="cx">             ASSERT(m_constants[constantIndex]);
</span><span class="cx">             return m_constants[constantIndex];
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommon.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -256,6 +256,11 @@
</span><span class="cx">     return doesKill ? DoesKill : DoesNotKill;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+enum class PlanStage {
+    Initial,
+    AfterFixup
+};
+
</ins><span class="cx"> template&lt;typename T, typename U&gt;
</span><span class="cx"> bool checkAndSet(T&amp; left, U right)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -67,7 +67,9 @@
</span><span class="cx">         
</span><span class="cx">         for (BlockIndex blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex)
</span><span class="cx">             injectTypeConversionsInBlock(m_graph.block(blockIndex));
</span><del>-        
</del><ins>+
+        m_graph.m_planStage = PlanStage::AfterFixup;
+
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1056,7 +1058,6 @@
</span><span class="cx">         case DoubleRep:
</span><span class="cx">         case ValueRep:
</span><span class="cx">         case Int52Rep:
</span><del>-        case DoubleConstant:
</del><span class="cx">         case Int52Constant:
</span><span class="cx">         case Identity: // This should have been cleaned up.
</span><span class="cx">         case BooleanToNumber:
</span><span class="lines">@@ -1219,6 +1220,7 @@
</span><span class="cx">         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
</span><span class="cx">         case SetArgument:
</span><span class="cx">         case JSConstant:
</span><ins>+        case DoubleConstant:
</ins><span class="cx">         case GetLocal:
</span><span class="cx">         case GetCallee:
</span><span class="cx">         case Flush:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -1053,6 +1053,7 @@
</span><span class="cx"> void Graph::registerFrozenValues()
</span><span class="cx"> {
</span><span class="cx">     m_codeBlock-&gt;constants().resize(0);
</span><ins>+    m_codeBlock-&gt;constantsSourceCodeRepresentation().resize(0);
</ins><span class="cx">     for (FrozenValue* value : m_frozenValues) {
</span><span class="cx">         if (value-&gt;structure())
</span><span class="cx">             ASSERT(m_plan.weakReferences.contains(value-&gt;structure()));
</span><span class="lines">@@ -1078,6 +1079,7 @@
</span><span class="cx">         } }
</span><span class="cx">     }
</span><span class="cx">     m_codeBlock-&gt;constants().shrinkToFit();
</span><ins>+    m_codeBlock-&gt;constantsSourceCodeRepresentation().shrinkToFit();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Graph::visitChildren(SlotVisitor&amp; visitor)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -217,9 +217,9 @@
</span><span class="cx">         Node* right = add-&gt;child2().node();
</span><span class="cx">         
</span><span class="cx">         if (left-&gt;hasConstant())
</span><del>-            return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source);
</del><ins>+            return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, right, left, source);
</ins><span class="cx">         if (right-&gt;hasConstant())
</span><del>-            return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source);
</del><ins>+            return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, left, right, source);
</ins><span class="cx">         
</span><span class="cx">         return (leftShouldSpeculateInt32 &amp;&amp; rightShouldSpeculateInt32 &amp;&amp; add-&gt;canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32;
</span><span class="cx">     }
</span><span class="lines">@@ -846,12 +846,13 @@
</span><span class="cx">     StructureRegistrationState m_structureRegistrationState;
</span><span class="cx">     GraphForm m_form;
</span><span class="cx">     UnificationState m_unificationState;
</span><ins>+    PlanStage m_planStage { PlanStage::Initial };
</ins><span class="cx">     RefCountState m_refCountState;
</span><span class="cx"> private:
</span><span class="cx">     
</span><span class="cx">     void handleSuccessor(Vector&lt;BasicBlock*, 16&gt;&amp; worklist, BasicBlock*, BasicBlock* successor);
</span><span class="cx">     
</span><del>-    AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source)
</del><ins>+    AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* operand, Node*immediate, RareCaseProfilingSource source)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(immediate-&gt;hasConstant());
</span><span class="cx">         
</span><span class="lines">@@ -861,8 +862,14 @@
</span><span class="cx">         
</span><span class="cx">         if (!variableShouldSpeculateInt32)
</span><span class="cx">             return DontSpeculateInt32;
</span><ins>+
+        // Integer constants can be typed Double if they are written like a double in the source code (e.g. 42.0).
+        // In that case, we stay conservative unless the other operand was explicitly typed as integer.
+        NodeFlags operandResultType = operand-&gt;result();
+        if (operandResultType != NodeResultInt32 &amp;&amp; immediateValue.isDouble())
+            return DontSpeculateInt32;
</ins><span class="cx">         
</span><del>-        if (immediateValue.isInt32() || immediateValue.isBoolean())
</del><ins>+        if (jsNumber(immediateValue.asNumber()).isInt32() || immediateValue.isBoolean())
</ins><span class="cx">             return add-&gt;canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32;
</span><span class="cx">         
</span><span class="cx">         double doubleImmediate = immediateValue.asDouble();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -148,6 +148,11 @@
</span><span class="cx">             changed |= setPrediction(type);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+        case DoubleConstant: {
+            SpeculatedType type = speculationFromValue(node-&gt;asJSValue());
+            changed |= setPrediction(type);
+            break;
+        }
</ins><span class="cx">             
</span><span class="cx">         case GetLocal: {
</span><span class="cx">             VariableAccessData* variable = node-&gt;variableAccessData();
</span><span class="lines">@@ -532,7 +537,6 @@
</span><span class="cx">         case DoubleRep:
</span><span class="cx">         case ValueRep:
</span><span class="cx">         case Int52Rep:
</span><del>-        case DoubleConstant:
</del><span class="cx">         case Int52Constant:
</span><span class="cx">         case Identity:
</span><span class="cx">         case BooleanToNumber:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -118,8 +118,8 @@
</span><span class="cx">                         continue;
</span><span class="cx">                     
</span><span class="cx">                     m_myRefCounts.find(edge.node())-&gt;value++;
</span><del>-                    
-                    VALIDATE((node, edge), edge-&gt;hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse));
</del><ins>+
+                    validateEdgeWithDoubleResultIfNecessary(node, edge);
</ins><span class="cx">                     VALIDATE((node, edge), edge-&gt;hasInt52Result() == (edge.useKind() == Int52RepUse));
</span><span class="cx">                     
</span><span class="cx">                     if (m_graph.m_form == SSA) {
</span><span class="lines">@@ -543,7 +543,18 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge)
+    {
+        if (!edge-&gt;hasDoubleResult())
+            return;
+
+        if (m_graph.m_planStage &lt; PlanStage::AfterFixup)
+            VALIDATE((node, edge), edge.useKind() == UntypedUse);
+        else
+            VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse);
+    }
+
</ins><span class="cx">     void checkOperand(
</span><span class="cx">         BasicBlock* block, Operands&lt;size_t&gt;&amp; getLocalPositions,
</span><span class="cx">         Operands&lt;size_t&gt;&amp; setLocalPositions, VirtualRegister operand)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserASTBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ASTBuilder.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -192,11 +192,16 @@
</span><span class="cx">             incConstants();
</span><span class="cx">         return new (m_parserArena) ArrayNode(location, elisions, elems);
</span><span class="cx">     }
</span><del>-    ExpressionNode* createNumberExpr(const JSTokenLocation&amp; location, double d)
</del><ins>+    ExpressionNode* createDoubleExpr(const JSTokenLocation&amp; location, double d)
</ins><span class="cx">     {
</span><span class="cx">         incConstants();
</span><del>-        return new (m_parserArena) NumberNode(location, d);
</del><ins>+        return new (m_parserArena) DoubleNode(location, d);
</ins><span class="cx">     }
</span><ins>+    ExpressionNode* createIntegerExpr(const JSTokenLocation&amp; location, double d)
+    {
+        incConstants();
+        return new (m_parserArena) IntegerNode(location, d);
+    }
</ins><span class="cx"> 
</span><span class="cx">     ExpressionNode* createString(const JSTokenLocation&amp; location, const Identifier* string)
</span><span class="cx">     {
</span><span class="lines">@@ -748,11 +753,27 @@
</span><span class="cx">         m_evalCount++;
</span><span class="cx">         m_scope.m_features |= EvalFeature;
</span><span class="cx">     }
</span><del>-    ExpressionNode* createNumber(const JSTokenLocation&amp; location, double d)
</del><ins>+    ExpressionNode* createIntegerLikeNumber(const JSTokenLocation&amp; location, double d)
</ins><span class="cx">     {
</span><del>-        return new (m_parserArena) NumberNode(location, d);
</del><ins>+        return new (m_parserArena) IntegerNode(location, d);
</ins><span class="cx">     }
</span><del>-    
</del><ins>+    ExpressionNode* createDoubleLikeNumber(const JSTokenLocation&amp; location, double d)
+    {
+        return new (m_parserArena) DoubleNode(location, d);
+    }
+    ExpressionNode* createNumberFromBinaryOperation(const JSTokenLocation&amp; location, double value, const NumberNode&amp; originalNodeA, const NumberNode&amp; originalNodeB)
+    {
+        if (originalNodeA.isIntegerNode() &amp;&amp; originalNodeB.isIntegerNode())
+            return createIntegerLikeNumber(location, value);
+        return createDoubleLikeNumber(location, value);
+    }
+    ExpressionNode* createNumberFromUnaryOperation(const JSTokenLocation&amp; location, double value, const NumberNode&amp; originalNode)
+    {
+        if (originalNode.isIntegerNode())
+            return createIntegerLikeNumber(location, value);
+        return createDoubleLikeNumber(location, value);
+    }
+
</ins><span class="cx">     VM* m_vm;
</span><span class="cx">     ParserArena&amp; m_parserArena;
</span><span class="cx">     SourceCode* m_sourceCode;
</span><span class="lines">@@ -793,9 +814,8 @@
</span><span class="cx"> ExpressionNode* ASTBuilder::makeNegateNode(const JSTokenLocation&amp; location, ExpressionNode* n)
</span><span class="cx"> {
</span><span class="cx">     if (n-&gt;isNumber()) {
</span><del>-        NumberNode* numberNode = static_cast&lt;NumberNode*&gt;(n);
-        numberNode-&gt;setValue(-numberNode-&gt;value());
-        return numberNode;
</del><ins>+        const NumberNode&amp; numberNode = static_cast&lt;const NumberNode&amp;&gt;(*n);
+        return createNumberFromUnaryOperation(location, -numberNode.value(), numberNode);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return new (m_parserArena) NegateNode(location, n);
</span><span class="lines">@@ -804,7 +824,7 @@
</span><span class="cx"> ExpressionNode* ASTBuilder::makeBitwiseNotNode(const JSTokenLocation&amp; location, ExpressionNode* expr)
</span><span class="cx"> {
</span><span class="cx">     if (expr-&gt;isNumber())
</span><del>-        return createNumber(location, ~toInt32(static_cast&lt;NumberNode*&gt;(expr)-&gt;value()));
</del><ins>+        return createIntegerLikeNumber(location, ~toInt32(static_cast&lt;NumberNode*&gt;(expr)-&gt;value()));
</ins><span class="cx">     return new (m_parserArena) BitwiseNotNode(location, expr);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -813,8 +833,11 @@
</span><span class="cx">     expr1 = expr1-&gt;stripUnaryPlus();
</span><span class="cx">     expr2 = expr2-&gt;stripUnaryPlus();
</span><span class="cx"> 
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, static_cast&lt;NumberNode*&gt;(expr1)-&gt;value() * static_cast&lt;NumberNode*&gt;(expr2)-&gt;value());
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createNumberFromBinaryOperation(location, numberExpr1.value() * numberExpr2.value(), numberExpr1, numberExpr2);
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (expr1-&gt;isNumber() &amp;&amp; static_cast&lt;NumberNode*&gt;(expr1)-&gt;value() == 1)
</span><span class="cx">         return new (m_parserArena) UnaryPlusNode(location, expr2);
</span><span class="lines">@@ -830,8 +853,14 @@
</span><span class="cx">     expr1 = expr1-&gt;stripUnaryPlus();
</span><span class="cx">     expr2 = expr2-&gt;stripUnaryPlus();
</span><span class="cx"> 
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, static_cast&lt;NumberNode*&gt;(expr1)-&gt;value() / static_cast&lt;NumberNode*&gt;(expr2)-&gt;value());
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        double result = numberExpr1.value() / numberExpr2.value();
+        if (static_cast&lt;int64_t&gt;(result) == result)
+            return createNumberFromBinaryOperation(location, result, numberExpr1, numberExpr2);
+        return createDoubleLikeNumber(location, result);
+    }
</ins><span class="cx">     return new (m_parserArena) DivNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -839,16 +868,23 @@
</span><span class="cx"> {
</span><span class="cx">     expr1 = expr1-&gt;stripUnaryPlus();
</span><span class="cx">     expr2 = expr2-&gt;stripUnaryPlus();
</span><del>-    
-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, fmod(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value(), static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()));
</del><ins>+
+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, fmod(numberExpr1.value(), numberExpr2.value()));
+    }
</ins><span class="cx">     return new (m_parserArena) ModNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeAddNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, static_cast&lt;NumberNode*&gt;(expr1)-&gt;value() + static_cast&lt;NumberNode*&gt;(expr2)-&gt;value());
</del><ins>+
+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createNumberFromBinaryOperation(location, numberExpr1.value() + numberExpr2.value(), numberExpr1, numberExpr2);
+    }
</ins><span class="cx">     return new (m_parserArena) AddNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -857,50 +893,71 @@
</span><span class="cx">     expr1 = expr1-&gt;stripUnaryPlus();
</span><span class="cx">     expr2 = expr2-&gt;stripUnaryPlus();
</span><span class="cx"> 
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, static_cast&lt;NumberNode*&gt;(expr1)-&gt;value() - static_cast&lt;NumberNode*&gt;(expr2)-&gt;value());
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createNumberFromBinaryOperation(location, numberExpr1.value() - numberExpr2.value(), numberExpr1, numberExpr2);
+    }
</ins><span class="cx">     return new (m_parserArena) SubNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeLeftShiftNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) &lt;&lt; (toUInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()) &amp; 0x1f));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) &lt;&lt; (toUInt32(numberExpr2.value()) &amp; 0x1f));
+    }
</ins><span class="cx">     return new (m_parserArena) LeftShiftNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeRightShiftNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) &gt;&gt; (toUInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()) &amp; 0x1f));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) &gt;&gt; (toUInt32(numberExpr2.value()) &amp; 0x1f));
+    }
</ins><span class="cx">     return new (m_parserArena) RightShiftNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeURightShiftNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toUInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) &gt;&gt; (toUInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()) &amp; 0x1f));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toUInt32(numberExpr1.value()) &gt;&gt; (toUInt32(numberExpr2.value()) &amp; 0x1f));
+    }
</ins><span class="cx">     return new (m_parserArena) UnsignedRightShiftNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeBitOrNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) | toInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) | toInt32(numberExpr2.value()));
+    }
</ins><span class="cx">     return new (m_parserArena) BitOrNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeBitAndNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) &amp; toInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) &amp; toInt32(numberExpr2.value()));
+    }
</ins><span class="cx">     return new (m_parserArena) BitAndNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ExpressionNode* ASTBuilder::makeBitXOrNode(const JSTokenLocation&amp; location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
</span><span class="cx"> {
</span><del>-    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber())
-        return createNumber(location, toInt32(static_cast&lt;NumberNode*&gt;(expr1)-&gt;value()) ^ toInt32(static_cast&lt;NumberNode*&gt;(expr2)-&gt;value()));
</del><ins>+    if (expr1-&gt;isNumber() &amp;&amp; expr2-&gt;isNumber()) {
+        const NumberNode&amp; numberExpr1 = static_cast&lt;NumberNode&amp;&gt;(*expr1);
+        const NumberNode&amp; numberExpr2 = static_cast&lt;NumberNode&amp;&gt;(*expr2);
+        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) ^ toInt32(numberExpr2.value()));
+    }
</ins><span class="cx">     return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserLexercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Lexer.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Lexer.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/Lexer.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -495,6 +495,13 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline JSTokenType tokenTypeForIntegerLikeToken(double doubleValue)
+{
+    if ((doubleValue || !std::signbit(doubleValue)) &amp;&amp; static_cast&lt;int64_t&gt;(doubleValue) == doubleValue)
+        return INTEGER;
+    return DOUBLE;
+}
+
</ins><span class="cx"> template &lt;typename T&gt;
</span><span class="cx"> Lexer&lt;T&gt;::~Lexer()
</span><span class="cx"> {
</span><span class="lines">@@ -1687,7 +1694,7 @@
</span><span class="cx">                 token = INVALID_HEX_NUMBER_ERRORTOK;
</span><span class="cx">                 goto returnError;
</span><span class="cx">             }
</span><del>-            token = NUMBER;
</del><ins>+            token = tokenTypeForIntegerLikeToken(tokenData-&gt;doubleValue);
</ins><span class="cx">             m_buffer8.resize(0);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -1700,17 +1707,19 @@
</span><span class="cx">         }
</span><span class="cx">         if (isASCIIOctalDigit(m_current)) {
</span><span class="cx">             if (parseOctal(tokenData-&gt;doubleValue)) {
</span><del>-                token = NUMBER;
</del><ins>+                token = tokenTypeForIntegerLikeToken(tokenData-&gt;doubleValue);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         FALLTHROUGH;
</span><span class="cx">     case CharacterNumber:
</span><del>-        if (LIKELY(token != NUMBER)) {
</del><ins>+        if (LIKELY(token != INTEGER &amp;&amp; token != DOUBLE)) {
</ins><span class="cx">             if (!parseDecimal(tokenData-&gt;doubleValue)) {
</span><ins>+                token = INTEGER;
</ins><span class="cx">                 if (m_current == '.') {
</span><span class="cx">                     shift();
</span><span class="cx"> inNumberAfterDecimalPoint:
</span><span class="cx">                     parseNumberAfterDecimalPoint();
</span><ins>+                    token = DOUBLE;
</ins><span class="cx">                 }
</span><span class="cx">                 if ((m_current | 0x20) == 'e') {
</span><span class="cx">                     if (!parseNumberAfterExponentIndicator()) {
</span><span class="lines">@@ -1721,8 +1730,10 @@
</span><span class="cx">                 }
</span><span class="cx">                 size_t parsedLength;
</span><span class="cx">                 tokenData-&gt;doubleValue = parseDouble(m_buffer8.data(), m_buffer8.size(), parsedLength);
</span><del>-            }
-            token = NUMBER;
</del><ins>+                if (token == INTEGER)
+                    token = tokenTypeForIntegerLikeToken(tokenData-&gt;doubleValue);
+            } else
+                token = tokenTypeForIntegerLikeToken(tokenData-&gt;doubleValue);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // No identifiers allowed directly after numeric literal, e.g. &quot;3in&quot; is bad.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodeConstructorsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/NodeConstructors.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -84,6 +84,16 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    inline DoubleNode::DoubleNode(const JSTokenLocation&amp; location, double value)
+        : NumberNode(location, value)
+    {
+    }
+
+    inline IntegerNode::IntegerNode(const JSTokenLocation&amp; location, double value)
+        : DoubleNode(location, value)
+    {
+    }
+
</ins><span class="cx">     inline StringNode::StringNode(const JSTokenLocation&amp; location, const Identifier&amp; value)
</span><span class="cx">         : ConstantNode(location, ResultType::stringType())
</span><span class="cx">         , m_value(value)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Nodes.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Nodes.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/Nodes.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -236,16 +236,32 @@
</span><span class="cx">     class NumberNode : public ConstantNode {
</span><span class="cx">     public:
</span><span class="cx">         NumberNode(const JSTokenLocation&amp;, double value);
</span><del>-        double value() { return m_value; }
-        void setValue(double value) { m_value = value; }
</del><ins>+        double value() const { return m_value; }
+        virtual bool isIntegerNode() const = 0;
+        virtual RegisterID* emitBytecode(BytecodeGenerator&amp;, RegisterID* = 0) override final;
</ins><span class="cx"> 
</span><span class="cx">     private:
</span><del>-        virtual bool isNumber() const override { return true; }
</del><ins>+        virtual bool isNumber() const override final { return true; }
</ins><span class="cx">         virtual JSValue jsValue(BytecodeGenerator&amp;) const override { return jsNumber(m_value); }
</span><span class="cx"> 
</span><span class="cx">         double m_value;
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    class DoubleNode : public NumberNode {
+    public:
+        DoubleNode(const JSTokenLocation&amp;, double value);
+
+    private:
+        virtual bool isIntegerNode() const override { return false; }
+    };
+
+    // An integer node represent a number represented as an integer (e.g. 42 instead of 42., 42.0, 42e0)
+    class IntegerNode : public DoubleNode {
+    public:
+        IntegerNode(const JSTokenLocation&amp;, double value);
+        virtual bool isIntegerNode() const override final { return true; }
+    };
+
</ins><span class="cx">     class StringNode : public ConstantNode {
</span><span class="cx">     public:
</span><span class="cx">         StringNode(const JSTokenLocation&amp;, const Identifier&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -629,7 +629,8 @@
</span><span class="cx">             } else {
</span><span class="cx">                 JSTokenType tokenType = m_token.m_type;
</span><span class="cx">                 switch (m_token.m_type) {
</span><del>-                case NUMBER:
</del><ins>+                case DOUBLE:
+                case INTEGER:
</ins><span class="cx">                     propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue);
</span><span class="cx">                     break;
</span><span class="cx">                 case STRING:
</span><span class="lines">@@ -1945,7 +1946,8 @@
</span><span class="cx">             failWithMessage(&quot;Expected a ':' following the property name '&quot;, ident-&gt;impl(), &quot;'&quot;);
</span><span class="cx">         return parseGetterSetter(context, complete, type, getterOrSetterStartOffset);
</span><span class="cx">     }
</span><del>-    case NUMBER: {
</del><ins>+    case DOUBLE:
+    case INTEGER: {
</ins><span class="cx">         double propertyName = m_token.m_data.doubleValue;
</span><span class="cx">         next();
</span><span class="cx">         consumeOrFail(COLON, &quot;Expected ':' after property name&quot;);
</span><span class="lines">@@ -1979,7 +1981,7 @@
</span><span class="cx">     double numericPropertyName = 0;
</span><span class="cx">     if (m_token.m_type == IDENT || m_token.m_type == STRING)
</span><span class="cx">         stringPropertyName = m_token.m_data.ident;
</span><del>-    else if (m_token.m_type == NUMBER)
</del><ins>+    else if (m_token.m_type == DOUBLE || m_token.m_type == INTEGER)
</ins><span class="cx">         numericPropertyName = m_token.m_data.doubleValue;
</span><span class="cx">     else
</span><span class="cx">         failDueToUnexpectedToken();
</span><span class="lines">@@ -2221,12 +2223,18 @@
</span><span class="cx">         next();
</span><span class="cx">         return context.createString(location, ident);
</span><span class="cx">     }
</span><del>-    case NUMBER: {
</del><ins>+    case DOUBLE: {
</ins><span class="cx">         double d = m_token.m_data.doubleValue;
</span><span class="cx">         JSTokenLocation location(tokenLocation());
</span><span class="cx">         next();
</span><del>-        return context.createNumberExpr(location, d);
</del><ins>+        return context.createDoubleExpr(location, d);
</ins><span class="cx">     }
</span><ins>+    case INTEGER: {
+        double d = m_token.m_data.doubleValue;
+        JSTokenLocation location(tokenLocation());
+        next();
+        return context.createIntegerExpr(location, d);
+    }
</ins><span class="cx">     case NULLTOKEN: {
</span><span class="cx">         JSTokenLocation location(tokenLocation());
</span><span class="cx">         next();
</span><span class="lines">@@ -2577,7 +2585,8 @@
</span><span class="cx">     case STRING:
</span><span class="cx">         out.print(&quot;Unexpected string literal &quot;, getToken());
</span><span class="cx">         return;
</span><del>-    case NUMBER:
</del><ins>+    case INTEGER:
+    case DOUBLE:
</ins><span class="cx">         out.print(&quot;Unexpected number '&quot;, getToken(), &quot;'&quot;);
</span><span class="cx">         return;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserTokensh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ParserTokens.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ParserTokens.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/ParserTokens.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -94,7 +94,8 @@
</span><span class="cx">     CLOSEBRACKET,
</span><span class="cx">     COMMA,
</span><span class="cx">     QUESTION,
</span><del>-    NUMBER,
</del><ins>+    INTEGER,
+    DOUBLE,
</ins><span class="cx">     IDENT,
</span><span class="cx">     STRING,
</span><span class="cx">     SEMICOLON,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserSyntaxCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/SyntaxChecker.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -71,7 +71,7 @@
</span><span class="cx"> 
</span><span class="cx">     typedef SyntaxChecker FunctionBodyBuilder;
</span><span class="cx">     enum { NoneExpr = 0,
</span><del>-        ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,
</del><ins>+        ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
</ins><span class="cx">         ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
</span><span class="cx">         FunctionExpr, ClassExpr, BracketExpr, DotExpr, CallExpr,
</span><span class="cx">         NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
</span><span class="lines">@@ -151,7 +151,8 @@
</span><span class="cx">     ExpressionType createObjectLiteral(const JSTokenLocation&amp;, int) { return ObjectLiteralExpr; }
</span><span class="cx">     ExpressionType createArray(const JSTokenLocation&amp;, int) { return ArrayLiteralExpr; }
</span><span class="cx">     ExpressionType createArray(const JSTokenLocation&amp;, int, int) { return ArrayLiteralExpr; }
</span><del>-    ExpressionType createNumberExpr(const JSTokenLocation&amp;, double) { return NumberExpr; }
</del><ins>+    ExpressionType createDoubleExpr(const JSTokenLocation&amp;, double) { return DoubleExpr; }
+    ExpressionType createIntegerExpr(const JSTokenLocation&amp;, double) { return IntegerExpr; }
</ins><span class="cx">     ExpressionType createString(const JSTokenLocation&amp;, const Identifier*) { return StringExpr; }
</span><span class="cx">     ExpressionType createBoolean(const JSTokenLocation&amp;, bool) { return BoolExpr; }
</span><span class="cx">     ExpressionType createNull(const JSTokenLocation&amp;) { return NullExpr; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.h (180812 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2015-02-28 03:16:25 UTC (rev 180812)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -124,8 +124,15 @@
</span><span class="cx"> int64_t tryConvertToInt52(double);
</span><span class="cx"> bool isInt52(double);
</span><span class="cx"> 
</span><ins>+enum class SourceCodeRepresentation {
+    Other,
+    Integer,
+    Double
+};
+
</ins><span class="cx"> class JSValue {
</span><span class="cx">     friend struct EncodedJSValueHashTraits;
</span><ins>+    friend struct EncodedJSValueWithRepresentationHashTraits;
</ins><span class="cx">     friend class AssemblyHelpers;
</span><span class="cx">     friend class JIT;
</span><span class="cx">     friend class JITSlowPathCall;
</span><span class="lines">@@ -448,8 +455,27 @@
</span><span class="cx"> };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-typedef HashMap&lt;EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits&gt; JSValueMap;
</del><ins>+typedef std::pair&lt;EncodedJSValue, SourceCodeRepresentation&gt; EncodedJSValueWithRepresentation;
</ins><span class="cx"> 
</span><ins>+struct EncodedJSValueWithRepresentationHashTraits : HashTraits&lt;EncodedJSValueWithRepresentation&gt; {
+    static const bool emptyValueIsZero = false;
+    static EncodedJSValueWithRepresentation emptyValue() { return std::make_pair(JSValue::encode(JSValue()), SourceCodeRepresentation::Other); }
+    static void constructDeletedValue(EncodedJSValueWithRepresentation&amp; slot) { slot = std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
+    static bool isDeletedValue(EncodedJSValueWithRepresentation value) { return value == std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
+};
+
+struct EncodedJSValueWithRepresentationHash {
+    static unsigned hash(const EncodedJSValueWithRepresentation&amp; value)
+    {
+        return WTF::pairIntHash(EncodedJSValueHash::hash(value.first), IntHash&lt;SourceCodeRepresentation&gt;::hash(value.second));
+    }
+    static bool equal(const EncodedJSValueWithRepresentation&amp; a, const EncodedJSValueWithRepresentation&amp; b)
+    {
+        return a == b;
+    }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
</ins><span class="cx"> // Stand-alone helper functions.
</span><span class="cx"> inline JSValue jsNull()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressarithaddwithconstantsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/arith-add-with-constants.js (0 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/arith-add-with-constants.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/arith-add-with-constants.js        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -0,0 +1,222 @@
</span><ins>+// Test value + 0.
+function arithAddIdentityWrittenAsInteger(x) {
+    var a = x + 0;
+    var b = 0 + x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithAddIdentityWrittenAsInteger, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithAddIdentityWrittenAsInteger);
+
+function testArithAddIdentityWrittenAsInteger() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAddIdentityWrittenAsInteger(i);
+        if (result !== i) {
+            throw &quot;arithAddIdentityWrittenAsInteger(i) = &quot; + result + &quot;, expected &quot; + i;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAddIdentityWrittenAsInteger(-0);
+        if (result !== -0) {
+            throw &quot;arithAddIdentityWrittenAsInteger(-0) = &quot; + result + &quot;, expected -0&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var testValue = i + .5;
+        var result = arithAddIdentityWrittenAsInteger(testValue);
+        if (result !== testValue) {
+            throw &quot;arithAddIdentityWrittenAsInteger(i) = &quot; + result + &quot;, expected &quot; + testValue;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsInteger(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithAddIdentityWrittenAsInteger(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsInteger(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithAddIdentityWrittenAsInteger(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsInteger(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithAddIdentityWrittenAsInteger(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithAddIdentityWrittenAsInteger();
+
+
+function arithAddIdentityWrittenAsDouble(x) {
+    var a = x + 0.0;
+    var b = 0. + x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithAddIdentityWrittenAsDouble, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithAddIdentityWrittenAsDouble);
+
+function testArithAddIdentityWrittenAsDouble() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAddIdentityWrittenAsDouble(i);
+        if (result !== i) {
+            throw &quot;arithAddIdentityWrittenAsDouble(i) = &quot; + result + &quot;, expected &quot; + i;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAddIdentityWrittenAsDouble(-0);
+        if (result !== -0) {
+            throw &quot;arithAddIdentityWrittenAsDouble(-0) = &quot; + result + &quot;, expected -0 &quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var testValue = i + .5;
+        var result = arithAddIdentityWrittenAsDouble(testValue);
+        if (result !== testValue) {
+            throw &quot;arithAddIdentityWrittenAsDouble(i) = &quot; + result + &quot;, expected &quot; + testValue;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsDouble(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithAddIdentityWrittenAsDouble(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsDouble(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithAddIdentityWrittenAsDouble(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAddIdentityWrittenAsDouble(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithAddIdentityWrittenAsDouble(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithAddIdentityWrittenAsDouble();
+
+
+// Test &quot;value + 42&quot;.
+function arithAdd42WrittenAsInteger(x) {
+    var a = x + 42;
+    var b = 42 + x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithAdd42WrittenAsInteger, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithAdd42WrittenAsInteger);
+
+function testArithAdd42WrittenAsInteger() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsInteger(13);
+        if (result !== 55) {
+            throw &quot;arithAdd42WrittenAsInteger(13) = &quot; + result + &quot;, expected 55&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsInteger(-0);
+        if (result !== 42) {
+            throw &quot;arithAdd42WrittenAsInteger(-0) = &quot; + result + &quot;, expected 42&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsInteger(13.3);
+        if (result !== 55.3) {
+            throw &quot;arithAdd42WrittenAsInteger(13.3) = &quot; + result + &quot;, expected 55.3&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsInteger(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithAdd42WrittenAsInteger(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsInteger(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithAdd42WrittenAsInteger(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsInteger(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithAdd42WrittenAsInteger(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithAdd42WrittenAsInteger();
+
+
+function arithAdd42WrittenAsDouble(x) {
+    var a = x + 42.0;
+    var b = 42. + x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithAdd42WrittenAsDouble, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithAdd42WrittenAsDouble);
+
+function testArithAdd42WrittenAsDouble() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsDouble(13);
+        if (result !== 55) {
+            throw &quot;arithAdd42WrittenAsDouble(i) = &quot; + result + &quot;, expected 55&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsDouble(-0);
+        if (result !== 42) {
+            throw &quot;arithAdd42WrittenAsDouble(-0) = &quot; + result + &quot;, expected 42&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithAdd42WrittenAsDouble(13.3);
+        if (result !== 55.3) {
+            throw &quot;arithAdd42WrittenAsDouble(13.3) = &quot; + result + &quot;, expected 55.3&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsDouble(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithAdd42WrittenAsDouble(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsDouble(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithAdd42WrittenAsDouble(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithAdd42WrittenAsDouble(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithAdd42WrittenAsDouble(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithAdd42WrittenAsDouble();
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressarithmulwithconstantsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/arith-mul-with-constants.js (0 => 180813)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/arith-mul-with-constants.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/arith-mul-with-constants.js        2015-02-28 03:21:37 UTC (rev 180813)
</span><span class="lines">@@ -0,0 +1,222 @@
</span><ins>+// Test value * 1.
+function arithMulIdentityWrittenAsInteger(x) {
+    var a = x * 1;
+    var b = 1 * x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithMulIdentityWrittenAsInteger, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithMulIdentityWrittenAsInteger);
+
+function testArithMulIdentityWrittenAsInteger() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMulIdentityWrittenAsInteger(i);
+        if (result !== i) {
+            throw &quot;arithMulIdentityWrittenAsInteger(i) = &quot; + result + &quot;, expected &quot; + i;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMulIdentityWrittenAsInteger(-0);
+        if (result !== -0) {
+            throw &quot;arithMulIdentityWrittenAsInteger(-0) = &quot; + result + &quot;, expected -0&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var testValue = i + .5;
+        var result = arithMulIdentityWrittenAsInteger(testValue);
+        if (result !== testValue) {
+            throw &quot;arithMulIdentityWrittenAsInteger(i) = &quot; + result + &quot;, expected &quot; + testValue;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsInteger(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithMulIdentityWrittenAsInteger(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsInteger(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithMulIdentityWrittenAsInteger(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsInteger(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithMulIdentityWrittenAsInteger(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithMulIdentityWrittenAsInteger();
+
+
+function arithMulIdentityWrittenAsDouble(x) {
+    var a = x * 1.0;
+    var b = 1. * x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithMulIdentityWrittenAsDouble, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithMulIdentityWrittenAsDouble);
+
+function testArithMulIdentityWrittenAsDouble() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMulIdentityWrittenAsDouble(i);
+        if (result !== i) {
+            throw &quot;arithMulIdentityWrittenAsDouble(i) = &quot; + result + &quot;, expected &quot; + i;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMulIdentityWrittenAsDouble(-0);
+        if (result !== -0) {
+            throw &quot;arithMulIdentityWrittenAsDouble(-0) = &quot; + result + &quot;, expected -0 &quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var testValue = i + .5;
+        var result = arithMulIdentityWrittenAsDouble(testValue);
+        if (result !== testValue) {
+            throw &quot;arithMulIdentityWrittenAsDouble(i) = &quot; + result + &quot;, expected &quot; + testValue;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsDouble(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithMulIdentityWrittenAsDouble(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsDouble(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithMulIdentityWrittenAsDouble(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMulIdentityWrittenAsDouble(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithMulIdentityWrittenAsDouble(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithMulIdentityWrittenAsDouble();
+
+
+// Test &quot;value * 42&quot;.
+function arithMul42WrittenAsInteger(x) {
+    var a = x * 42;
+    var b = 42 * x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithMul42WrittenAsInteger, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithMul42WrittenAsInteger);
+
+function testArithMul42WrittenAsInteger() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsInteger(13);
+        if (result !== 546) {
+            throw &quot;arithMul42WrittenAsInteger(13) = &quot; + result + &quot;, expected 546&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsInteger(-0);
+        if (result !== -0) {
+            throw &quot;arithMul42WrittenAsInteger(-0) = &quot; + result + &quot;, expected -0&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsInteger(13.3);
+        if (result !== 558.6) {
+            throw &quot;arithMul42WrittenAsInteger(13.3) = &quot; + result + &quot;, expected 558.6&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsInteger(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithMul42WrittenAsInteger(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsInteger(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithMul42WrittenAsInteger(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsInteger(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithMul42WrittenAsInteger(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithMul42WrittenAsInteger();
+
+
+function arithMul42WrittenAsDouble(x) {
+    var a = x * 42.0;
+    var b = 42. * x;
+    if (!(isNaN(x) &amp;&amp; isNaN(a) &amp;&amp; isNaN(b)) &amp;&amp; a !== b)
+        throw &quot;Internal error on arithMul42WrittenAsDouble, a = &quot; + a + &quot; b = &quot; + b;
+    return a;
+}
+noInline(arithMul42WrittenAsDouble);
+
+function testArithMul42WrittenAsDouble() {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsDouble(13);
+        if (result !== 546) {
+            throw &quot;arithMul42WrittenAsDouble(i) = &quot; + result + &quot;, expected 546&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsDouble(-0);
+        if (result !== -0) {
+            throw &quot;arithMul42WrittenAsDouble(-0) = &quot; + result + &quot;, expected -0&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {
+        var result = arithMul42WrittenAsDouble(13.3);
+        if (result !== 558.6) {
+            throw &quot;arithMul42WrittenAsDouble(13.3) = &quot; + result + &quot;, expected 558.6&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsDouble(NaN);
+        if (!isNaN(result)) {
+            throw &quot;arithMul42WrittenAsDouble(NaN) = &quot; + result + &quot;, expected NaN&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsDouble(Infinity);
+        if (isFinite(result)) {
+            throw &quot;arithMul42WrittenAsDouble(Infinity) = &quot; + result + &quot;, expected Infinity&quot;;
+        }
+    }
+
+    for (var i = 0; i &lt; 1e4; ++i) {;
+        var result = arithMul42WrittenAsDouble(-Infinity);
+        if (isFinite(result) || result &gt;= 0) {
+            throw &quot;arithMul42WrittenAsDouble(-Infinity) = &quot; + result + &quot;, expected -Infinity&quot;;
+        }
+    }
+}
+testArithMul42WrittenAsDouble();
</ins><span class="cx">\ No newline at end of file
</span></span></pre>
</div>
</div>

</body>
</html>