Changeset 249117 in webkit
- Timestamp:
- Aug 26, 2019, 2:09:35 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/stress/nullish-coalescing.js (modified) (1 diff)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (modified) (1 diff)
-
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (modified) (1 diff)
-
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/parser/ASTBuilder.h (modified) (4 diffs)
-
Source/JavaScriptCore/parser/NodeConstructors.h (modified) (1 diff)
-
Source/JavaScriptCore/parser/Nodes.h (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r249075 r249117 1 2019-08-26 Ross Kirsling <ross.kirsling@sony.com> 2 3 [JSC] Ensure x?.y ?? z is fast 4 https://bugs.webkit.org/show_bug.cgi?id=200875 5 6 Reviewed by Yusuke Suzuki. 7 8 * stress/nullish-coalescing.js: 9 1 10 2019-08-23 Tadeu Zagallo <tzagallo@apple.com> 2 11 -
trunk/JSTests/stress/nullish-coalescing.js
r248829 r249117 90 90 shouldThrowSyntaxError('0 || 1 && 2 | 3 ^ 4 & 5 == 6 != 7 === 8 !== 9 < 0 > 1 <= 2 >= 3 << 4 >> 5 >>> 6 + 7 - 8 * 9 / 0 % 1 ** 2 ?? 3'); 91 91 shouldThrowSyntaxError('3 ?? 2 ** 1 % 0 / 9 * 8 - 7 + 6 >>> 5 >> 4 << 3 >= 2 <= 1 > 0 < 9 !== 8 === 7 != 6 == 5 & 4 ^ 3 | 2 && 1 || 0'); 92 93 shouldBe(null?.x ?? 3, 3); 94 shouldBe(({})?.x ?? 3, 3); 95 shouldBe(({ x: 0 })?.x ?? 3, 0); 96 shouldBe(null?.() ?? 3, 3); 97 shouldBe((() => 0)?.() ?? 3, 0); 98 shouldBe(({ x: 0 })?.[null?.a ?? 'x'] ?? 3, 0); 99 shouldBe((() => 0)?.(null?.a ?? 'x') ?? 3, 0); -
trunk/Source/JavaScriptCore/ChangeLog
r249095 r249117 1 2019-08-26 Ross Kirsling <ross.kirsling@sony.com> 2 3 [JSC] Ensure x?.y ?? z is fast 4 https://bugs.webkit.org/show_bug.cgi?id=200875 5 6 Reviewed by Yusuke Suzuki. 7 8 We anticipate `x?.y ?? z` to quickly become a common idiom in JS. With a little bytecode rearrangement, 9 we can avoid the "load undefined and check it" dance in the middle and just turn this into two jumps. 10 11 Before: 12 (get x) 13 ----- jundefined_or_null 14 | (get y) 15 | --- jmp 16 > | (load undefined) 17 > - jnundefined_or_null 18 | (get z) 19 > end 20 21 After: 22 (get x) 23 --- jundefined_or_null 24 | (get y) 25 | - jnundefined_or_null 26 > | (get z) 27 > end 28 29 * bytecompiler/BytecodeGenerator.cpp: 30 (JSC::BytecodeGenerator::popOptionalChainTarget): Added specialization. 31 * bytecompiler/BytecodeGenerator.h: 32 * bytecompiler/NodesCodegen.cpp: 33 (JSC::CoalesceNode::emitBytecode): 34 (JSC::OptionalChainNode::emitBytecode): 35 * parser/ASTBuilder.h: 36 (JSC::ASTBuilder::makeDeleteNode): 37 (JSC::ASTBuilder::makeCoalesceNode): Added. 38 (JSC::ASTBuilder::makeBinaryNode): 39 * parser/NodeConstructors.h: 40 (JSC::CoalesceNode::CoalesceNode): 41 * parser/Nodes.h: 42 (JSC::ExpressionNode::isDeleteNode const): Added. (Replaces OptionalChainNode::m_isDelete.) 43 1 44 2019-08-26 Carlos Alberto Lopez Perez <clopez@igalia.com> 2 45 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r248829 r249117 4970 4970 } 4971 4971 4972 void BytecodeGenerator::popOptionalChainTarget() 4973 { 4974 ASSERT(m_optionalChainTargetStack.size()); 4975 emitLabel(m_optionalChainTargetStack.takeLast().get()); 4976 } 4977 4972 4978 void BytecodeGenerator::popOptionalChainTarget(RegisterID* dst, bool isDelete) 4973 4979 { 4974 ASSERT(m_optionalChainTargetStack.size());4975 4976 4980 Ref<Label> endLabel = newLabel(); 4977 4981 emitJump(endLabel.get()); 4978 4982 4979 emitLabel(m_optionalChainTargetStack.takeLast().get());4983 popOptionalChainTarget(); 4980 4984 emitLoad(dst, isDelete ? jsBoolean(true) : jsUndefined()); 4981 4985 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r248846 r249117 961 961 962 962 void pushOptionalChainTarget(); 963 void popOptionalChainTarget(RegisterID* dst, bool isDelete = false); 963 void popOptionalChainTarget(); 964 void popOptionalChainTarget(RegisterID* dst, bool isDelete); 964 965 void emitOptionalCheck(RegisterID* src); 965 966 -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r248829 r249117 2409 2409 { 2410 2410 RefPtr<RegisterID> temp = generator.tempDestination(dst); 2411 Ref<Label> target = generator.newLabel(); 2412 2411 Ref<Label> endLabel = generator.newLabel(); 2412 2413 if (m_hasAbsorbedOptionalChain) 2414 generator.pushOptionalChainTarget(); 2413 2415 generator.emitNode(temp.get(), m_expr1); 2414 generator.emitJumpIfFalse(generator.emitIsUndefinedOrNull(generator.newTemporary(), temp.get()), target.get()); 2416 generator.emitJumpIfFalse(generator.emitIsUndefinedOrNull(generator.newTemporary(), temp.get()), endLabel.get()); 2417 2418 if (m_hasAbsorbedOptionalChain) 2419 generator.popOptionalChainTarget(); 2415 2420 generator.emitNodeInTailPosition(temp.get(), m_expr2); 2416 generator.emitLabel(target.get()); 2417 2421 2422 generator.emitLabel(endLabel.get()); 2418 2423 return generator.move(dst, temp.get()); 2419 2424 } … … 2429 2434 generator.emitNodeInTailPosition(finalDest.get(), m_expr); 2430 2435 if (m_isOutermost) 2431 generator.popOptionalChainTarget(finalDest.get(), m_ isDelete);2436 generator.popOptionalChainTarget(finalDest.get(), m_expr->isDeleteNode()); 2432 2437 2433 2438 return finalDest.get(); -
trunk/Source/JavaScriptCore/parser/ASTBuilder.h
r248829 r249117 153 153 ExpressionNode* makeBitAndNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); 154 154 ExpressionNode* makeBitOrNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); 155 ExpressionNode* makeCoalesceNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right); 155 156 ExpressionNode* makeLeftShiftNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); 156 157 ExpressionNode* makeRightShiftNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); … … 1160 1161 ASSERT(!optionalChain->expr()->isResolveNode()); 1161 1162 optionalChain->setExpr(makeDeleteNode(location, optionalChain->expr(), start, divot, end)); 1162 optionalChain->setIsDelete();1163 1163 return optionalChain; 1164 1164 } … … 1360 1360 } 1361 1361 return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments); 1362 } 1363 1364 ExpressionNode* ASTBuilder::makeCoalesceNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2) 1365 { 1366 // Optimization for `x?.y ?? z`. 1367 if (expr1->isOptionalChain()) { 1368 OptionalChainNode* optionalChain = static_cast<OptionalChainNode*>(expr1); 1369 if (!optionalChain->expr()->isDeleteNode()) { 1370 constexpr bool hasAbsorbedOptionalChain = true; 1371 return new (m_parserArena) CoalesceNode(location, optionalChain->expr(), expr2, hasAbsorbedOptionalChain); 1372 } 1373 } 1374 constexpr bool hasAbsorbedOptionalChain = false; 1375 return new (m_parserArena) CoalesceNode(location, expr1, expr2, hasAbsorbedOptionalChain); 1362 1376 } 1363 1377 … … 1425 1439 switch (token) { 1426 1440 case COALESCE: 1427 return new (m_parserArena)CoalesceNode(location, lhs.first, rhs.first);1441 return makeCoalesceNode(location, lhs.first, rhs.first); 1428 1442 1429 1443 case OR: -
trunk/Source/JavaScriptCore/parser/NodeConstructors.h
r248829 r249117 670 670 } 671 671 672 inline CoalesceNode::CoalesceNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2 )672 inline CoalesceNode::CoalesceNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool hasAbsorbedOptionalChain) 673 673 : ExpressionNode(location, ResultType::forCoalesce(expr1->resultDescriptor(), expr2->resultDescriptor())) 674 674 , m_expr1(expr1) 675 675 , m_expr2(expr2) 676 , m_hasAbsorbedOptionalChain(hasAbsorbedOptionalChain) 676 677 { 677 678 } -
trunk/Source/JavaScriptCore/parser/Nodes.h
r248829 r249117 206 206 virtual bool isBinaryOpNode() const { return false; } 207 207 virtual bool isFunctionCall() const { return false; } 208 virtual bool isDeleteNode() const { return false; } 208 209 virtual bool isOptionalChain() const { return false; } 209 210 … … 995 996 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 996 997 998 bool isDeleteNode() const final { return true; } 999 997 1000 const Identifier& m_ident; 998 1001 }; … … 1004 1007 private: 1005 1008 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 1009 1010 bool isDeleteNode() const final { return true; } 1006 1011 1007 1012 ExpressionNode* m_base; … … 1016 1021 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 1017 1022 1023 bool isDeleteNode() const final { return true; } 1024 1018 1025 ExpressionNode* m_base; 1019 1026 const Identifier& m_ident; … … 1026 1033 private: 1027 1034 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 1035 1036 bool isDeleteNode() const final { return true; } 1028 1037 1029 1038 ExpressionNode* m_expr; … … 1313 1322 class CoalesceNode final : public ExpressionNode { 1314 1323 public: 1315 CoalesceNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2 );1324 CoalesceNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool); 1316 1325 1317 1326 private: … … 1320 1329 ExpressionNode* m_expr1; 1321 1330 ExpressionNode* m_expr2; 1331 bool m_hasAbsorbedOptionalChain; 1322 1332 }; 1323 1333 … … 1329 1339 ExpressionNode* expr() const { return m_expr; } 1330 1340 1331 void setIsDelete() { m_isDelete = true; }1332 1333 1341 private: 1334 1342 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; … … 1338 1346 ExpressionNode* m_expr; 1339 1347 bool m_isOutermost; 1340 bool m_isDelete { false };1341 1348 }; 1342 1349
Note:
See TracChangeset
for help on using the changeset viewer.