Source/JavaScriptCore/ChangeLog

 12014-02-11 Filip Pizlo <fpizlo@apple.com>
 2
 3 FTL should support CompareEq(ObjectOrOther:, Object:)
 4 https://bugs.webkit.org/show_bug.cgi?id=127752
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Also introduce some helpers for reasoning about nullness and truthyness.
 9
 10 * ftl/FTLCapabilities.cpp:
 11 (JSC::FTL::canCompile):
 12 * ftl/FTLLowerDFGToLLVM.cpp:
 13 (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
 14 (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject):
 15 (JSC::FTL::LowerDFGToLLVM::speculateTruthyObject):
 16 (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
 17 (JSC::FTL::LowerDFGToLLVM::isNotNully):
 18 (JSC::FTL::LowerDFGToLLVM::isNully):
 19 (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
 20 * tests/stress/compare-eq-object-or-other-to-object.js: Added.
 21 (foo):
 22 (test):
 23 * tests/stress/compare-eq-object-to-object-or-other.js: Added.
 24 (foo):
 25 (test):
 26
1272014-02-11 Mark Hahnenberg <mhahnenberg@apple.com>
228
329 32-bit LLInt writeBarrierOnGlobalObject is wrong
163888

Source/JavaScriptCore/ftl/FTLCapabilities.cpp

@@inline CapabilityLevel canCompile(Node*
226226 break;
227227 if (node->isBinaryUseKind(UntypedUse))
228228 break;
 229 if (node->child1().useKind() == ObjectUse
 230 && node->child2().useKind() == ObjectOrOtherUse)
 231 break;
 232 if (node->child1().useKind() == ObjectOrOtherUse
 233 && node->child2().useKind() == ObjectUse)
 234 break;
229235 return CannotCompile;
230236 case CompareStrictEq:
231237 if (node->isBinaryUseKind(Int32Use))
163885

Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

@@private:
32083208 return;
32093209 }
32103210
 3211 if (m_node->child1().useKind() == ObjectUse
 3212 && m_node->child2().useKind() == ObjectOrOtherUse) {
 3213 compareEqObjectOrOtherToObject(m_node->child2(), m_node->child1());
 3214 return;
 3215 }
 3216
 3217 if (m_node->child1().useKind() == ObjectOrOtherUse
 3218 && m_node->child2().useKind() == ObjectUse) {
 3219 compareEqObjectOrOtherToObject(m_node->child2(), m_node->child1());
 3220 return;
 3221 }
 3222
32113223 if (m_node->isBinaryUseKind(UntypedUse)) {
32123224 nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
32133225 return;

@@private:
36063618 RELEASE_ASSERT_NOT_REACHED();
36073619 }
36083620
 3621 void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
 3622 {
 3623 LValue rightCell = lowCell(rightChild);
 3624 LValue leftValue = lowJSValue(leftChild);
 3625
 3626 speculateTruthyObject(rightChild, rightCell, SpecObject);
 3627
 3628 LBasicBlock leftCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left cell case"));
 3629 LBasicBlock leftNotCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left not cell case"));
 3630 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject continuation"));
 3631
 3632 m_out.branch(isCell(leftValue), leftCellCase, leftNotCellCase);
 3633
 3634 LBasicBlock lastNext = m_out.appendTo(leftCellCase, leftNotCellCase);
 3635 speculateTruthyObject(leftChild, leftValue, SpecObject | (~SpecCell));
 3636 ValueFromBlock cellResult = m_out.anchor(m_out.equal(rightCell, leftValue));
 3637 m_out.jump(continuation);
 3638
 3639 m_out.appendTo(leftNotCellCase, continuation);
 3640 FTL_TYPE_CHECK(
 3641 jsValueValue(leftValue), leftChild, SpecOther | SpecCell, isNotNully(leftValue));
 3642 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
 3643 m_out.jump(continuation);
 3644
 3645 m_out.appendTo(continuation, lastNext);
 3646 setBoolean(m_out.phi(m_out.boolean, cellResult, notCellResult));
 3647 }
 3648
 3649 void speculateTruthyObject(Edge edge, LValue cell, SpeculatedType filter)
 3650 {
 3651 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
 3652 FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell));
 3653 return;
 3654 }
 3655
 3656 LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
 3657 FTL_TYPE_CHECK(
 3658 jsValueValue(cell), edge, filter,
 3659 m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())));
 3660 speculate(
 3661 BadType, jsValueValue(cell), edge.node(),
 3662 m_out.testNonZero8(
 3663 m_out.load8(structure, m_heaps.Structure_typeInfoFlags),
 3664 m_out.constInt8(MasqueradesAsUndefined)));
 3665 }
 3666
36093667 void nonSpeculativeCompare(LIntPredicate intCondition, S_JITOperation_EJJ helperFunction)
36103668 {
36113669 LValue left = lowJSValue(m_node->child1());

@@private:
39123970 primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined));
39133971 break;
39143972 case EqualNullOrUndefined:
3915  primitiveResult = m_out.equal(
3916  m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
3917  m_out.constInt64(ValueNull));
 3973 primitiveResult = isNully(value);
39183974 break;
39193975 case SpeculateNullOrUndefined:
39203976 FTL_TYPE_CHECK(
3921  jsValueValue(value), edge, SpecCell | SpecOther,
3922  m_out.notEqual(
3923  m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
3924  m_out.constInt64(ValueNull)));
 3977 jsValueValue(value), edge, SpecCell | SpecOther, isNotNully(value));
39253978 primitiveResult = m_out.booleanTrue;
39263979 break;
39273980 }

@@private:
45674620 return m_out.select(
45684621 value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse));
45694622 }
 4623
 4624 LValue isNotNully(LValue value)
 4625 {
 4626 return m_out.notEqual(
 4627 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
 4628 m_out.constInt64(ValueNull));
 4629 }
 4630 LValue isNully(LValue value)
 4631 {
 4632 return m_out.equal(
 4633 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
 4634 m_out.constInt64(ValueNull));
 4635 }
45704636
45714637 void speculate(Edge edge)
45724638 {

@@private:
47544820 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
47554821
47564822 FTL_TYPE_CHECK(
4757  jsValueValue(value), edge, (~SpecCell) | SpecObject,
4758  m_out.equal(
4759  m_out.loadPtr(value, m_heaps.JSCell_structure),
4760  m_out.constIntPtr(vm().stringStructure.get())));
 4823 jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value));
47614824
47624825 m_out.jump(continuation);
47634826
47644827 m_out.appendTo(primitiveCase, continuation);
47654828
47664829 FTL_TYPE_CHECK(
4767  jsValueValue(value), edge, SpecCell | SpecOther,
4768  m_out.notEqual(
4769  m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
4770  m_out.constInt64(ValueNull)));
 4830 jsValueValue(value), edge, SpecCell | SpecOther, isNotNully(value));
47714831
47724832 m_out.jump(continuation);
47734833
163885

Source/JavaScriptCore/tests/stress/compare-eq-object-or-other-to-object.js

 1function foo(a, b) {
 2 return a == b;
 3}
 4
 5noInline(foo);
 6
 7function test(a, b, expected) {
 8 var result = foo(a, b);
 9 if (result != expected)
 10 throw new Error("Unexpected result: " + result);
 11}
 12
 13for (var i = 0; i < 100000; ++i) {
 14 var o = {f:42};
 15 var p = {g:43};
 16 test(o, o, true);
 17 test(o, p, false);
 18 test(p, o, false);
 19 test(p, p, true);
 20 test(null, o, false);
 21 test(null, p, false);
 22 test(void 0, o, false);
 23 test(void 0, p, false);
 24}
0

Source/JavaScriptCore/tests/stress/compare-eq-object-to-object-or-other.js

 1function foo(a, b) {
 2 return a == b;
 3}
 4
 5noInline(foo);
 6
 7function test(a, b, expected) {
 8 var result = foo(a, b);
 9 if (result != expected)
 10 throw new Error("Unexpected result: " + result);
 11}
 12
 13for (var i = 0; i < 100000; ++i) {
 14 var o = {f:42};
 15 var p = {g:43};
 16 test(o, o, true);
 17 test(o, p, false);
 18 test(p, o, false);
 19 test(p, p, true);
 20 test(o, null, false);
 21 test(p, null, false);
 22 test(o, void 0, false);
 23 test(p, void 0, false);
 24}
0