Changeset 247819 in webkit
- Timestamp:
- Jul 25, 2019 12:50:46 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r247811 r247819 1 2019-07-25 Ross Kirsling <ross.kirsling@sony.com> 2 3 [ESNext] Implement nullish coalescing 4 https://bugs.webkit.org/show_bug.cgi?id=200072 5 6 Reviewed by Darin Adler. 7 8 * stress/nullish-coalescing.js: Added. 9 1 10 2019-07-24 Alexey Shvayka <shvaikalesh@gmail.com> 2 11 -
trunk/Source/JavaScriptCore/ChangeLog
r247811 r247819 1 2019-07-25 Ross Kirsling <ross.kirsling@sony.com> 2 3 [ESNext] Implement nullish coalescing 4 https://bugs.webkit.org/show_bug.cgi?id=200072 5 6 Reviewed by Darin Adler. 7 8 Implement the nullish coalescing proposal, which has now reached Stage 3 at TC39. 9 10 This introduces a ?? operator which: 11 - acts like || but checks for nullishness instead of truthiness 12 - has a precedence lower than || (or any other binary operator) 13 - must be disambiguated with parentheses when combined with || or && 14 15 * bytecompiler/NodesCodegen.cpp: 16 (JSC::CoalesceNode::emitBytecode): Added. 17 Bytecode must use OpIsUndefinedOrNull and not OpNeqNull because of document.all. 18 19 * parser/ASTBuilder.h: 20 (JSC::ASTBuilder::makeBinaryNode): 21 * parser/Lexer.cpp: 22 (JSC::Lexer<T>::lexWithoutClearingLineTerminator): 23 * parser/NodeConstructors.h: 24 (JSC::CoalesceNode::CoalesceNode): Added. 25 * parser/Nodes.h: 26 Introduce new token and AST node. 27 28 * parser/Parser.cpp: 29 (JSC::Parser<LexerType>::parseBinaryExpression): 30 Implement early error. 31 32 * parser/ParserTokens.h: 33 Since this patch needs to shift the value of every binary operator token anyway, 34 let's only bother to increment their LSBs when we actually have a precedence conflict. 35 36 * parser/ResultType.h: 37 (JSC::ResultType::definitelyIsNull const): Added. 38 (JSC::ResultType::mightBeUndefinedOrNull const): Added. 39 (JSC::ResultType::forCoalesce): Added. 40 We can do better than forLogicalOp here; let's be as accurate as possible. 41 42 * runtime/Options.h: 43 Add runtime feature flag. 44 1 45 2019-07-24 Alexey Shvayka <shvaikalesh@gmail.com> 2 46 -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r247088 r247819 2339 2339 } 2340 2340 2341 // ------------------------------ CoalesceNode ---------------------------- 2342 2343 RegisterID* CoalesceNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) 2344 { 2345 RefPtr<RegisterID> temp = generator.tempDestination(dst); 2346 Ref<Label> target = generator.newLabel(); 2347 2348 generator.emitNode(temp.get(), m_expr1); 2349 generator.emitJumpIfFalse(generator.emitUnaryOp<OpIsUndefinedOrNull>(generator.newTemporary(), temp.get()), target.get()); 2350 generator.emitNodeInTailPosition(temp.get(), m_expr2); 2351 generator.emitLabel(target.get()); 2352 2353 return generator.move(dst, temp.get()); 2354 } 2355 2341 2356 // ------------------------------ ConditionalNode ------------------------------ 2342 2357 -
trunk/Source/JavaScriptCore/parser/ASTBuilder.h
r245406 r247819 1394 1394 { 1395 1395 switch (token) { 1396 case COALESCE: 1397 return new (m_parserArena) CoalesceNode(location, lhs.first, rhs.first); 1398 1396 1399 case OR: 1397 1400 return new (m_parserArena) LogicalOpNode(location, lhs.first, rhs.first, OpLogicalOr); -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r245697 r247819 2154 2154 break; 2155 2155 case CharacterQuestion: 2156 shift(); 2157 if (Options::useNullishCoalescing() && m_current == '?') { 2158 shift(); 2159 token = COALESCE; 2160 break; 2161 } 2156 2162 token = QUESTION; 2157 shift();2158 2163 break; 2159 2164 case CharacterTilde: -
trunk/Source/JavaScriptCore/parser/NodeConstructors.h
r238543 r247819 670 670 } 671 671 672 inline CoalesceNode::CoalesceNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2) 673 : ExpressionNode(location, ResultType::forCoalesce(expr1->resultDescriptor(), expr2->resultDescriptor())) 674 , m_expr1(expr1) 675 , m_expr2(expr2) 676 { 677 } 678 672 679 inline ConditionalNode::ConditionalNode(const JSTokenLocation& location, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) 673 680 : ExpressionNode(location) -
trunk/Source/JavaScriptCore/parser/Nodes.h
r245406 r247819 1306 1306 }; 1307 1307 1308 class CoalesceNode final : public ExpressionNode { 1309 public: 1310 CoalesceNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2); 1311 1312 private: 1313 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 1314 1315 ExpressionNode* m_expr1; 1316 ExpressionNode* m_expr2; 1317 }; 1318 1308 1319 // The ternary operator, "m_logical ? m_expr1 : m_expr2" 1309 1320 class ConditionalNode final : public ExpressionNode { -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r246549 r247819 3884 3884 typename TreeBuilder::BinaryExprContext binaryExprContext(context); 3885 3885 JSTokenLocation location(tokenLocation()); 3886 bool hasLogicalOperator = false; 3887 bool hasCoalesceOperator = false; 3888 3886 3889 while (true) { 3887 3890 JSTextPosition exprStart = tokenStartPosition(); … … 3890 3893 TreeExpression current = parseUnaryExpression(context); 3891 3894 failIfFalse(current, "Cannot parse expression"); 3892 3895 3893 3896 context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEndPosition(), lastTokenEndPosition(), initialAssignments != m_parserState.assignmentCount); 3897 int precedence = isBinaryOperator(m_token.m_type); 3898 if (!precedence) 3899 break; 3894 3900 3895 3901 // 12.6 https://tc39.github.io/ecma262/#sec-exp-operator … … 3916 3922 failIfTrue(match(POW) && isUnaryOpExcludingUpdateOp(leadingTokenTypeForUnaryExpression), "Ambiguous unary expression in the left hand side of the exponentiation expression; parentheses must be used to disambiguate the expression"); 3917 3923 3918 int precedence = isBinaryOperator(m_token.m_type); 3919 if (!precedence) 3920 break; 3924 // Mixing ?? with || or && is currently specified as an early error. 3925 // Since ?? is the lowest-precedence binary operator, it suffices to check whether these ever coexist in the operator stack. 3926 if (match(AND) || match(OR)) 3927 hasLogicalOperator = true; 3928 else if (match(COALESCE)) 3929 hasCoalesceOperator = true; 3930 failIfTrue(hasLogicalOperator && hasCoalesceOperator, "Coalescing and logical operators used together in the same expression; parentheses must be used to disambiguate"); 3931 3921 3932 m_parserState.nonTrivialExpressionCount++; 3922 3933 m_parserState.nonLHSCount++; -
trunk/Source/JavaScriptCore/parser/ParserTokens.h
r241201 r247819 149 149 VOIDTOKEN = 7 | UnaryOpTokenFlag | KeywordTokenFlag, 150 150 DELETETOKEN = 8 | UnaryOpTokenFlag | KeywordTokenFlag, 151 OR = 0 | BINARY_OP_PRECEDENCE(1), 152 AND = 1 | BINARY_OP_PRECEDENCE(2), 153 BITOR = 2 | BINARY_OP_PRECEDENCE(3), 154 BITXOR = 3 | BINARY_OP_PRECEDENCE(4), 155 BITAND = 4 | BINARY_OP_PRECEDENCE(5), 156 EQEQ = 5 | BINARY_OP_PRECEDENCE(6), 157 NE = 6 | BINARY_OP_PRECEDENCE(6), 158 STREQ = 7 | BINARY_OP_PRECEDENCE(6), 159 STRNEQ = 8 | BINARY_OP_PRECEDENCE(6), 160 LT = 9 | BINARY_OP_PRECEDENCE(7), 161 GT = 10 | BINARY_OP_PRECEDENCE(7), 162 LE = 11 | BINARY_OP_PRECEDENCE(7), 163 GE = 12 | BINARY_OP_PRECEDENCE(7), 164 INSTANCEOF = 13 | BINARY_OP_PRECEDENCE(7) | KeywordTokenFlag, 165 INTOKEN = 14 | IN_OP_PRECEDENCE(7) | KeywordTokenFlag, 166 LSHIFT = 15 | BINARY_OP_PRECEDENCE(8), 167 RSHIFT = 16 | BINARY_OP_PRECEDENCE(8), 168 URSHIFT = 17 | BINARY_OP_PRECEDENCE(8), 169 PLUS = 18 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag, 170 MINUS = 19 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag, 171 TIMES = 20 | BINARY_OP_PRECEDENCE(10), 172 DIVIDE = 21 | BINARY_OP_PRECEDENCE(10), 173 MOD = 22 | BINARY_OP_PRECEDENCE(10), 174 POW = 23 | BINARY_OP_PRECEDENCE(11) | RightAssociativeBinaryOpTokenFlag, // Make sure that POW has the highest operator precedence. 151 COALESCE = 0 | BINARY_OP_PRECEDENCE(1), 152 OR = 0 | BINARY_OP_PRECEDENCE(2), 153 AND = 0 | BINARY_OP_PRECEDENCE(3), 154 BITOR = 0 | BINARY_OP_PRECEDENCE(4), 155 BITXOR = 0 | BINARY_OP_PRECEDENCE(5), 156 BITAND = 0 | BINARY_OP_PRECEDENCE(6), 157 EQEQ = 0 | BINARY_OP_PRECEDENCE(7), 158 NE = 1 | BINARY_OP_PRECEDENCE(7), 159 STREQ = 2 | BINARY_OP_PRECEDENCE(7), 160 STRNEQ = 3 | BINARY_OP_PRECEDENCE(7), 161 LT = 0 | BINARY_OP_PRECEDENCE(8), 162 GT = 1 | BINARY_OP_PRECEDENCE(8), 163 LE = 2 | BINARY_OP_PRECEDENCE(8), 164 GE = 3 | BINARY_OP_PRECEDENCE(8), 165 INSTANCEOF = 4 | BINARY_OP_PRECEDENCE(8) | KeywordTokenFlag, 166 INTOKEN = 5 | IN_OP_PRECEDENCE(8) | KeywordTokenFlag, 167 LSHIFT = 0 | BINARY_OP_PRECEDENCE(9), 168 RSHIFT = 1 | BINARY_OP_PRECEDENCE(9), 169 URSHIFT = 2 | BINARY_OP_PRECEDENCE(9), 170 PLUS = 0 | BINARY_OP_PRECEDENCE(10) | UnaryOpTokenFlag, 171 MINUS = 1 | BINARY_OP_PRECEDENCE(10) | UnaryOpTokenFlag, 172 TIMES = 0 | BINARY_OP_PRECEDENCE(11), 173 DIVIDE = 1 | BINARY_OP_PRECEDENCE(11), 174 MOD = 2 | BINARY_OP_PRECEDENCE(11), 175 POW = 0 | BINARY_OP_PRECEDENCE(12) | RightAssociativeBinaryOpTokenFlag, // Make sure that POW has the highest operator precedence. 175 176 ERRORTOK = 0 | ErrorTokenFlag, 176 177 UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK = 0 | ErrorTokenFlag | UnterminatedErrorTokenFlag, -
trunk/Source/JavaScriptCore/parser/ResultType.h
r245906 r247819 77 77 } 78 78 79 constexpr bool definitelyIsNull() const 80 { 81 return (m_bits & TypeBits) == TypeMaybeNull; 82 } 83 84 constexpr bool mightBeUndefinedOrNull() const 85 { 86 return m_bits & (TypeMaybeNull | TypeMaybeOther); 87 } 88 79 89 constexpr bool mightBeNumber() const 80 90 { … … 173 183 } 174 184 185 static constexpr ResultType forCoalesce(ResultType op1, ResultType op2) 186 { 187 if (op1.definitelyIsNull()) 188 return op2; 189 if (!op1.mightBeUndefinedOrNull()) 190 return op1; 191 return unknownType(); 192 } 193 175 194 static constexpr ResultType forBitOp() 176 195 { -
trunk/Source/JavaScriptCore/runtime/Options.h
r247713 r247819 495 495 v(bool, useWeakRefs, false, Normal, "Expose the WeakRef constructor.") \ 496 496 v(bool, useBigInt, false, Normal, "If true, we will enable BigInt support.") \ 497 v(bool, useNullishCoalescing, false, Normal, "Enable support for the ?? operator.") \ 497 498 v(bool, useArrayAllocationProfiling, true, Normal, "If true, we will use our normal array allocation profiling. If false, the allocation profile will always claim to be undecided.") \ 498 499 v(bool, forcePolyProto, false, Normal, "If true, create_this will always create an object with a poly proto structure.") \ -
trunk/Tools/ChangeLog
r247818 r247819 1 2019-07-25 Ross Kirsling <ross.kirsling@sony.com> 2 3 [ESNext] Implement nullish coalescing 4 https://bugs.webkit.org/show_bug.cgi?id=200072 5 6 Reviewed by Darin Adler. 7 8 * Scripts/run-jsc-stress-tests: 9 1 10 2019-07-24 Fujii Hironori <Hironori.Fujii@sony.com> 2 11 -
trunk/Tools/Scripts/run-jsc-stress-tests
r247703 r247819 700 700 end 701 701 702 def runNullishCoalescingEnabled(*optionalTestSpecificOptions) 703 run("nullish-coalescing-enabled", "--useNullishCoalescing=true" , *(FTL_OPTIONS + optionalTestSpecificOptions)) 704 end 705 702 706 def runFTLNoCJIT(*optionalTestSpecificOptions) 703 707 run("misc-ftl-no-cjit", *(FTL_OPTIONS + NO_CJIT_OPTIONS + optionalTestSpecificOptions))
Note: See TracChangeset
for help on using the changeset viewer.