Changeset 180813 in webkit
- Timestamp:
- Feb 27, 2015, 7:21:37 PM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 added
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r180732 r180813 1 2015-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 1 158 2015-02-26 Filip Pizlo <fpizlo@apple.com> 2 159 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r180639 r180813 173 173 } 174 174 175 static CString constantName(int k, JSValue value)176 {177 return toCString(value, "(", VirtualRegister(k), ")");178 }179 180 175 static CString idName(int id0, const Identifier& ident) 181 176 { … … 186 181 { 187 182 if (isConstantRegisterIndex(r)) 188 return constantName(r , getConstant(r));183 return constantName(r); 189 184 190 185 return toCString(VirtualRegister(r)); 186 } 187 188 CString CodeBlock::constantName(int index) const 189 { 190 JSValue value = getConstant(index); 191 return toCString(value, "(", VirtualRegister(index), ")"); 191 192 } 192 193 … … 607 608 size_t i = 0; 608 609 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); 610 623 ++i; 611 624 } while (i < m_constantRegisters.size()); … … 1450 1463 JSNameScope::Type scopeType = (JSNameScope::Type)(++it)->u.operand; 1451 1464 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")); 1453 1466 break; 1454 1467 } … … 1467 1480 int k1 = (++it)->u.operand; 1468 1481 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"); 1470 1483 break; 1471 1484 } … … 1640 1653 , m_codeType(other.m_codeType) 1641 1654 , m_constantRegisters(other.m_constantRegisters) 1655 , m_constantsSourceCodeRepresentation(other.m_constantsSourceCodeRepresentation) 1642 1656 , m_functionDecls(other.m_functionDecls) 1643 1657 , m_functionExprs(other.m_functionExprs) … … 1731 1745 vm()->functionHasExecutedCache()->removeUnexecutedRange(m_ownerExecutable->sourceID(), m_ownerExecutable->typeProfilingStartOffset(), m_ownerExecutable->typeProfilingEndOffset()); 1732 1746 1733 setConstantRegisters(unlinkedCodeBlock->constantRegisters() );1747 setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation()); 1734 1748 if (unlinkedCodeBlock->usesGlobalObject()) 1735 1749 m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get()); … … 2981 2995 if (shrinkMode == EarlyShrink) { 2982 2996 m_constantRegisters.shrinkToFit(); 2997 m_constantsSourceCodeRepresentation.shrinkToFit(); 2983 2998 2984 2999 if (m_rareData) { -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r179862 r180813 629 629 630 630 Vector<WriteBarrier<Unknown>>& constants() { return m_constantRegisters; } 631 Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } 631 632 size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } 632 633 unsigned addConstant(JSValue v) … … 635 636 m_constantRegisters.append(WriteBarrier<Unknown>()); 636 637 m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v); 638 m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); 637 639 return result; 638 640 } … … 642 644 unsigned result = m_constantRegisters.size(); 643 645 m_constantRegisters.append(WriteBarrier<Unknown>()); 646 m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); 644 647 return result; 645 648 } … … 650 653 ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } 651 654 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]; } 652 656 653 657 FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } … … 984 988 void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); 985 989 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()); 988 993 size_t count = constants.size(); 989 994 m_constantRegisters.resize(count); 990 995 for (size_t i = 0; i < count; i++) 991 996 m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get()); 997 m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation; 992 998 } 993 999 … … 997 1003 998 1004 CString registerName(int r) const; 1005 CString constantName(int index) const; 999 1006 void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); 1000 1007 void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); … … 1094 1101 // it, so we're stuck with it for now. 1095 1102 Vector<WriteBarrier<Unknown>> m_constantRegisters; 1103 Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; 1096 1104 Vector<WriteBarrier<FunctionExecutable>> m_functionDecls; 1097 1105 Vector<WriteBarrier<FunctionExecutable>> m_functionExprs; -
trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
r180637 r180813 319 319 320 320 size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } 321 unsigned addConstant(JSValue v )321 unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other) 322 322 { 323 323 unsigned result = m_constantRegisters.size(); 324 324 m_constantRegisters.append(WriteBarrier<Unknown>()); 325 325 m_constantRegisters.last().set(*m_vm, this, v); 326 m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation); 326 327 return result; 327 328 } … … 331 332 ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } 332 333 ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } 334 const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } 333 335 334 336 // Jumps … … 348 350 m_identifiers.shrinkToFit(); 349 351 m_constantRegisters.shrinkToFit(); 352 m_constantsSourceCodeRepresentation.shrinkToFit(); 350 353 m_functionDecls.shrinkToFit(); 351 354 m_functionExprs.shrinkToFit(); … … 545 548 Vector<Identifier> m_identifiers; 546 549 Vector<WriteBarrier<Unknown>> m_constantRegisters; 550 Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; 547 551 typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector; 548 552 FunctionExpressionVector m_functionDecls; -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r180732 r180813 980 980 } 981 981 982 RegisterID* BytecodeGenerator::addConstantValue(JSValue v )982 RegisterID* BytecodeGenerator::addConstantValue(JSValue v, SourceCodeRepresentation sourceCodeRepresentation) 983 983 { 984 984 if (!v) … … 986 986 987 987 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); 989 991 if (result.isNewEntry) { 990 992 m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); 991 993 ++m_nextConstantOffset; 992 m_codeBlock->addConstant(v );994 m_codeBlock->addConstant(v, sourceCodeRepresentation); 993 995 } else 994 996 index = result.iterator->value; … … 1163 1165 } 1164 1166 1165 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v )1166 { 1167 RegisterID* constantID = addConstantValue(v );1167 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v, SourceCodeRepresentation sourceCodeRepresentation) 1168 { 1169 RegisterID* constantID = addConstantValue(v, sourceCodeRepresentation); 1168 1170 if (dst) 1169 1171 return emitMove(dst, constantID); -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r180732 r180813 444 444 RegisterID* emitLoad(RegisterID* dst, bool); 445 445 RegisterID* emitLoad(RegisterID* dst, const Identifier&); 446 RegisterID* emitLoad(RegisterID* dst, JSValue );446 RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); 447 447 RegisterID* emitLoadGlobalObject(RegisterID* dst); 448 448 … … 647 647 bool hasConstant(const Identifier&) const; 648 648 unsigned addConstant(const Identifier&); 649 RegisterID* addConstantValue(JSValue );649 RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); 650 650 RegisterID* addConstantEmptyValue(); 651 651 unsigned addRegExp(RegExp*); … … 793 793 // Constant pool 794 794 IdentifierMap m_identifierMap; 795 796 typedef HashMap<EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits> JSValueMap; 795 797 JSValueMap m_jsValueMap; 796 798 IdentifierStringMap m_stringMap; -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r180732 r180813 121 121 { 122 122 return generator.addStringConstant(m_value); 123 } 124 125 // ------------------------------ NumberNode ---------------------------------- 126 127 RegisterID* 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); 123 132 } 124 133 -
trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
r173069 r180813 96 96 bool isWithinPowerOfTwoNonRecursive(Node* node) 97 97 { 98 if ( node->op() != JSConstant)98 if (!node->isNumberConstant()) 99 99 return false; 100 100 return isWithinPowerOfTwoForConstant<power>(node); … … 105 105 { 106 106 switch (node->op()) { 107 case JSConstant: { 107 case DoubleConstant: 108 case JSConstant: 109 case Int52Constant: { 108 110 return isWithinPowerOfTwoForConstant<power>(node); 109 111 } … … 129 131 130 132 Node* shiftAmount = node->child2().node(); 131 if ( shiftAmount->op() != JSConstant)133 if (!node->isNumberConstant()) 132 134 return false; 133 135 JSValue immediateValue = shiftAmount->asJSValue(); -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r180595 r180813 253 253 unsigned oldSize = m_constants.size(); 254 254 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()); 256 258 if (constantIndex >= oldSize) { 257 259 m_constants.grow(constantIndex + 1); … … 259 261 m_constants[i] = nullptr; 260 262 } 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; 263 270 } 264 271 ASSERT(m_constants[constantIndex]); -
trunk/Source/JavaScriptCore/dfg/DFGCommon.h
r180279 r180813 257 257 } 258 258 259 enum class PlanStage { 260 Initial, 261 AfterFixup 262 }; 263 259 264 template<typename T, typename U> 260 265 bool checkAndSet(T& left, U right) -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r180703 r180813 68 68 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) 69 69 injectTypeConversionsInBlock(m_graph.block(blockIndex)); 70 70 71 m_graph.m_planStage = PlanStage::AfterFixup; 72 71 73 return true; 72 74 } … … 1057 1059 case ValueRep: 1058 1060 case Int52Rep: 1059 case DoubleConstant:1060 1061 case Int52Constant: 1061 1062 case Identity: // This should have been cleaned up. … … 1220 1221 case SetArgument: 1221 1222 case JSConstant: 1223 case DoubleConstant: 1222 1224 case GetLocal: 1223 1225 case GetCallee: -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r180691 r180813 1054 1054 { 1055 1055 m_codeBlock->constants().resize(0); 1056 m_codeBlock->constantsSourceCodeRepresentation().resize(0); 1056 1057 for (FrozenValue* value : m_frozenValues) { 1057 1058 if (value->structure()) … … 1079 1080 } 1080 1081 m_codeBlock->constants().shrinkToFit(); 1082 m_codeBlock->constantsSourceCodeRepresentation().shrinkToFit(); 1081 1083 } 1082 1084 -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r180691 r180813 218 218 219 219 if (left->hasConstant()) 220 return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source);220 return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, right, left, source); 221 221 if (right->hasConstant()) 222 return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source);222 return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, left, right, source); 223 223 224 224 return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32; … … 847 847 GraphForm m_form; 848 848 UnificationState m_unificationState; 849 PlanStage m_planStage { PlanStage::Initial }; 849 850 RefCountState m_refCountState; 850 851 private: … … 852 853 void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor); 853 854 854 AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source)855 AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* operand, Node*immediate, RareCaseProfilingSource source) 855 856 { 856 857 ASSERT(immediate->hasConstant()); … … 862 863 if (!variableShouldSpeculateInt32) 863 864 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()) 866 873 return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32; 867 874 -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r180691 r180813 149 149 break; 150 150 } 151 case DoubleConstant: { 152 SpeculatedType type = speculationFromValue(node->asJSValue()); 153 changed |= setPrediction(type); 154 break; 155 } 151 156 152 157 case GetLocal: { … … 533 538 case ValueRep: 534 539 case Int52Rep: 535 case DoubleConstant:536 540 case Int52Constant: 537 541 case Identity: -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r180691 r180813 119 119 120 120 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); 123 123 VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse)); 124 124 … … 544 544 } 545 545 } 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 547 558 void checkOperand( 548 559 BasicBlock* block, Operands<size_t>& getLocalPositions, -
trunk/Source/JavaScriptCore/parser/ASTBuilder.h
r180518 r180813 193 193 return new (m_parserArena) ArrayNode(location, elisions, elems); 194 194 } 195 ExpressionNode* create NumberExpr(const JSTokenLocation& location, double d)195 ExpressionNode* createDoubleExpr(const JSTokenLocation& location, double d) 196 196 { 197 197 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); 199 204 } 200 205 … … 749 754 m_scope.m_features |= EvalFeature; 750 755 } 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 756 777 VM* m_vm; 757 778 ParserArena& m_parserArena; … … 794 815 { 795 816 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); 799 819 } 800 820 … … 805 825 { 806 826 if (expr->isNumber()) 807 return create Number(location, ~toInt32(static_cast<NumberNode*>(expr)->value()));827 return createIntegerLikeNumber(location, ~toInt32(static_cast<NumberNode*>(expr)->value())); 808 828 return new (m_parserArena) BitwiseNotNode(location, expr); 809 829 } … … 814 834 expr2 = expr2->stripUnaryPlus(); 815 835 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 } 818 841 819 842 if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1) … … 831 854 expr2 = expr2->stripUnaryPlus(); 832 855 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 } 835 864 return new (m_parserArena) DivNode(location, expr1, expr2, rightHasAssignments); 836 865 } … … 840 869 expr1 = expr1->stripUnaryPlus(); 841 870 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 } 845 877 return new (m_parserArena) ModNode(location, expr1, expr2, rightHasAssignments); 846 878 } … … 848 880 ExpressionNode* ASTBuilder::makeAddNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 849 881 { 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 } 852 888 return new (m_parserArena) AddNode(location, expr1, expr2, rightHasAssignments); 853 889 } … … 858 894 expr2 = expr2->stripUnaryPlus(); 859 895 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 } 862 901 return new (m_parserArena) SubNode(location, expr1, expr2, rightHasAssignments); 863 902 } … … 865 904 ExpressionNode* ASTBuilder::makeLeftShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 866 905 { 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 } 869 911 return new (m_parserArena) LeftShiftNode(location, expr1, expr2, rightHasAssignments); 870 912 } … … 872 914 ExpressionNode* ASTBuilder::makeRightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 873 915 { 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 } 876 921 return new (m_parserArena) RightShiftNode(location, expr1, expr2, rightHasAssignments); 877 922 } … … 879 924 ExpressionNode* ASTBuilder::makeURightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 880 925 { 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 } 883 931 return new (m_parserArena) UnsignedRightShiftNode(location, expr1, expr2, rightHasAssignments); 884 932 } … … 886 934 ExpressionNode* ASTBuilder::makeBitOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 887 935 { 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 } 890 941 return new (m_parserArena) BitOrNode(location, expr1, expr2, rightHasAssignments); 891 942 } … … 893 944 ExpressionNode* ASTBuilder::makeBitAndNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 894 945 { 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 } 897 951 return new (m_parserArena) BitAndNode(location, expr1, expr2, rightHasAssignments); 898 952 } … … 900 954 ExpressionNode* ASTBuilder::makeBitXOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) 901 955 { 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 } 904 961 return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments); 905 962 } -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r178427 r180813 496 496 } 497 497 498 static 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 498 505 template <typename T> 499 506 Lexer<T>::~Lexer() … … 1688 1695 goto returnError; 1689 1696 } 1690 token = NUMBER;1697 token = tokenTypeForIntegerLikeToken(tokenData->doubleValue); 1691 1698 m_buffer8.resize(0); 1692 1699 break; … … 1701 1708 if (isASCIIOctalDigit(m_current)) { 1702 1709 if (parseOctal(tokenData->doubleValue)) { 1703 token = NUMBER;1710 token = tokenTypeForIntegerLikeToken(tokenData->doubleValue); 1704 1711 } 1705 1712 } 1706 1713 FALLTHROUGH; 1707 1714 case CharacterNumber: 1708 if (LIKELY(token != NUMBER)) {1715 if (LIKELY(token != INTEGER && token != DOUBLE)) { 1709 1716 if (!parseDecimal(tokenData->doubleValue)) { 1717 token = INTEGER; 1710 1718 if (m_current == '.') { 1711 1719 shift(); 1712 1720 inNumberAfterDecimalPoint: 1713 1721 parseNumberAfterDecimalPoint(); 1722 token = DOUBLE; 1714 1723 } 1715 1724 if ((m_current | 0x20) == 'e') { … … 1722 1731 size_t parsedLength; 1723 1732 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); 1726 1737 } 1727 1738 -
trunk/Source/JavaScriptCore/parser/NodeConstructors.h
r179371 r180813 85 85 } 86 86 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 87 97 inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value) 88 98 : ConstantNode(location, ResultType::stringType()) -
trunk/Source/JavaScriptCore/parser/Nodes.h
r180518 r180813 237 237 public: 238 238 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; } 244 245 virtual JSValue jsValue(BytecodeGenerator&) const override { return jsNumber(m_value); } 245 246 246 247 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; } 247 263 }; 248 264 -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r180518 r180813 630 630 JSTokenType tokenType = m_token.m_type; 631 631 switch (m_token.m_type) { 632 case NUMBER: 632 case DOUBLE: 633 case INTEGER: 633 634 propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue); 634 635 break; … … 1946 1947 return parseGetterSetter(context, complete, type, getterOrSetterStartOffset); 1947 1948 } 1948 case NUMBER: { 1949 case DOUBLE: 1950 case INTEGER: { 1949 1951 double propertyName = m_token.m_data.doubleValue; 1950 1952 next(); … … 1980 1982 if (m_token.m_type == IDENT || m_token.m_type == STRING) 1981 1983 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) 1983 1985 numericPropertyName = m_token.m_data.doubleValue; 1984 1986 else … … 2222 2224 return context.createString(location, ident); 2223 2225 } 2224 case NUMBER: {2226 case DOUBLE: { 2225 2227 double d = m_token.m_data.doubleValue; 2226 2228 JSTokenLocation location(tokenLocation()); 2227 2229 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); 2229 2237 } 2230 2238 case NULLTOKEN: { … … 2578 2586 out.print("Unexpected string literal ", getToken()); 2579 2587 return; 2580 case NUMBER: 2588 case INTEGER: 2589 case DOUBLE: 2581 2590 out.print("Unexpected number '", getToken(), "'"); 2582 2591 return; -
trunk/Source/JavaScriptCore/parser/ParserTokens.h
r178954 r180813 95 95 COMMA, 96 96 QUESTION, 97 NUMBER, 97 INTEGER, 98 DOUBLE, 98 99 IDENT, 99 100 STRING, -
trunk/Source/JavaScriptCore/parser/SyntaxChecker.h
r179371 r180813 72 72 typedef SyntaxChecker FunctionBodyBuilder; 73 73 enum { NoneExpr = 0, 74 ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,74 ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr, 75 75 ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr, 76 76 FunctionExpr, ClassExpr, BracketExpr, DotExpr, CallExpr, … … 152 152 ExpressionType createArray(const JSTokenLocation&, int) { return ArrayLiteralExpr; } 153 153 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; } 155 156 ExpressionType createString(const JSTokenLocation&, const Identifier*) { return StringExpr; } 156 157 ExpressionType createBoolean(const JSTokenLocation&, bool) { return BoolExpr; } -
trunk/Source/JavaScriptCore/runtime/JSCJSValue.h
r180130 r180813 125 125 bool isInt52(double); 126 126 127 enum class SourceCodeRepresentation { 128 Other, 129 Integer, 130 Double 131 }; 132 127 133 class JSValue { 128 134 friend struct EncodedJSValueHashTraits; 135 friend struct EncodedJSValueWithRepresentationHashTraits; 129 136 friend class AssemblyHelpers; 130 137 friend class JIT; … … 449 456 #endif 450 457 451 typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; 458 typedef std::pair<EncodedJSValue, SourceCodeRepresentation> EncodedJSValueWithRepresentation; 459 460 struct 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 467 struct 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 }; 452 478 453 479 // Stand-alone helper functions.
Note:
See TracChangeset
for help on using the changeset viewer.