Changeset 180813 in webkit


Ignore:
Timestamp:
Feb 27, 2015, 7:21:37 PM (11 years ago)
Author:
benjamin@webkit.org
Message:

[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 <bpoulain@apple.com> 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<T>::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<LexerType>::parseDeconstructionPattern):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::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)) -> 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.
Location:
trunk/Source/JavaScriptCore
Files:
2 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r180732 r180813  
     12015-02-27  Benjamin Poulain  <bpoulain@apple.com>
     2
     3        [JSC] Use the way number constants are written to help type speculation
     4        https://bugs.webkit.org/show_bug.cgi?id=142072
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch changes how we interpret numeric constant based on how they appear
     9        in the source.
     10
     11        Constants that are integers but written with a decimal point now carry that information
     12        to the optimizating tiers. From there, we use that to be more aggressive about typing
     13        math operations toward double operations.
     14
     15        For example, in:
     16            var a = x + 1.0;
     17            var b = y + 1;
     18        The Add for a would be biased toward doubles, the Add for b would speculate
     19        integer as usual.
     20
     21
     22        The gains are tiny but this is a prerequisite to make my next patch useful:
     23        -SunSpider's access-fannkuch: definitely 1.0661x faster
     24        -SunSpider's math-cordic: definitely 1.0266x slower
     25            overal: might be 1.0066x slower.
     26        -Kraken's imaging-darkroom: definitely 1.0333x faster.
     27
     28        * parser/Lexer.cpp:
     29        (JSC::tokenTypeForIntegerLikeToken):
     30        (JSC::Lexer<T>::lex):
     31        The lexer now create two types of tokens for number: INTEGER and DOUBLE.
     32        Those token types only carry information about how the values were
     33        entered, an INTEGER does not have to be an integer, it is only written like one.
     34        Large integer still end up represented as double in memory.
     35
     36        One trap I fell into was typing numbers like 12e3 as double. This kind of literal
     37        is frequently used in integer-typed code, while 12.e3 would appear in double-typed
     38        code.
     39        Because of that, the only signals for double are: decimal point, negative zero,
     40        and ridiculously large values.
     41
     42        * parser/NodeConstructors.h:
     43        (JSC::DoubleNode::DoubleNode):
     44        (JSC::IntegerNode::IntegerNode):
     45        * parser/Nodes.h:
     46        (JSC::NumberNode::value):
     47        (JSC::NumberNode::setValue): Deleted.
     48        Number get specialized in two new kind of nodes in the AST: IntegerNode and DoubleNode.
     49
     50        * bytecompiler/NodesCodegen.cpp:
     51        (JSC::NumberNode::emitBytecode):
     52
     53        * parser/ASTBuilder.h:
     54        (JSC::ASTBuilder::createDoubleExpr):
     55        (JSC::ASTBuilder::createIntegerExpr):
     56        (JSC::ASTBuilder::createIntegerLikeNumber):
     57        (JSC::ASTBuilder::createDoubleLikeNumber):
     58        (JSC::ASTBuilder::createNumberFromBinaryOperation):
     59        (JSC::ASTBuilder::createNumberFromUnaryOperation):
     60        (JSC::ASTBuilder::makeNegateNode):
     61        (JSC::ASTBuilder::makeBitwiseNotNode):
     62        (JSC::ASTBuilder::makeMultNode):
     63        (JSC::ASTBuilder::makeDivNode):
     64        (JSC::ASTBuilder::makeModNode):
     65        (JSC::ASTBuilder::makeAddNode):
     66        (JSC::ASTBuilder::makeSubNode):
     67        (JSC::ASTBuilder::makeLeftShiftNode):
     68        (JSC::ASTBuilder::makeRightShiftNode):
     69        (JSC::ASTBuilder::makeURightShiftNode):
     70        (JSC::ASTBuilder::makeBitOrNode):
     71        (JSC::ASTBuilder::makeBitAndNode):
     72        (JSC::ASTBuilder::makeBitXOrNode):
     73        (JSC::ASTBuilder::createNumberExpr): Deleted.
     74        (JSC::ASTBuilder::createNumber): Deleted.
     75        The AST has some optimization to resolve constants before emitting bytecode.
     76        In the new code, the intger representation is kept if both operands where
     77        also represented as integers.
     78
     79        * parser/Parser.cpp:
     80        (JSC::Parser<LexerType>::parseDeconstructionPattern):
     81        (JSC::Parser<LexerType>::parseProperty):
     82        (JSC::Parser<LexerType>::parseGetterSetter):
     83        (JSC::Parser<LexerType>::parsePrimaryExpression):
     84        (JSC::Parser<LexerType>::printUnexpectedTokenText):
     85        * parser/ParserTokens.h:
     86        * parser/SyntaxChecker.h:
     87        (JSC::SyntaxChecker::createDoubleExpr):
     88        (JSC::SyntaxChecker::createIntegerExpr):
     89        (JSC::SyntaxChecker::createNumberExpr): Deleted.
     90
     91        * bytecode/CodeBlock.cpp:
     92        (JSC::CodeBlock::registerName):
     93        (JSC::CodeBlock::constantName):
     94        Change constantName(r, getConstant(r)) -> constantName(r) to simplify
     95        the dump code.
     96
     97        (JSC::CodeBlock::dumpBytecode):
     98        Dump thre soure representation information we have with each constant.
     99
     100        (JSC::CodeBlock::CodeBlock):
     101        (JSC::CodeBlock::shrinkToFit):
     102        (JSC::constantName): Deleted.
     103        * bytecode/CodeBlock.h:
     104        (JSC::CodeBlock::constantsSourceCodeRepresentation):
     105        (JSC::CodeBlock::addConstant):
     106        (JSC::CodeBlock::addConstantLazily):
     107        (JSC::CodeBlock::constantSourceCodeRepresentation):
     108        (JSC::CodeBlock::setConstantRegisters):
     109
     110        * bytecode/UnlinkedCodeBlock.h:
     111        (JSC::UnlinkedCodeBlock::addConstant):
     112        (JSC::UnlinkedCodeBlock::constantsSourceCodeRepresentation):
     113        (JSC::UnlinkedCodeBlock::shrinkToFit):
     114
     115        * bytecompiler/BytecodeGenerator.cpp:
     116        (JSC::BytecodeGenerator::addConstantValue):
     117        (JSC::BytecodeGenerator::emitLoad):
     118        * bytecompiler/BytecodeGenerator.h:
     119        We have to differentiate between constants that have the same values but are
     120        represented differently in the source. Values like 1.0 and 1 now end up
     121        as different constants.
     122
     123        * dfg/DFGByteCodeParser.cpp:
     124        (JSC::DFG::ByteCodeParser::get):
     125        (JSC::DFG::ByteCodeParser::addConstantToGraph):
     126        * dfg/DFGGraph.cpp:
     127        (JSC::DFG::Graph::registerFrozenValues):
     128        * dfg/DFGGraph.h:
     129        (JSC::DFG::Graph::addSpeculationMode):
     130        (JSC::DFG::Graph::addImmediateShouldSpeculateInt32):
     131        ArithAdd is very aggressive toward using Int52, which is quite useful
     132        in many benchmarks.
     133
     134        Here we need to specialize to make sure we don't force our literals
     135        to Int52 if there were represented as double.
     136
     137        There is one exception to that rule: when the other operand is guaranteed
     138        to come from a NodeResultInt32. This is because there is some weird code
     139        doing stuff like:
     140            var b = a|0;
     141            var c = b*2.0;
     142
     143        * dfg/DFGNode.h:
     144        (JSC::DFG::Node::Node):
     145        (JSC::DFG::Node::setOpAndDefaultFlags):
     146        (JSC::DFG::Node::sourceCodeRepresentation):
     147        * dfg/DFGPredictionPropagationPhase.cpp:
     148        (JSC::DFG::PredictionPropagationPhase::propagate):
     149        * runtime/JSCJSValue.h:
     150        (JSC::EncodedJSValueWithRepresentationHashTraits::emptyValue):
     151        (JSC::EncodedJSValueWithRepresentationHashTraits::constructDeletedValue):
     152        (JSC::EncodedJSValueWithRepresentationHashTraits::isDeletedValue):
     153        (JSC::EncodedJSValueWithRepresentationHash::hash):
     154        (JSC::EncodedJSValueWithRepresentationHash::equal):
     155        * tests/stress/arith-add-with-constants.js: Added.
     156        * tests/stress/arith-mul-with-constants.js: Added.
     157
    11582015-02-26  Filip Pizlo  <fpizlo@apple.com>
    2159
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r180639 r180813  
    173173}
    174174
    175 static CString constantName(int k, JSValue value)
    176 {
    177     return toCString(value, "(", VirtualRegister(k), ")");
    178 }
    179 
    180175static CString idName(int id0, const Identifier& ident)
    181176{
     
    186181{
    187182    if (isConstantRegisterIndex(r))
    188         return constantName(r, getConstant(r));
     183        return constantName(r);
    189184
    190185    return toCString(VirtualRegister(r));
     186}
     187
     188CString CodeBlock::constantName(int index) const
     189{
     190    JSValue value = getConstant(index);
     191    return toCString(value, "(", VirtualRegister(index), ")");
    191192}
    192193
     
    607608        size_t i = 0;
    608609        do {
    609             out.printf("   k%u = %s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data());
     610            const char* sourceCodeRepresentationDescription;
     611            switch (m_constantsSourceCodeRepresentation[i]) {
     612            case SourceCodeRepresentation::Double:
     613                sourceCodeRepresentationDescription = ": in source as double";
     614                break;
     615            case SourceCodeRepresentation::Integer:
     616                sourceCodeRepresentationDescription = ": in source as integer";
     617                break;
     618            case SourceCodeRepresentation::Other:
     619                sourceCodeRepresentationDescription = "";
     620                break;
     621            }
     622            out.printf("   k%u = %s%s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data(), sourceCodeRepresentationDescription);
    610623            ++i;
    611624        } while (i < m_constantRegisters.size());
     
    14501463            JSNameScope::Type scopeType = (JSNameScope::Type)(++it)->u.operand;
    14511464            printLocationAndOp(out, exec, location, it, "push_name_scope");
    1452             out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(r1).data(), constantName(k0, getConstant(k0)).data(), (scopeType == JSNameScope::FunctionNameScope) ? "functionScope" : ((scopeType == JSNameScope::CatchScope) ? "catchScope" : "unknownScopeType"));
     1465            out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(r1).data(), constantName(k0).data(), (scopeType == JSNameScope::FunctionNameScope) ? "functionScope" : ((scopeType == JSNameScope::CatchScope) ? "catchScope" : "unknownScopeType"));
    14531466            break;
    14541467        }
     
    14671480            int k1 = (++it)->u.operand;
    14681481            printLocationAndOp(out, exec, location, it, "throw_static_error");
    1469             out.printf("%s, %s", constantName(k0, getConstant(k0)).data(), k1 ? "true" : "false");
     1482            out.printf("%s, %s", constantName(k0).data(), k1 ? "true" : "false");
    14701483            break;
    14711484        }
     
    16401653    , m_codeType(other.m_codeType)
    16411654    , m_constantRegisters(other.m_constantRegisters)
     1655    , m_constantsSourceCodeRepresentation(other.m_constantsSourceCodeRepresentation)
    16421656    , m_functionDecls(other.m_functionDecls)
    16431657    , m_functionExprs(other.m_functionExprs)
     
    17311745        vm()->functionHasExecutedCache()->removeUnexecutedRange(m_ownerExecutable->sourceID(), m_ownerExecutable->typeProfilingStartOffset(), m_ownerExecutable->typeProfilingEndOffset());
    17321746
    1733     setConstantRegisters(unlinkedCodeBlock->constantRegisters());
     1747    setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation());
    17341748    if (unlinkedCodeBlock->usesGlobalObject())
    17351749        m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get());
     
    29812995    if (shrinkMode == EarlyShrink) {
    29822996        m_constantRegisters.shrinkToFit();
     2997        m_constantsSourceCodeRepresentation.shrinkToFit();
    29832998       
    29842999        if (m_rareData) {
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r179862 r180813  
    629629
    630630    Vector<WriteBarrier<Unknown>>& constants() { return m_constantRegisters; }
     631    Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
    631632    size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
    632633    unsigned addConstant(JSValue v)
     
    635636        m_constantRegisters.append(WriteBarrier<Unknown>());
    636637        m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v);
     638        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
    637639        return result;
    638640    }
     
    642644        unsigned result = m_constantRegisters.size();
    643645        m_constantRegisters.append(WriteBarrier<Unknown>());
     646        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
    644647        return result;
    645648    }
     
    650653    ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
    651654    ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
     655    ALWAYS_INLINE SourceCodeRepresentation constantSourceCodeRepresentation(int index) const { return m_constantsSourceCodeRepresentation[index - FirstConstantRegisterIndex]; }
    652656
    653657    FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
     
    984988    void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
    985989
    986     void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants)
    987     {
     990    void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation)
     991    {
     992        ASSERT(constants.size() == constantsSourceCodeRepresentation.size());
    988993        size_t count = constants.size();
    989994        m_constantRegisters.resize(count);
    990995        for (size_t i = 0; i < count; i++)
    991996            m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get());
     997        m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation;
    992998    }
    993999
     
    9971003
    9981004    CString registerName(int r) const;
     1005    CString constantName(int index) const;
    9991006    void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
    10001007    void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
     
    10941101    // it, so we're stuck with it for now.
    10951102    Vector<WriteBarrier<Unknown>> m_constantRegisters;
     1103    Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
    10961104    Vector<WriteBarrier<FunctionExecutable>> m_functionDecls;
    10971105    Vector<WriteBarrier<FunctionExecutable>> m_functionExprs;
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h

    r180637 r180813  
    319319
    320320    size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
    321     unsigned addConstant(JSValue v)
     321    unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
    322322    {
    323323        unsigned result = m_constantRegisters.size();
    324324        m_constantRegisters.append(WriteBarrier<Unknown>());
    325325        m_constantRegisters.last().set(*m_vm, this, v);
     326        m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
    326327        return result;
    327328    }
     
    331332    ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
    332333    ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
     334    const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
    333335
    334336    // Jumps
     
    348350        m_identifiers.shrinkToFit();
    349351        m_constantRegisters.shrinkToFit();
     352        m_constantsSourceCodeRepresentation.shrinkToFit();
    350353        m_functionDecls.shrinkToFit();
    351354        m_functionExprs.shrinkToFit();
     
    545548    Vector<Identifier> m_identifiers;
    546549    Vector<WriteBarrier<Unknown>> m_constantRegisters;
     550    Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
    547551    typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector;
    548552    FunctionExpressionVector m_functionDecls;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r180732 r180813  
    980980}
    981981
    982 RegisterID* BytecodeGenerator::addConstantValue(JSValue v)
     982RegisterID* BytecodeGenerator::addConstantValue(JSValue v, SourceCodeRepresentation sourceCodeRepresentation)
    983983{
    984984    if (!v)
     
    986986
    987987    int index = m_nextConstantOffset;
    988     JSValueMap::AddResult result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset);
     988
     989    EncodedJSValueWithRepresentation valueMapKey { JSValue::encode(v), sourceCodeRepresentation };
     990    JSValueMap::AddResult result = m_jsValueMap.add(valueMapKey, m_nextConstantOffset);
    989991    if (result.isNewEntry) {
    990992        m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
    991993        ++m_nextConstantOffset;
    992         m_codeBlock->addConstant(v);
     994        m_codeBlock->addConstant(v, sourceCodeRepresentation);
    993995    } else
    994996        index = result.iterator->value;
     
    11631165}
    11641166
    1165 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
    1166 {
    1167     RegisterID* constantID = addConstantValue(v);
     1167RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v, SourceCodeRepresentation sourceCodeRepresentation)
     1168{
     1169    RegisterID* constantID = addConstantValue(v, sourceCodeRepresentation);
    11681170    if (dst)
    11691171        return emitMove(dst, constantID);
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r180732 r180813  
    444444        RegisterID* emitLoad(RegisterID* dst, bool);
    445445        RegisterID* emitLoad(RegisterID* dst, const Identifier&);
    446         RegisterID* emitLoad(RegisterID* dst, JSValue);
     446        RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
    447447        RegisterID* emitLoadGlobalObject(RegisterID* dst);
    448448
     
    647647        bool hasConstant(const Identifier&) const;
    648648        unsigned addConstant(const Identifier&);
    649         RegisterID* addConstantValue(JSValue);
     649        RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
    650650        RegisterID* addConstantEmptyValue();
    651651        unsigned addRegExp(RegExp*);
     
    793793        // Constant pool
    794794        IdentifierMap m_identifierMap;
     795
     796        typedef HashMap<EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits> JSValueMap;
    795797        JSValueMap m_jsValueMap;
    796798        IdentifierStringMap m_stringMap;
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r180732 r180813  
    121121{
    122122    return generator.addStringConstant(m_value);
     123}
     124
     125// ------------------------------ NumberNode ----------------------------------
     126
     127RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     128{
     129    if (dst == generator.ignoredResult())
     130        return nullptr;
     131    return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double);
    123132}
    124133
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r173069 r180813  
    9696    bool isWithinPowerOfTwoNonRecursive(Node* node)
    9797    {
    98         if (node->op() != JSConstant)
     98        if (!node->isNumberConstant())
    9999            return false;
    100100        return isWithinPowerOfTwoForConstant<power>(node);
     
    105105    {
    106106        switch (node->op()) {
    107         case JSConstant: {
     107        case DoubleConstant:
     108        case JSConstant:
     109        case Int52Constant: {
    108110            return isWithinPowerOfTwoForConstant<power>(node);
    109111        }
     
    129131           
    130132            Node* shiftAmount = node->child2().node();
    131             if (shiftAmount->op() != JSConstant)
     133            if (!node->isNumberConstant())
    132134                return false;
    133135            JSValue immediateValue = shiftAmount->asJSValue();
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r180595 r180813  
    253253            unsigned oldSize = m_constants.size();
    254254            if (constantIndex >= oldSize || !m_constants[constantIndex]) {
    255                 JSValue value = m_inlineStackTop->m_codeBlock->getConstant(operand.offset());
     255                const CodeBlock& codeBlock = *m_inlineStackTop->m_codeBlock;
     256                JSValue value = codeBlock.getConstant(operand.offset());
     257                SourceCodeRepresentation sourceCodeRepresentation = codeBlock.constantSourceCodeRepresentation(operand.offset());
    256258                if (constantIndex >= oldSize) {
    257259                    m_constants.grow(constantIndex + 1);
     
    259261                        m_constants[i] = nullptr;
    260262                }
    261                 m_constants[constantIndex] =
    262                     addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value)));
     263
     264                Node* constantNode = nullptr;
     265                if (sourceCodeRepresentation == SourceCodeRepresentation::Double)
     266                    constantNode = addToGraph(DoubleConstant, OpInfo(m_graph.freezeStrong(jsDoubleNumber(value.asNumber()))));
     267                else
     268                    constantNode = addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value)));
     269                m_constants[constantIndex] = constantNode;
    263270            }
    264271            ASSERT(m_constants[constantIndex]);
  • trunk/Source/JavaScriptCore/dfg/DFGCommon.h

    r180279 r180813  
    257257}
    258258
     259enum class PlanStage {
     260    Initial,
     261    AfterFixup
     262};
     263
    259264template<typename T, typename U>
    260265bool checkAndSet(T& left, U right)
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r180703 r180813  
    6868        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
    6969            injectTypeConversionsInBlock(m_graph.block(blockIndex));
    70        
     70
     71        m_graph.m_planStage = PlanStage::AfterFixup;
     72
    7173        return true;
    7274    }
     
    10571059        case ValueRep:
    10581060        case Int52Rep:
    1059         case DoubleConstant:
    10601061        case Int52Constant:
    10611062        case Identity: // This should have been cleaned up.
     
    12201221        case SetArgument:
    12211222        case JSConstant:
     1223        case DoubleConstant:
    12221224        case GetLocal:
    12231225        case GetCallee:
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r180691 r180813  
    10541054{
    10551055    m_codeBlock->constants().resize(0);
     1056    m_codeBlock->constantsSourceCodeRepresentation().resize(0);
    10561057    for (FrozenValue* value : m_frozenValues) {
    10571058        if (value->structure())
     
    10791080    }
    10801081    m_codeBlock->constants().shrinkToFit();
     1082    m_codeBlock->constantsSourceCodeRepresentation().shrinkToFit();
    10811083}
    10821084
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r180691 r180813  
    218218       
    219219        if (left->hasConstant())
    220             return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source);
     220            return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, right, left, source);
    221221        if (right->hasConstant())
    222             return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source);
     222            return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, left, right, source);
    223223       
    224224        return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32;
     
    847847    GraphForm m_form;
    848848    UnificationState m_unificationState;
     849    PlanStage m_planStage { PlanStage::Initial };
    849850    RefCountState m_refCountState;
    850851private:
     
    852853    void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor);
    853854   
    854     AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source)
     855    AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* operand, Node*immediate, RareCaseProfilingSource source)
    855856    {
    856857        ASSERT(immediate->hasConstant());
     
    862863        if (!variableShouldSpeculateInt32)
    863864            return DontSpeculateInt32;
    864        
    865         if (immediateValue.isInt32() || immediateValue.isBoolean())
     865
     866        // Integer constants can be typed Double if they are written like a double in the source code (e.g. 42.0).
     867        // In that case, we stay conservative unless the other operand was explicitly typed as integer.
     868        NodeFlags operandResultType = operand->result();
     869        if (operandResultType != NodeResultInt32 && immediateValue.isDouble())
     870            return DontSpeculateInt32;
     871       
     872        if (jsNumber(immediateValue.asNumber()).isInt32() || immediateValue.isBoolean())
    866873            return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32;
    867874       
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r180691 r180813  
    149149            break;
    150150        }
     151        case DoubleConstant: {
     152            SpeculatedType type = speculationFromValue(node->asJSValue());
     153            changed |= setPrediction(type);
     154            break;
     155        }
    151156           
    152157        case GetLocal: {
     
    533538        case ValueRep:
    534539        case Int52Rep:
    535         case DoubleConstant:
    536540        case Int52Constant:
    537541        case Identity:
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r180691 r180813  
    119119                   
    120120                    m_myRefCounts.find(edge.node())->value++;
    121                    
    122                     VALIDATE((node, edge), edge->hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse));
     121
     122                    validateEdgeWithDoubleResultIfNecessary(node, edge);
    123123                    VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse));
    124124                   
     
    544544        }
    545545    }
    546    
     546
     547    void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge)
     548    {
     549        if (!edge->hasDoubleResult())
     550            return;
     551
     552        if (m_graph.m_planStage < PlanStage::AfterFixup)
     553            VALIDATE((node, edge), edge.useKind() == UntypedUse);
     554        else
     555            VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse);
     556    }
     557
    547558    void checkOperand(
    548559        BasicBlock* block, Operands<size_t>& getLocalPositions,
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r180518 r180813  
    193193        return new (m_parserArena) ArrayNode(location, elisions, elems);
    194194    }
    195     ExpressionNode* createNumberExpr(const JSTokenLocation& location, double d)
     195    ExpressionNode* createDoubleExpr(const JSTokenLocation& location, double d)
    196196    {
    197197        incConstants();
    198         return new (m_parserArena) NumberNode(location, d);
     198        return new (m_parserArena) DoubleNode(location, d);
     199    }
     200    ExpressionNode* createIntegerExpr(const JSTokenLocation& location, double d)
     201    {
     202        incConstants();
     203        return new (m_parserArena) IntegerNode(location, d);
    199204    }
    200205
     
    749754        m_scope.m_features |= EvalFeature;
    750755    }
    751     ExpressionNode* createNumber(const JSTokenLocation& location, double d)
    752     {
    753         return new (m_parserArena) NumberNode(location, d);
    754     }
    755    
     756    ExpressionNode* createIntegerLikeNumber(const JSTokenLocation& location, double d)
     757    {
     758        return new (m_parserArena) IntegerNode(location, d);
     759    }
     760    ExpressionNode* createDoubleLikeNumber(const JSTokenLocation& location, double d)
     761    {
     762        return new (m_parserArena) DoubleNode(location, d);
     763    }
     764    ExpressionNode* createNumberFromBinaryOperation(const JSTokenLocation& location, double value, const NumberNode& originalNodeA, const NumberNode& originalNodeB)
     765    {
     766        if (originalNodeA.isIntegerNode() && originalNodeB.isIntegerNode())
     767            return createIntegerLikeNumber(location, value);
     768        return createDoubleLikeNumber(location, value);
     769    }
     770    ExpressionNode* createNumberFromUnaryOperation(const JSTokenLocation& location, double value, const NumberNode& originalNode)
     771    {
     772        if (originalNode.isIntegerNode())
     773            return createIntegerLikeNumber(location, value);
     774        return createDoubleLikeNumber(location, value);
     775    }
     776
    756777    VM* m_vm;
    757778    ParserArena& m_parserArena;
     
    794815{
    795816    if (n->isNumber()) {
    796         NumberNode* numberNode = static_cast<NumberNode*>(n);
    797         numberNode->setValue(-numberNode->value());
    798         return numberNode;
     817        const NumberNode& numberNode = static_cast<const NumberNode&>(*n);
     818        return createNumberFromUnaryOperation(location, -numberNode.value(), numberNode);
    799819    }
    800820
     
    805825{
    806826    if (expr->isNumber())
    807         return createNumber(location, ~toInt32(static_cast<NumberNode*>(expr)->value()));
     827        return createIntegerLikeNumber(location, ~toInt32(static_cast<NumberNode*>(expr)->value()));
    808828    return new (m_parserArena) BitwiseNotNode(location, expr);
    809829}
     
    814834    expr2 = expr2->stripUnaryPlus();
    815835
    816     if (expr1->isNumber() && expr2->isNumber())
    817         return createNumber(location, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
     836    if (expr1->isNumber() && expr2->isNumber()) {
     837        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     838        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     839        return createNumberFromBinaryOperation(location, numberExpr1.value() * numberExpr2.value(), numberExpr1, numberExpr2);
     840    }
    818841
    819842    if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
     
    831854    expr2 = expr2->stripUnaryPlus();
    832855
    833     if (expr1->isNumber() && expr2->isNumber())
    834         return createNumber(location, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
     856    if (expr1->isNumber() && expr2->isNumber()) {
     857        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     858        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     859        double result = numberExpr1.value() / numberExpr2.value();
     860        if (static_cast<int64_t>(result) == result)
     861            return createNumberFromBinaryOperation(location, result, numberExpr1, numberExpr2);
     862        return createDoubleLikeNumber(location, result);
     863    }
    835864    return new (m_parserArena) DivNode(location, expr1, expr2, rightHasAssignments);
    836865}
     
    840869    expr1 = expr1->stripUnaryPlus();
    841870    expr2 = expr2->stripUnaryPlus();
    842    
    843     if (expr1->isNumber() && expr2->isNumber())
    844         return createNumber(location, fmod(static_cast<NumberNode*>(expr1)->value(), static_cast<NumberNode*>(expr2)->value()));
     871
     872    if (expr1->isNumber() && expr2->isNumber()) {
     873        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     874        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     875        return createIntegerLikeNumber(location, fmod(numberExpr1.value(), numberExpr2.value()));
     876    }
    845877    return new (m_parserArena) ModNode(location, expr1, expr2, rightHasAssignments);
    846878}
     
    848880ExpressionNode* ASTBuilder::makeAddNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    849881{
    850     if (expr1->isNumber() && expr2->isNumber())
    851         return createNumber(location, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
     882
     883    if (expr1->isNumber() && expr2->isNumber()) {
     884        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     885        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     886        return createNumberFromBinaryOperation(location, numberExpr1.value() + numberExpr2.value(), numberExpr1, numberExpr2);
     887    }
    852888    return new (m_parserArena) AddNode(location, expr1, expr2, rightHasAssignments);
    853889}
     
    858894    expr2 = expr2->stripUnaryPlus();
    859895
    860     if (expr1->isNumber() && expr2->isNumber())
    861         return createNumber(location, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
     896    if (expr1->isNumber() && expr2->isNumber()) {
     897        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     898        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     899        return createNumberFromBinaryOperation(location, numberExpr1.value() - numberExpr2.value(), numberExpr1, numberExpr2);
     900    }
    862901    return new (m_parserArena) SubNode(location, expr1, expr2, rightHasAssignments);
    863902}
     
    865904ExpressionNode* ASTBuilder::makeLeftShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    866905{
    867     if (expr1->isNumber() && expr2->isNumber())
    868         return createNumber(location, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
     906    if (expr1->isNumber() && expr2->isNumber()) {
     907        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     908        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     909        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) << (toUInt32(numberExpr2.value()) & 0x1f));
     910    }
    869911    return new (m_parserArena) LeftShiftNode(location, expr1, expr2, rightHasAssignments);
    870912}
     
    872914ExpressionNode* ASTBuilder::makeRightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    873915{
    874     if (expr1->isNumber() && expr2->isNumber())
    875         return createNumber(location, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
     916    if (expr1->isNumber() && expr2->isNumber()) {
     917        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     918        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     919        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) >> (toUInt32(numberExpr2.value()) & 0x1f));
     920    }
    876921    return new (m_parserArena) RightShiftNode(location, expr1, expr2, rightHasAssignments);
    877922}
     
    879924ExpressionNode* ASTBuilder::makeURightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    880925{
    881     if (expr1->isNumber() && expr2->isNumber())
    882         return createNumber(location, toUInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
     926    if (expr1->isNumber() && expr2->isNumber()) {
     927        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     928        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     929        return createIntegerLikeNumber(location, toUInt32(numberExpr1.value()) >> (toUInt32(numberExpr2.value()) & 0x1f));
     930    }
    883931    return new (m_parserArena) UnsignedRightShiftNode(location, expr1, expr2, rightHasAssignments);
    884932}
     
    886934ExpressionNode* ASTBuilder::makeBitOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    887935{
    888     if (expr1->isNumber() && expr2->isNumber())
    889         return createNumber(location, toInt32(static_cast<NumberNode*>(expr1)->value()) | toInt32(static_cast<NumberNode*>(expr2)->value()));
     936    if (expr1->isNumber() && expr2->isNumber()) {
     937        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     938        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     939        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) | toInt32(numberExpr2.value()));
     940    }
    890941    return new (m_parserArena) BitOrNode(location, expr1, expr2, rightHasAssignments);
    891942}
     
    893944ExpressionNode* ASTBuilder::makeBitAndNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    894945{
    895     if (expr1->isNumber() && expr2->isNumber())
    896         return createNumber(location, toInt32(static_cast<NumberNode*>(expr1)->value()) & toInt32(static_cast<NumberNode*>(expr2)->value()));
     946    if (expr1->isNumber() && expr2->isNumber()) {
     947        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     948        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     949        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) & toInt32(numberExpr2.value()));
     950    }
    897951    return new (m_parserArena) BitAndNode(location, expr1, expr2, rightHasAssignments);
    898952}
     
    900954ExpressionNode* ASTBuilder::makeBitXOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
    901955{
    902     if (expr1->isNumber() && expr2->isNumber())
    903         return createNumber(location, toInt32(static_cast<NumberNode*>(expr1)->value()) ^ toInt32(static_cast<NumberNode*>(expr2)->value()));
     956    if (expr1->isNumber() && expr2->isNumber()) {
     957        const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
     958        const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
     959        return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) ^ toInt32(numberExpr2.value()));
     960    }
    904961    return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments);
    905962}
  • trunk/Source/JavaScriptCore/parser/Lexer.cpp

    r178427 r180813  
    496496}
    497497
     498static inline JSTokenType tokenTypeForIntegerLikeToken(double doubleValue)
     499{
     500    if ((doubleValue || !std::signbit(doubleValue)) && static_cast<int64_t>(doubleValue) == doubleValue)
     501        return INTEGER;
     502    return DOUBLE;
     503}
     504
    498505template <typename T>
    499506Lexer<T>::~Lexer()
     
    16881695                goto returnError;
    16891696            }
    1690             token = NUMBER;
     1697            token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
    16911698            m_buffer8.resize(0);
    16921699            break;
     
    17011708        if (isASCIIOctalDigit(m_current)) {
    17021709            if (parseOctal(tokenData->doubleValue)) {
    1703                 token = NUMBER;
     1710                token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
    17041711            }
    17051712        }
    17061713        FALLTHROUGH;
    17071714    case CharacterNumber:
    1708         if (LIKELY(token != NUMBER)) {
     1715        if (LIKELY(token != INTEGER && token != DOUBLE)) {
    17091716            if (!parseDecimal(tokenData->doubleValue)) {
     1717                token = INTEGER;
    17101718                if (m_current == '.') {
    17111719                    shift();
    17121720inNumberAfterDecimalPoint:
    17131721                    parseNumberAfterDecimalPoint();
     1722                    token = DOUBLE;
    17141723                }
    17151724                if ((m_current | 0x20) == 'e') {
     
    17221731                size_t parsedLength;
    17231732                tokenData->doubleValue = parseDouble(m_buffer8.data(), m_buffer8.size(), parsedLength);
    1724             }
    1725             token = NUMBER;
     1733                if (token == INTEGER)
     1734                    token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
     1735            } else
     1736                token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
    17261737        }
    17271738
  • trunk/Source/JavaScriptCore/parser/NodeConstructors.h

    r179371 r180813  
    8585    }
    8686
     87    inline DoubleNode::DoubleNode(const JSTokenLocation& location, double value)
     88        : NumberNode(location, value)
     89    {
     90    }
     91
     92    inline IntegerNode::IntegerNode(const JSTokenLocation& location, double value)
     93        : DoubleNode(location, value)
     94    {
     95    }
     96
    8797    inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value)
    8898        : ConstantNode(location, ResultType::stringType())
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r180518 r180813  
    237237    public:
    238238        NumberNode(const JSTokenLocation&, double value);
    239         double value() { return m_value; }
    240         void setValue(double value) { m_value = value; }
    241 
    242     private:
    243         virtual bool isNumber() const override { return true; }
     239        double value() const { return m_value; }
     240        virtual bool isIntegerNode() const = 0;
     241        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override final;
     242
     243    private:
     244        virtual bool isNumber() const override final { return true; }
    244245        virtual JSValue jsValue(BytecodeGenerator&) const override { return jsNumber(m_value); }
    245246
    246247        double m_value;
     248    };
     249
     250    class DoubleNode : public NumberNode {
     251    public:
     252        DoubleNode(const JSTokenLocation&, double value);
     253
     254    private:
     255        virtual bool isIntegerNode() const override { return false; }
     256    };
     257
     258    // An integer node represent a number represented as an integer (e.g. 42 instead of 42., 42.0, 42e0)
     259    class IntegerNode : public DoubleNode {
     260    public:
     261        IntegerNode(const JSTokenLocation&, double value);
     262        virtual bool isIntegerNode() const override final { return true; }
    247263    };
    248264
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r180518 r180813  
    630630                JSTokenType tokenType = m_token.m_type;
    631631                switch (m_token.m_type) {
    632                 case NUMBER:
     632                case DOUBLE:
     633                case INTEGER:
    633634                    propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue);
    634635                    break;
     
    19461947        return parseGetterSetter(context, complete, type, getterOrSetterStartOffset);
    19471948    }
    1948     case NUMBER: {
     1949    case DOUBLE:
     1950    case INTEGER: {
    19491951        double propertyName = m_token.m_data.doubleValue;
    19501952        next();
     
    19801982    if (m_token.m_type == IDENT || m_token.m_type == STRING)
    19811983        stringPropertyName = m_token.m_data.ident;
    1982     else if (m_token.m_type == NUMBER)
     1984    else if (m_token.m_type == DOUBLE || m_token.m_type == INTEGER)
    19831985        numericPropertyName = m_token.m_data.doubleValue;
    19841986    else
     
    22222224        return context.createString(location, ident);
    22232225    }
    2224     case NUMBER: {
     2226    case DOUBLE: {
    22252227        double d = m_token.m_data.doubleValue;
    22262228        JSTokenLocation location(tokenLocation());
    22272229        next();
    2228         return context.createNumberExpr(location, d);
     2230        return context.createDoubleExpr(location, d);
     2231    }
     2232    case INTEGER: {
     2233        double d = m_token.m_data.doubleValue;
     2234        JSTokenLocation location(tokenLocation());
     2235        next();
     2236        return context.createIntegerExpr(location, d);
    22292237    }
    22302238    case NULLTOKEN: {
     
    25782586        out.print("Unexpected string literal ", getToken());
    25792587        return;
    2580     case NUMBER:
     2588    case INTEGER:
     2589    case DOUBLE:
    25812590        out.print("Unexpected number '", getToken(), "'");
    25822591        return;
  • trunk/Source/JavaScriptCore/parser/ParserTokens.h

    r178954 r180813  
    9595    COMMA,
    9696    QUESTION,
    97     NUMBER,
     97    INTEGER,
     98    DOUBLE,
    9899    IDENT,
    99100    STRING,
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r179371 r180813  
    7272    typedef SyntaxChecker FunctionBodyBuilder;
    7373    enum { NoneExpr = 0,
    74         ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,
     74        ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
    7575        ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
    7676        FunctionExpr, ClassExpr, BracketExpr, DotExpr, CallExpr,
     
    152152    ExpressionType createArray(const JSTokenLocation&, int) { return ArrayLiteralExpr; }
    153153    ExpressionType createArray(const JSTokenLocation&, int, int) { return ArrayLiteralExpr; }
    154     ExpressionType createNumberExpr(const JSTokenLocation&, double) { return NumberExpr; }
     154    ExpressionType createDoubleExpr(const JSTokenLocation&, double) { return DoubleExpr; }
     155    ExpressionType createIntegerExpr(const JSTokenLocation&, double) { return IntegerExpr; }
    155156    ExpressionType createString(const JSTokenLocation&, const Identifier*) { return StringExpr; }
    156157    ExpressionType createBoolean(const JSTokenLocation&, bool) { return BoolExpr; }
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.h

    r180130 r180813  
    125125bool isInt52(double);
    126126
     127enum class SourceCodeRepresentation {
     128    Other,
     129    Integer,
     130    Double
     131};
     132
    127133class JSValue {
    128134    friend struct EncodedJSValueHashTraits;
     135    friend struct EncodedJSValueWithRepresentationHashTraits;
    129136    friend class AssemblyHelpers;
    130137    friend class JIT;
     
    449456#endif
    450457
    451 typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap;
     458typedef std::pair<EncodedJSValue, SourceCodeRepresentation> EncodedJSValueWithRepresentation;
     459
     460struct EncodedJSValueWithRepresentationHashTraits : HashTraits<EncodedJSValueWithRepresentation> {
     461    static const bool emptyValueIsZero = false;
     462    static EncodedJSValueWithRepresentation emptyValue() { return std::make_pair(JSValue::encode(JSValue()), SourceCodeRepresentation::Other); }
     463    static void constructDeletedValue(EncodedJSValueWithRepresentation& slot) { slot = std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
     464    static bool isDeletedValue(EncodedJSValueWithRepresentation value) { return value == std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
     465};
     466
     467struct EncodedJSValueWithRepresentationHash {
     468    static unsigned hash(const EncodedJSValueWithRepresentation& value)
     469    {
     470        return WTF::pairIntHash(EncodedJSValueHash::hash(value.first), IntHash<SourceCodeRepresentation>::hash(value.second));
     471    }
     472    static bool equal(const EncodedJSValueWithRepresentation& a, const EncodedJSValueWithRepresentation& b)
     473    {
     474        return a == b;
     475    }
     476    static const bool safeToCompareToEmptyOrDeleted = true;
     477};
    452478
    453479// Stand-alone helper functions.
Note: See TracChangeset for help on using the changeset viewer.