Changeset 142491 in webkit
- Timestamp:
- Feb 11, 2013 11:21:10 AM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r142489 r142491 1 2013-02-10 Filip Pizlo <fpizlo@apple.com> 2 3 DFG CompareEq(a, null) and CompareStrictEq(a, const) are unsound with respect to constant folding 4 https://bugs.webkit.org/show_bug.cgi?id=109387 5 6 Reviewed by Oliver Hunt. 7 8 Lock in the decision to use a non-speculative constant comparison as early as possible 9 and don't let the CFA change it by folding constants. This might be a performance 10 penalty on some really weird code (FWIW, I haven't seen this on benchmarks), but on 11 the other hand it completely side-steps the unsoundness that the bug speaks of. 12 13 * dfg/DFGAbstractState.cpp: 14 (JSC::DFG::AbstractState::execute): 15 * dfg/DFGByteCodeParser.cpp: 16 (JSC::DFG::ByteCodeParser::isConstantForCompareStrictEq): 17 (ByteCodeParser): 18 (JSC::DFG::ByteCodeParser::parseBlock): 19 * dfg/DFGCSEPhase.cpp: 20 (JSC::DFG::CSEPhase::performNodeCSE): 21 * dfg/DFGNodeType.h: 22 (DFG): 23 * dfg/DFGPredictionPropagationPhase.cpp: 24 (JSC::DFG::PredictionPropagationPhase::propagate): 25 * dfg/DFGSpeculativeJIT.cpp: 26 (JSC::DFG::SpeculativeJIT::compileStrictEq): 27 * dfg/DFGSpeculativeJIT64.cpp: 28 (JSC::DFG::SpeculativeJIT::compile): 29 1 30 2013-02-11 Csaba Osztrogonác <ossy@webkit.org> 2 31 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
r142481 r142491 779 779 case CompareGreater: 780 780 case CompareGreaterEq: 781 case CompareEq: { 781 case CompareEq: 782 case CompareEqConstant: { 782 783 bool constantWasSet = false; 783 784 … … 810 811 } 811 812 812 if (!constantWasSet && node->op() == CompareEq) {813 if (!constantWasSet && (node->op() == CompareEqConstant || node->op() == CompareEq)) { 813 814 SpeculatedType leftType = forNode(node->child1()).m_type; 814 815 SpeculatedType rightType = forNode(node->child2()).m_type; … … 825 826 826 827 forNode(node).set(SpecBoolean); 828 829 if (node->op() == CompareEqConstant) { 830 // We can exit if we haven't fired the MasqueradesAsUndefind watchpoint yet. 831 node->setCanExit(m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()); 832 break; 833 } 827 834 828 835 Node* left = node->child1().node(); … … 837 844 checker = isNumberSpeculation; 838 845 } else if (node->op() == CompareEq) { 839 if ((m_graph.isConstant(left) && m_graph.valueOfJSConstant(left).isNull())840 || (m_graph.isConstant(right) && m_graph.valueOfJSConstant(right).isNull())) {841 // We can exit if we haven't fired the MasqueradesAsUndefind watchpoint yet.842 node->setCanExit(m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());843 break;844 }845 846 846 if (left->shouldSpeculateString() || right->shouldSpeculateString()) { 847 847 node->setCanExit(false); … … 883 883 } 884 884 885 case CompareStrictEq: { 885 case CompareStrictEq: 886 case CompareStrictEqConstant: { 886 887 Node* leftNode = node->child1().node(); 887 888 Node* rightNode = node->child2().node(); … … 895 896 } 896 897 forNode(node).set(SpecBoolean); 897 if (m_graph.isJSConstant(leftNode)) { 898 JSValue value = m_graph.valueOfJSConstant(leftNode); 899 if (!value.isNumber() && !value.isString()) { 900 node->setCanExit(false); 901 break; 902 } 903 } 904 if (m_graph.isJSConstant(rightNode)) { 905 JSValue value = m_graph.valueOfJSConstant(rightNode); 906 if (!value.isNumber() && !value.isString()) { 907 node->setCanExit(false); 908 break; 909 } 898 if (node->op() == CompareStrictEqConstant) { 899 node->setCanExit(false); 900 break; 910 901 } 911 902 if (Node::shouldSpeculateInteger(leftNode, rightNode)) { -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r142377 r142491 685 685 } 686 686 687 bool isConstantForCompareStrictEq(Node* node) 688 { 689 if (!node->isConstant()) 690 return false; 691 JSValue value = valueOfJSConstant(node); 692 return value.isBoolean() || value.isUndefinedOrNull(); 693 } 694 687 695 // These methods create a node and add it to the graph. If nodes of this type are 688 696 // 'mustGenerate' then the node will implicitly be ref'ed to ensure generation. … … 2419 2427 case op_eq_null: { 2420 2428 Node* value = get(currentInstruction[2].u.operand); 2421 set(currentInstruction[1].u.operand, addToGraph(CompareEq , value, constantNull()));2429 set(currentInstruction[1].u.operand, addToGraph(CompareEqConstant, value, constantNull())); 2422 2430 NEXT_OPCODE(op_eq_null); 2423 2431 } … … 2435 2443 } 2436 2444 } 2437 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2)); 2445 if (isConstantForCompareStrictEq(op1)) 2446 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEqConstant, op2, op1)); 2447 else if (isConstantForCompareStrictEq(op2)) 2448 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEqConstant, op1, op2)); 2449 else 2450 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2)); 2438 2451 NEXT_OPCODE(op_stricteq); 2439 2452 } … … 2457 2470 case op_neq_null: { 2458 2471 Node* value = get(currentInstruction[2].u.operand); 2459 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq , value, constantNull())));2472 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEqConstant, value, constantNull()))); 2460 2473 NEXT_OPCODE(op_neq_null); 2461 2474 } … … 2473 2486 } 2474 2487 } 2475 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2))); 2488 Node* invertedResult; 2489 if (isConstantForCompareStrictEq(op1)) 2490 invertedResult = addToGraph(CompareStrictEqConstant, op2, op1); 2491 else if (isConstantForCompareStrictEq(op2)) 2492 invertedResult = addToGraph(CompareStrictEqConstant, op1, op2); 2493 else 2494 invertedResult = addToGraph(CompareStrictEq, op1, op2); 2495 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, invertedResult)); 2476 2496 NEXT_OPCODE(op_nstricteq); 2477 2497 } … … 2727 2747 unsigned relativeOffset = currentInstruction[2].u.operand; 2728 2748 Node* value = get(currentInstruction[1].u.operand); 2729 Node* condition = addToGraph(CompareEq , value, constantNull());2749 Node* condition = addToGraph(CompareEqConstant, value, constantNull()); 2730 2750 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jeq_null)), condition); 2731 2751 LAST_OPCODE(op_jeq_null); … … 2735 2755 unsigned relativeOffset = currentInstruction[2].u.operand; 2736 2756 Node* value = get(currentInstruction[1].u.operand); 2737 Node* condition = addToGraph(CompareEq , value, constantNull());2757 Node* condition = addToGraph(CompareEqConstant, value, constantNull()); 2738 2758 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_null)), OpInfo(m_currentIndex + relativeOffset), condition); 2739 2759 LAST_OPCODE(op_jneq_null); -
trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
r142481 r142491 1112 1112 case GetScope: 1113 1113 case TypeOf: 1114 case CompareEqConstant: 1114 1115 setReplacement(pureCSE(node)); 1115 1116 break; -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r142377 r142491 187 187 macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \ 188 188 macro(CompareEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \ 189 macro(CompareEqConstant, NodeResultBoolean | NodeMustGenerate) \ 189 190 macro(CompareStrictEq, NodeResultBoolean) \ 191 macro(CompareStrictEqConstant, NodeResultBoolean) \ 190 192 \ 191 193 /* Calls. */\ -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r142377 r142491 509 509 case CompareGreaterEq: 510 510 case CompareEq: 511 case CompareEqConstant: 511 512 case CompareStrictEq: 513 case CompareStrictEqConstant: 512 514 case InstanceOf: 513 515 case IsUndefined: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r141962 r142491 3461 3461 bool SpeculativeJIT::compileStrictEq(Node* node) 3462 3462 { 3463 // 1) If either operand is a constant and that constant is not a double, integer,3464 // or string, then do a JSValue comparison.3465 3466 if (isJSConstant(node->child1().node())) {3467 JSValue value = valueOfJSConstant(node->child1().node());3468 if (!value.isNumber() && !value.isString())3469 return compileStrictEqForConstant(node, node->child2(), value);3470 }3471 3472 if (isJSConstant(node->child2().node())) {3473 JSValue value = valueOfJSConstant(node->child2().node());3474 if (!value.isNumber() && !value.isString())3475 return compileStrictEqForConstant(node, node->child1(), value);3476 }3477 3478 // 2) If the operands are predicted integer, do an integer comparison.3479 3480 3463 if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) { 3481 3464 unsigned branchIndexInBlock = detectPeepHoleBranch(); … … 3492 3475 return false; 3493 3476 } 3494 3495 // 3) If the operands are predicted double, do a double comparison.3496 3477 3497 3478 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) { … … 3526 3507 return false; 3527 3508 } 3528 3529 // 5) Fall back to non-speculative strict equality.3530 3509 3531 3510 return nonSpeculativeStrictEq(node); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r142377 r142491 2514 2514 return; 2515 2515 break; 2516 2517 case CompareEqConstant: 2518 ASSERT(isNullConstant(node->child2().node())); 2519 if (nonSpeculativeCompareNull(node, node->child1())) 2520 return; 2521 break; 2516 2522 2517 2523 case CompareEq: 2518 if (isNullConstant(node->child1().node())) {2519 if (nonSpeculativeCompareNull(node, node->child2()))2520 return;2521 break;2522 }2523 if (isNullConstant(node->child2().node())) {2524 if (nonSpeculativeCompareNull(node, node->child1()))2525 return;2526 break;2527 }2528 2524 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq)) 2525 return; 2526 break; 2527 2528 case CompareStrictEqConstant: 2529 if (compileStrictEqForConstant(node, node->child1(), valueOfJSConstant(node->child2().node()))) 2529 2530 return; 2530 2531 break;
Note: See TracChangeset
for help on using the changeset viewer.