WebKit Bugzilla
Attachment 339084 Details for
Bug 185065
: [JSC] Add SameValue DFG node
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-185065-20180429025242.patch (text/plain), 47.37 KB, created by
Yusuke Suzuki
on 2018-04-28 18:52:44 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-04-28 18:52:44 PDT
Size:
47.37 KB
patch
obsolete
>Subversion Revision: 231086 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index de2aa449ca5792a81320f11fff5c72bbfe8c4de1..5f9cd7e11eb9799d7bf1bf8f579b4b225c8232af 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,73 @@ >+2018-04-28 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ Poor Object.is performance >+ https://bugs.webkit.org/show_bug.cgi?id=185065 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch adds Object.is handling in DFG and FTL. Object.is is converted to SameValue DFG node. >+ And DFG fixup phase attempts to convert SameValue node to CompareStrictEq with type filter edges >+ if possible. Since SameValue(Untyped, Untyped) and SameValue(Double, Double) have different semantics >+ from CompareStrictEq, we do not convert SameValue to CompareStrictEq for them. DFG and FTL have >+ implementations for these SameValue nodes. >+ >+ This old MacroAssemblerX86Common::compareDouble was dead code since the derived class, "MacroAssembler" >+ has a generalized compareDouble, which just uses branchDouble. Since this was not used, this function >+ was broken. This patch fixes issues and move compareDouble to MacroAssemblerX86Common, and remove a >+ generalized compareDouble for x86 arch to use this specialized efficient version instead. The fixes are >+ correctly using set32 to zero-extending the result, and setting the initial value of `dest` register >+ correctly for DoubleEqual and DoubleNotEqualOrUnordered cases. >+ >+ Added microbenchmark shows performance improvement. >+ >+ object-is 651.0053+-38.8204 ^ 241.3467+-15.8753 ^ definitely 2.6974x faster >+ >+ * assembler/MacroAssembler.h: >+ * assembler/MacroAssemblerX86Common.h: >+ (JSC::MacroAssemblerX86Common::compareDouble): >+ * assembler/MacroAssemblerX86_64.h: >+ (JSC::MacroAssemblerX86_64::compareDouble): Deleted. >+ * assembler/testmasm.cpp: >+ (JSC::doubleOperands): >+ (JSC::testCompareDouble): >+ (JSC::run): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ (JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileSameValue): >+ * dfg/DFGSpeculativeJIT.h: >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGValidate.cpp: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileSameValue): >+ * runtime/Intrinsic.cpp: >+ (JSC::intrinsicName): >+ * runtime/Intrinsic.h: >+ * runtime/ObjectConstructor.cpp: >+ > 2018-04-26 Caio Lima <ticaiolima@gmail.com> > > [ESNext][BigInt] Implement support for "*" operation >diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h >index d25da3c1d74df60d0cc38899c30dd528c72929cd..8679261fb8eb88898c4d06ee1cd789c19a874cfe 100644 >--- a/Source/JavaScriptCore/assembler/MacroAssembler.h >+++ b/Source/JavaScriptCore/assembler/MacroAssembler.h >@@ -1459,9 +1459,10 @@ class MacroAssembler : public MacroAssemblerBase { > > #endif // !CPU(X86_64) > >-#if ENABLE(B3_JIT) > // We should implement this the right way eventually, but for now, it's fine because it arises so > // infrequently. >+ >+#if !CPU(X86) && !CPU(X86_64) > void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest) > { > move(TrustedImm32(0), dest); >@@ -1469,6 +1470,9 @@ class MacroAssembler : public MacroAssemblerBase { > move(TrustedImm32(1), dest); > falseCase.link(this); > } >+#endif >+ >+#if ENABLE(B3_JIT) > void compareFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest) > { > move(TrustedImm32(0), dest); >diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >index e8c859906fee12ed5e1a8906a95fa42738ba01e9..d969e854cd7d2bca01c57d4101c4be785254fd8e 100644 >--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >@@ -2004,6 +2004,48 @@ class MacroAssemblerX86Common : public AbstractMacroAssembler<Assembler> { > return jumpAfterFloatingPointCompare(cond, left, right); > } > >+ void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest) >+ { >+ if (cond & DoubleConditionBitSpecial) { >+ ASSERT(!(cond & DoubleConditionBitInvert)); >+ if (cond == DoubleEqual) { >+ if (left == right) { >+ m_assembler.ucomisd_rr(right, left); >+ set32(X86Assembler::ConditionNP, dest); >+ return; >+ } >+ >+ move(TrustedImm32(0), dest); >+ m_assembler.ucomisd_rr(right, left); >+ Jump isUnordered = m_assembler.jp(); >+ set32(X86Assembler::ConditionE, dest); >+ isUnordered.link(this); >+ return; >+ } >+ if (cond == DoubleNotEqualOrUnordered) { >+ if (left == right) { >+ m_assembler.ucomisd_rr(right, left); >+ set32(X86Assembler::ConditionP, dest); >+ return; >+ } >+ >+ move(TrustedImm32(1), dest); >+ m_assembler.ucomisd_rr(right, left); >+ Jump isUnordered = m_assembler.jp(); >+ set32(X86Assembler::ConditionNE, dest); >+ isUnordered.link(this); >+ return; >+ } >+ return; >+ } >+ >+ if (cond & DoubleConditionBitInvert) >+ m_assembler.ucomisd_rr(left, right); >+ else >+ m_assembler.ucomisd_rr(right, left); >+ set32(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), dest); >+ } >+ > // Truncates 'src' to an integer, and places the resulting 'dest'. > // If the result is not representable as a 32 bit value, branch. > // May also branch for some values that are representable in 32 bits >diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >index d4428cc53d0529a5c1a27b93d2e1c13a66a13790..d550a88a1f89b0fd49f4d7d34a5409bd9ad33db2 100644 >--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >@@ -983,40 +983,6 @@ class MacroAssemblerX86_64 : public MacroAssemblerX86Common { > set32(x86Condition(cond), dest); > } > >- void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest) >- { >- if (cond & DoubleConditionBitInvert) >- m_assembler.ucomisd_rr(left, right); >- else >- m_assembler.ucomisd_rr(right, left); >- >- if (cond == DoubleEqual) { >- if (left == right) { >- m_assembler.setnp_r(dest); >- return; >- } >- >- Jump isUnordered(m_assembler.jp()); >- m_assembler.sete_r(dest); >- isUnordered.link(this); >- return; >- } >- >- if (cond == DoubleNotEqualOrUnordered) { >- if (left == right) { >- m_assembler.setp_r(dest); >- return; >- } >- >- m_assembler.setp_r(dest); >- m_assembler.setne_r(dest); >- return; >- } >- >- ASSERT(!(cond & DoubleConditionBitSpecial)); >- m_assembler.setCC_r(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), dest); >- } >- > Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right) > { > m_assembler.cmpq_rr(right, left); >diff --git a/Source/JavaScriptCore/assembler/testmasm.cpp b/Source/JavaScriptCore/assembler/testmasm.cpp >index f18c412154492285c44b50f5767d812cd91f4eb4..e4fe153baff233b393895e5d708eb1221106d84c 100644 >--- a/Source/JavaScriptCore/assembler/testmasm.cpp >+++ b/Source/JavaScriptCore/assembler/testmasm.cpp >@@ -227,6 +227,67 @@ void testBranchTruncateDoubleToInt32(double val, int32_t expected) > } > > >+static Vector<double> doubleOperands() >+{ >+ return Vector<double> { >+ 0, >+ -0, >+ 1, >+ -1, >+ 42, >+ -42, >+ std::numeric_limits<double>::max(), >+ std::numeric_limits<double>::min(), >+ std::numeric_limits<double>::lowest(), >+ std::numeric_limits<double>::quiet_NaN(), >+ std::numeric_limits<double>::infinity(), >+ -std::numeric_limits<double>::infinity(), >+ }; >+} >+ >+ >+void testCompareDouble(MacroAssembler::DoubleCondition condition) >+{ >+ double arg1 = 0; >+ double arg2 = 0; >+ >+ auto compareDouble = compile([&, condition] (CCallHelpers& jit) { >+ jit.emitFunctionPrologue(); >+ >+ jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0); >+ jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1); >+ jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR); >+ jit.compareDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, GPRInfo::returnValueGPR); >+ >+ jit.emitFunctionEpilogue(); >+ jit.ret(); >+ }); >+ >+ auto compareDoubleGeneric = compile([&, condition] (CCallHelpers& jit) { >+ jit.emitFunctionPrologue(); >+ >+ jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0); >+ jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1); >+ jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR); >+ auto jump = jit.branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1); >+ jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR); >+ jump.link(&jit); >+ >+ jit.emitFunctionEpilogue(); >+ jit.ret(); >+ }); >+ >+ auto operands = doubleOperands(); >+ for (auto a : operands) { >+ for (auto b : operands) { >+ arg1 = a; >+ arg2 = b; >+ CHECK_EQ(invoke<int>(compareDouble), invoke<int>(compareDoubleGeneric)); >+ } >+ } >+} >+ >+ > #if ENABLE(MASM_PROBE) > void testProbeReadsArgumentRegisters() > { >@@ -787,6 +848,19 @@ void run(const char* filter) > // reset to check a conversion result > RUN(testBranchTruncateDoubleToInt32(123, 123)); > >+ RUN(testCompareDouble(MacroAssembler::DoubleEqual)); >+ RUN(testCompareDouble(MacroAssembler::DoubleNotEqual)); >+ RUN(testCompareDouble(MacroAssembler::DoubleGreaterThan)); >+ RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqual)); >+ RUN(testCompareDouble(MacroAssembler::DoubleLessThan)); >+ RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqual)); >+ RUN(testCompareDouble(MacroAssembler::DoubleEqualOrUnordered)); >+ RUN(testCompareDouble(MacroAssembler::DoubleNotEqualOrUnordered)); >+ RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrUnordered)); >+ RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered)); >+ RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrUnordered)); >+ RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered)); >+ > #if ENABLE(MASM_PROBE) > RUN(testProbeReadsArgumentRegisters()); > RUN(testProbeWritesArgumentRegisters()); >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 6f857340b0f79420a7035e4d7d59116451d6e214..da69f44b92e1fbb56ce4ba5880af85ed7048dd97 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -1673,7 +1673,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >- case CompareStrictEq: { >+ case CompareStrictEq: >+ case SameValue: { > Node* leftNode = node->child1().node(); > Node* rightNode = node->child2().node(); > JSValue left = forNode(leftNode).value(); >@@ -1689,7 +1690,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > } else { >- setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right))); >+ if (node->op() == CompareStrictEq) >+ setConstant(node, jsBoolean(JSValue::strictEqual(nullptr, left, right))); >+ else >+ setConstant(node, jsBoolean(sameValue(nullptr, left, right))); > break; > } > } >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index 66132faa0d0c9a1ba5490eed06cd6e653e2bfc15..6576b4eeb11cc803bb556c3ab2fb212a231d1a7b 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -2639,6 +2639,15 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > return true; > } > >+ case ObjectIsIntrinsic: { >+ if (argumentCountIncludingThis != 3) >+ return false; >+ >+ insertChecks(); >+ set(VirtualRegister(resultOperand), addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); >+ return true; >+ } >+ > case ReflectGetPrototypeOfIntrinsic: { > if (argumentCountIncludingThis != 2) > return false; >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 24fd9413cab494fb7f5eaf367b12b604671bab4f..8a73652119794caa3391023efcf4f827836e40a4 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -165,6 +165,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case GetGlobalObject: > case StringCharCodeAt: > case CompareStrictEq: >+ case SameValue: > case IsEmpty: > case IsUndefined: > case IsBoolean: >diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >index e4650ac3080f6b420b6378b665ced526bb9de5a7..7e2c754d3bdde7abc20ea683cfeba655c4961fae 100644 >--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >@@ -140,7 +140,8 @@ class ConstantFoldingPhase : public Phase { > break; > } > >- case CompareStrictEq: { >+ case CompareStrictEq: >+ case SameValue: { > if (node->isBinaryUseKind(UntypedUse)) { > JSValue child1Constant = m_state.forNode(node->child1().node()).value(); > JSValue child2Constant = m_state.forNode(node->child2().node()).value(); >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 390b4e3a1bd22c752ddbfe4bebea26a52efa7083..3ef8f58a26d25d928a9b1da3a09e1f9059186170 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -153,6 +153,7 @@ bool doesGC(Graph& graph, Node* node) > case CompareEq: > case CompareStrictEq: > case CompareEqPtr: >+ case SameValue: > case Call: > case DirectCall: > case TailCallInlinedCaller: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 47d0e66b38602191edc7054c619d1b6f61313ac6..d822737a192ee7a2d05f568cbc65e08298dfd13f 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -589,106 +589,12 @@ class FixupPhase : public Phase { > break; > } > >- case CompareStrictEq: { >- if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) { >- fixEdge<BooleanUse>(node->child1()); >- fixEdge<BooleanUse>(node->child2()); >- break; >- } >- if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) { >- fixEdge<Int32Use>(node->child1()); >- fixEdge<Int32Use>(node->child2()); >- break; >- } >- if (enableInt52() >- && Node::shouldSpeculateAnyInt(node->child1().node(), node->child2().node())) { >- fixEdge<Int52RepUse>(node->child1()); >- fixEdge<Int52RepUse>(node->child2()); >- break; >- } >- if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) { >- fixEdge<DoubleRepUse>(node->child1()); >- fixEdge<DoubleRepUse>(node->child2()); >- break; >- } >- if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) { >- fixEdge<SymbolUse>(node->child1()); >- fixEdge<SymbolUse>(node->child2()); >- break; >- } >- if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) { >- fixEdge<BigIntUse>(node->child1()); >- fixEdge<BigIntUse>(node->child2()); >- break; >- } >- if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) { >- fixEdge<StringIdentUse>(node->child1()); >- fixEdge<StringIdentUse>(node->child2()); >- break; >- } >- if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) { >- fixEdge<StringUse>(node->child1()); >- fixEdge<StringUse>(node->child2()); >- break; >- } >- WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint(); >- if (masqueradesAsUndefinedWatchpoint->isStillValid()) { >- >- if (node->child1()->shouldSpeculateObject()) { >- m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); >- fixEdge<ObjectUse>(node->child1()); >- break; >- } >- if (node->child2()->shouldSpeculateObject()) { >- m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); >- fixEdge<ObjectUse>(node->child2()); >- break; >- } >- >- } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) { >- fixEdge<ObjectUse>(node->child1()); >- fixEdge<ObjectUse>(node->child2()); >- break; >- } >- if (node->child1()->shouldSpeculateSymbol()) { >- fixEdge<SymbolUse>(node->child1()); >- break; >- } >- if (node->child2()->shouldSpeculateSymbol()) { >- fixEdge<SymbolUse>(node->child2()); >- break; >- } >- if (node->child1()->shouldSpeculateMisc()) { >- fixEdge<MiscUse>(node->child1()); >- break; >- } >- if (node->child2()->shouldSpeculateMisc()) { >- fixEdge<MiscUse>(node->child2()); >- break; >- } >- if (node->child1()->shouldSpeculateStringIdent() >- && node->child2()->shouldSpeculateNotStringVar()) { >- fixEdge<StringIdentUse>(node->child1()); >- fixEdge<NotStringVarUse>(node->child2()); >- break; >- } >- if (node->child2()->shouldSpeculateStringIdent() >- && node->child1()->shouldSpeculateNotStringVar()) { >- fixEdge<StringIdentUse>(node->child2()); >- fixEdge<NotStringVarUse>(node->child1()); >- break; >- } >- if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { >- fixEdge<StringUse>(node->child1()); >- break; >- } >- if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { >- fixEdge<StringUse>(node->child2()); >- break; >- } >+ case CompareStrictEq: >+ case SameValue: { >+ fixupCompareStrictEqAndSameValue(node); > break; > } >- >+ > case StringFromCharCode: > if (node->child1()->shouldSpeculateInt32()) { > fixEdge<Int32Use>(node->child1()); >@@ -3474,6 +3380,138 @@ class FixupPhase : public Phase { > } > } > >+ void fixupCompareStrictEqAndSameValue(Node* node) >+ { >+ ASSERT(node->op() == SameValue || node->op() == CompareStrictEq); >+ >+ if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) { >+ fixEdge<BooleanUse>(node->child1()); >+ fixEdge<BooleanUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) { >+ fixEdge<Int32Use>(node->child1()); >+ fixEdge<Int32Use>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (enableInt52() >+ && Node::shouldSpeculateAnyInt(node->child1().node(), node->child2().node())) { >+ fixEdge<Int52RepUse>(node->child1()); >+ fixEdge<Int52RepUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) { >+ fixEdge<DoubleRepUse>(node->child1()); >+ fixEdge<DoubleRepUse>(node->child2()); >+ // Do not convert SameValue to CompareStrictEq in this case since SameValue(NaN, NaN) and SameValue(-0, +0) >+ // are not the same to CompareStrictEq(NaN, NaN) and CompareStrictEq(-0, +0). >+ return; >+ } >+ if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) { >+ fixEdge<SymbolUse>(node->child1()); >+ fixEdge<SymbolUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) { >+ fixEdge<BigIntUse>(node->child1()); >+ fixEdge<BigIntUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) { >+ fixEdge<StringIdentUse>(node->child1()); >+ fixEdge<StringIdentUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) { >+ fixEdge<StringUse>(node->child1()); >+ fixEdge<StringUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ >+ if (node->op() == SameValue) { >+ if (node->child1()->shouldSpeculateObject()) { >+ fixEdge<ObjectUse>(node->child1()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child2()->shouldSpeculateObject()) { >+ fixEdge<ObjectUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ } else { >+ WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint(); >+ if (masqueradesAsUndefinedWatchpoint->isStillValid()) { >+ if (node->child1()->shouldSpeculateObject()) { >+ m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); >+ fixEdge<ObjectUse>(node->child1()); >+ return; >+ } >+ if (node->child2()->shouldSpeculateObject()) { >+ m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); >+ fixEdge<ObjectUse>(node->child2()); >+ return; >+ } >+ } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) { >+ fixEdge<ObjectUse>(node->child1()); >+ fixEdge<ObjectUse>(node->child2()); >+ return; >+ } >+ } >+ >+ if (node->child1()->shouldSpeculateSymbol()) { >+ fixEdge<SymbolUse>(node->child1()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child2()->shouldSpeculateSymbol()) { >+ fixEdge<SymbolUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child1()->shouldSpeculateMisc()) { >+ fixEdge<MiscUse>(node->child1()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child2()->shouldSpeculateMisc()) { >+ fixEdge<MiscUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child1()->shouldSpeculateStringIdent() >+ && node->child2()->shouldSpeculateNotStringVar()) { >+ fixEdge<StringIdentUse>(node->child1()); >+ fixEdge<NotStringVarUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child2()->shouldSpeculateStringIdent() >+ && node->child1()->shouldSpeculateNotStringVar()) { >+ fixEdge<StringIdentUse>(node->child2()); >+ fixEdge<NotStringVarUse>(node->child1()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { >+ fixEdge<StringUse>(node->child1()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { >+ fixEdge<StringUse>(node->child2()); >+ node->setOpAndDefaultFlags(CompareStrictEq); >+ return; >+ } >+ } >+ > void fixupChecksInBlock(BasicBlock* block) > { > if (!block) >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index d630b1d61ec6f36a7023b9a63d68749bb0b2b964..ef38620afc5dde20609d6389ee8126318d114ac8 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -294,6 +294,7 @@ namespace JSC { namespace DFG { > macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \ > macro(CompareStrictEq, NodeResultBoolean) \ > macro(CompareEqPtr, NodeResultBoolean) \ >+ macro(SameValue, NodeResultBoolean) \ > \ > /* Calls. */\ > macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index f8fa9295ffdb7e93986949e5e3f07126f9c53407..e79d5852001e976e9e49b2319f0afbd56ed50d26 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -1237,6 +1237,14 @@ size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, > return JSValue::strictEqualSlowCaseInline(exec, op1, op2); > } > >+size_t JIT_OPERATION operationSameValue(ExecState* exec, EncodedJSValue arg1, EncodedJSValue arg2) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ >+ return sameValue(exec, JSValue::decode(arg1), JSValue::decode(arg2)); >+} >+ > EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) > { > VM* vm = &exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index f48f9ab89f18f9e2219987bea6cc31ff1391b0d1..dd62b4ecd600d7ea78b5f728a156803f37644512 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -161,6 +161,7 @@ size_t JIT_OPERATION operationRegExpTestString(ExecState*, JSGlobalObject*, RegE > size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL; > size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; > size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >+size_t JIT_OPERATION operationSameValue(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; > JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue); > JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, uint32_t length, uint32_t minCapacity); > JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, uint32_t argumentCount); >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index 47743853bc97aa61a893d842eef1cffa5cd496b5..2f67cda801233c61d19370785d67ae959ed71019 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -850,6 +850,7 @@ class PredictionPropagationPhase : public Phase { > case CompareEq: > case CompareStrictEq: > case CompareEqPtr: >+ case SameValue: > case OverridesHasInstance: > case InstanceOf: > case InstanceOfCustom: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 6bc74513eee8da31cd49342738af1a703a735de3..f62be0b2e3a47379e1dd1b56743efb4c8123a1e0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -278,6 +278,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) > case CompareEq: > case CompareStrictEq: > case CompareEqPtr: >+ case SameValue: > case Call: > case DirectCall: > case TailCallInlinedCaller: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index df692279582d9a5e7fcda01e458ebbb0106fbcdf..e492746859e8dd113ea0c77a1aac151a19269b9d 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -6365,6 +6365,73 @@ void SpeculativeJIT::compileStringIdentCompare(Node* node, MacroAssembler::Relat > unblessedBooleanResult(resultGPR, node); > } > >+void SpeculativeJIT::compileSameValue(Node* node) >+{ >+ if (node->isBinaryUseKind(DoubleRepUse)) { >+ SpeculateDoubleOperand arg1(this, node->child1()); >+ SpeculateDoubleOperand arg2(this, node->child2()); >+ GPRTemporary result(this); >+ GPRTemporary temp(this); >+ GPRTemporary temp2(this); >+ >+ FPRReg arg1FPR = arg1.fpr(); >+ FPRReg arg2FPR = arg2.fpr(); >+ GPRReg resultGPR = result.gpr(); >+ GPRReg tempGPR = temp.gpr(); >+ GPRReg temp2GPR = temp2.gpr(); >+ >+ m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg1FPR, arg1FPR, tempGPR); >+ m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg2FPR, arg2FPR, temp2GPR); >+ m_jit.or32(tempGPR, temp2GPR, resultGPR); >+ auto notNaNCase = m_jit.branchTest32(CCallHelpers::Zero, resultGPR); >+ m_jit.and32(tempGPR, temp2GPR, resultGPR); >+ auto done = m_jit.jump(); >+ >+ notNaNCase.link(&m_jit); >+ // Here, resultGPR is 0. >+#if USE(JSVALUE64) >+ m_jit.moveDoubleTo64(arg1FPR, tempGPR); >+ m_jit.moveDoubleTo64(arg2FPR, temp2GPR); >+ m_jit.compare64(CCallHelpers::Equal, tempGPR, temp2GPR, resultGPR); >+#else >+ GPRTemporary temp3(this); >+ GPRTemporary temp4(this); >+ >+ GPRReg temp3GPR = temp.gpr(); >+ GPRReg temp4GPR = temp2.gpr(); >+ >+ m_jit.moveDoubleToInts(arg1FPR, tempGPR, temp2GPR); >+ m_jit.moveDoubleToInts(arg2FPR, temp3GPR, temp4GPR); >+ auto notEqual = m_jit.branch32(CCallHelpers::NotEqual, tempGPR, temp3GPR); >+ m_jit.compare32(CCallHelpers::Equal, temp2GPR, temp4GPR, resultGPR); >+ notEqual.link(&m_jit); >+#endif >+ >+ done.link(&m_jit); >+ unblessedBooleanResult(resultGPR, node); >+ return; >+ } >+ >+ ASSERT(node->isBinaryUseKind(UntypedUse)); >+ >+ JSValueOperand arg1(this, node->child1()); >+ JSValueOperand arg2(this, node->child2()); >+ JSValueRegs arg1Regs = arg1.jsValueRegs(); >+ JSValueRegs arg2Regs = arg2.jsValueRegs(); >+ >+ arg1.use(); >+ arg2.use(); >+ >+ flushRegisters(); >+ >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ callOperation(operationSameValue, resultGPR, arg1Regs, arg2Regs); >+ m_jit.exceptionCheck(); >+ >+ unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly); >+} >+ > void SpeculativeJIT::compileStringZeroLength(Node* node) > { > SpeculateCellOperand str(this, node->child1()); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index bbf174c7f7438d85fce7584df00ade6f3befcc14..7097ab8ee0bad8c763b8218d08634df772ace15b 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1263,6 +1263,8 @@ class SpeculativeJIT { > void compileStringIdentCompare(Node*, MacroAssembler::RelationalCondition); > > bool compileStrictEq(Node*); >+ >+ void compileSameValue(Node*); > > void compileAllocatePropertyStorage(Node*); > void compileReallocatePropertyStorage(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 99bfa09880d49879637bf8a0732690a8e615ad4b..55709f930ee787e5f9afb8ca28116a6ae986cfd0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2211,6 +2211,10 @@ void SpeculativeJIT::compile(Node* node) > compileCompareEqPtr(node); > break; > >+ case SameValue: >+ compileSameValue(node); >+ break; >+ > case StringCharCodeAt: { > compileGetCharCodeAt(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 5c980e4a1f4549dcd7119d69e2f4bcf23c93664b..5119348387b42aef616ea61edd5f1c0562d979d9 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2377,6 +2377,10 @@ void SpeculativeJIT::compile(Node* node) > compileCompareEqPtr(node); > break; > >+ case SameValue: >+ compileSameValue(node); >+ break; >+ > case StringCharCodeAt: { > compileGetCharCodeAt(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp >index e94783353042c980205451d9a0fa488afaf6632b..d7726bbe1df4c2b0b72d97304bf8777cbdd1e53d 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -271,6 +271,7 @@ class Validate { > case CompareBelowEq: > case CompareEq: > case CompareStrictEq: >+ case SameValue: > case StrCat: > VALIDATE((node), !!node->child1()); > VALIDATE((node), !!node->child2()); >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index f1a45a8dd64b4f29409fc0bd41452ff70c809cbb..3beecaf728a5c1906be10732ecfdeadc2cb01f6a 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -313,6 +313,7 @@ inline CapabilityLevel canCompile(Node* node) > case CompareBelow: > case CompareBelowEq: > case CompareStrictEq: >+ case SameValue: > case DefineDataProperty: > case DefineAccessorProperty: > case StringSlice: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index cc3ee9842db38d236d7111d768acd60557351c0c..92052c0e9dca5ef918a65dcac3fdc57f0c043896 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -984,6 +984,9 @@ class LowerDFGToB3 { > case CompareEqPtr: > compileCompareEqPtr(); > break; >+ case SameValue: >+ compileSameValue(); >+ break; > case LogicalNot: > compileLogicalNot(); > break; >@@ -7063,6 +7066,47 @@ class LowerDFGToB3 { > { > setBoolean(m_out.belowOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); > } >+ >+ void compileSameValue() >+ { >+ if (m_node->isBinaryUseKind(DoubleRepUse)) { >+ LValue arg1 = lowDouble(m_node->child1()); >+ LValue arg2 = lowDouble(m_node->child2()); >+ >+ LBasicBlock numberCase = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ LValue isArg1NaN = m_out.doubleNotEqualOrUnordered(arg1, arg1); >+ LValue isArg2NaN = m_out.doubleNotEqualOrUnordered(arg2, arg2); >+ >+ ValueFromBlock nanResult = m_out.anchor(m_out.bitAnd(isArg1NaN, isArg2NaN)); >+ m_out.branch(m_out.bitOr(isArg1NaN, isArg2NaN), unsure(continuation), unsure(numberCase)); >+ >+ LBasicBlock lastNext = m_out.appendTo(numberCase, continuation); >+ >+ PatchpointValue* patchpoint = m_out.patchpoint(Int32); >+ patchpoint->append(arg1, ValueRep::SomeRegister); >+ patchpoint->append(arg2, ValueRep::SomeRegister); >+ patchpoint->numGPScratchRegisters = 1; >+ patchpoint->setGenerator( >+ [] (CCallHelpers& jit, const StackmapGenerationParams& params) { >+ GPRReg scratchGPR = params.gpScratch(0); >+ jit.moveDoubleTo64(params[1].fpr(), scratchGPR); >+ jit.moveDoubleTo64(params[2].fpr(), params[0].gpr()); >+ jit.compare64(CCallHelpers::Equal, scratchGPR, params[0].gpr(), params[0].gpr()); >+ }); >+ patchpoint->effects = Effects::none(); >+ ValueFromBlock compareResult = m_out.anchor(patchpoint); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setBoolean(m_out.phi(Int32, nanResult, compareResult)); >+ return; >+ } >+ >+ ASSERT(m_node->isBinaryUseKind(UntypedUse)); >+ setBoolean(vmCall(Int32, m_out.operation(operationSameValue), m_callFrame, lowJSValue(m_node->child1()), lowJSValue(m_node->child2()))); >+ } > > void compileLogicalNot() > { >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.cpp b/Source/JavaScriptCore/runtime/Intrinsic.cpp >index ad49b17b2d1857123cfaab1caf4c501fd6f8e0a7..6652de04467b4615cd80ff753bf2da5cb990d980 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.cpp >+++ b/Source/JavaScriptCore/runtime/Intrinsic.cpp >@@ -115,6 +115,8 @@ const char* intrinsicName(Intrinsic intrinsic) > return "RegExpMatchFastIntrinsic"; > case ObjectGetPrototypeOfIntrinsic: > return "ObjectGetPrototypeOfIntrinsic"; >+ case ObjectIsIntrinsic: >+ return "ObjectIsIntrinsic"; > case ReflectGetPrototypeOfIntrinsic: > return "ReflectGetPrototypeOfIntrinsic"; > case StringPrototypeValueOfIntrinsic: >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h >index d64e9c7f12ad64e956b38c6609be8a02846f6e44..61fe0bd7f2580f265652167ff82bceaabbe76a00 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.h >+++ b/Source/JavaScriptCore/runtime/Intrinsic.h >@@ -70,6 +70,7 @@ enum Intrinsic { > RegExpTestFastIntrinsic, > RegExpMatchFastIntrinsic, > ObjectGetPrototypeOfIntrinsic, >+ ObjectIsIntrinsic, > ReflectGetPrototypeOfIntrinsic, > StringPrototypeValueOfIntrinsic, > StringPrototypeReplaceIntrinsic, >diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp >index 22d64596dac2f9319c514b7268cd72f96fc7138f..e18c765473a024d33bf50ced0be9c1cc1a29b166 100644 >--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp >+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp >@@ -83,7 +83,7 @@ const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_i > isSealed objectConstructorIsSealed DontEnum|Function 1 > isFrozen objectConstructorIsFrozen DontEnum|Function 1 > isExtensible objectConstructorIsExtensible DontEnum|Function 1 >- is objectConstructorIs DontEnum|Function 2 >+ is objectConstructorIs DontEnum|Function 2 ObjectIsIntrinsic > assign objectConstructorAssign DontEnum|Function 2 > values objectConstructorValues DontEnum|Function 1 > entries JSBuiltin DontEnum|Function 1 >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 8236337bc4c15e0c340591a6ce05ab60f5f84646..4211c660c8b6cace187602feac3b39cf7c6dcf0b 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,37 @@ >+2018-04-28 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ Poor Object.is performance >+ https://bugs.webkit.org/show_bug.cgi?id=185065 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * microbenchmarks/object-is.js: Added. >+ (incognito): >+ (sameValue): >+ (test1): >+ (test2): >+ (test3): >+ (test4): >+ (test5): >+ (test6): >+ * stress/object-is.js: Added. >+ (shouldBe): >+ (is1): >+ (is2): >+ (is3): >+ (is4): >+ (is5): >+ (is6): >+ (is7): >+ (is8): >+ (is9): >+ (is10): >+ (is11): >+ (is12): >+ (is13): >+ (is14): >+ (is15): >+ > 2018-04-26 Caio Lima <ticaiolima@gmail.com> > > [ESNext][BigInt] Implement support for "*" operation >diff --git a/JSTests/microbenchmarks/object-is.js b/JSTests/microbenchmarks/object-is.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8c4d94f142b445a22f060cd4afe163c11358ad0b >--- /dev/null >+++ b/JSTests/microbenchmarks/object-is.js >@@ -0,0 +1,82 @@ >+function incognito(value) { >+ var array = []; >+ array.push(value); >+ array.push("ignore me"); >+ array.push(value); >+ array.push({ ignore: "me" }); >+ return array[((Math.random() * 2) | 0) * 2]; >+} >+ >+// cached Object.is >+var objectIs = Object.is; >+ >+// pure JS version of Object.is >+function sameValue(a, b) { >+ return (a === b) ? >+ (a !== 0 || (1 / a === 1 / b)) : >+ (a !== a && b !== b); >+} >+ >+var testFiveA = incognito("back5"); >+var testFiveB = incognito("2back5".substring(1)); >+var testPi = incognito("PI"); >+var testNaN = incognito(NaN); >+var testNaN_2 = incognito(NaN); >+ >+var result; >+ >+function test1() >+{ >+ return testFiveA === testFiveB; >+} >+noInline(test1); >+ >+function test2() >+{ >+ return Object.is(testFiveA, testFiveB); >+} >+noInline(test2); >+ >+function test3() >+{ >+ return sameValue(testFiveA, testFiveB); >+} >+noInline(test3); >+ >+function test4() >+{ >+ return testFiveA === testPi; >+} >+noInline(test4); >+ >+function test5() >+{ >+ return Object.is(testFiveA, testPi); >+} >+noInline(test5); >+ >+function test6() >+{ >+ return sameValue(testFiveA, testPi); >+} >+noInline(test6); >+ >+var verbose = false; >+var tests = [ >+// test1, >+ test2, >+// test3, >+// test4, >+ test5, >+// test6, >+]; >+for (let test of tests) { >+ if (verbose) >+ var time = Date.now(); >+ >+ for (let i = 0; i < 2e7; ++i) >+ test(); >+ >+ if (verbose) >+ print(Date.now() - time); >+} >diff --git a/JSTests/stress/object-is.js b/JSTests/stress/object-is.js >new file mode 100644 >index 0000000000000000000000000000000000000000..4e74e35dc2bdcb6b7ac62dee08f0b4b6743709ac >--- /dev/null >+++ b/JSTests/stress/object-is.js >@@ -0,0 +1,72 @@ >+function shouldBe(actual, expected) { >+ if (actual !== expected) >+ throw new Error('bad value: ' + actual); >+} >+ >+function is1(a, b) { return Object.is(a, b); } >+noInline(is1); >+function is2(a, b) { return Object.is(a, b); } >+noInline(is2); >+function is3(a, b) { return Object.is(a, b); } >+noInline(is3); >+function is4(a, b) { return Object.is(a, b); } >+noInline(is4); >+function is5(a, b) { return Object.is(a, b); } >+noInline(is5); >+function is6(a, b) { return Object.is(a, b); } >+noInline(is6); >+function is7(a, b) { return Object.is(a, b); } >+noInline(is7); >+function is8(a, b) { return Object.is(a, b); } >+noInline(is8); >+function is9(a, b) { return Object.is(a, b); } >+noInline(is9); >+function is10(a, b) { return Object.is(a, b); } >+noInline(is10); >+function is11(a, b) { return Object.is(a, b); } >+noInline(is11); >+function is12(a, b) { return Object.is(a, b); } >+noInline(is12); >+function is13(a, b) { return Object.is(a, b); } >+noInline(is13); >+function is14(a, b) { return Object.is(a, b); } >+noInline(is14); >+function is15(a, b) { return Object.is(a, b); } >+noInline(is15); >+ >+for (var i = 0; i < 1e5; ++i) { >+ shouldBe(Object.is(NaN, NaN), true); >+ shouldBe(Object.is(null, null), true); >+ shouldBe(Object.is(null), false); >+ shouldBe(Object.is(undefined, undefined), true); >+ shouldBe(Object.is(true, true), true); >+ shouldBe(Object.is(false, false), true); >+ shouldBe(Object.is('abc', 'abc'), true); >+ shouldBe(Object.is(Infinity, Infinity), true); >+ shouldBe(Object.is(0, 0), true); >+ shouldBe(Object.is(-0, -0), true); >+ shouldBe(Object.is(0, -0), false); >+ shouldBe(Object.is(-0, 0), false); >+ var obj = {}; >+ shouldBe(Object.is(obj, obj), true); >+ var arr = []; >+ shouldBe(Object.is(arr, arr), true); >+ var sym = Symbol(); >+ shouldBe(Object.is(sym, sym), true); >+ >+ shouldBe(is1(NaN, NaN), true); >+ shouldBe(is2(null, null), true); >+ shouldBe(is3(null), false); >+ shouldBe(is4(undefined, undefined), true); >+ shouldBe(is5(true, true), true); >+ shouldBe(is6(false, false), true); >+ shouldBe(is7('abc', 'abc'), true); >+ shouldBe(is8(Infinity, Infinity), true); >+ shouldBe(is9(0, 0), true); >+ shouldBe(is10(-0, -0), true); >+ shouldBe(is11(0, -0), false); >+ shouldBe(is12(-0, 0), false); >+ shouldBe(is13(obj, obj), true); >+ shouldBe(is14(arr, arr), true); >+ shouldBe(is15(sym, sym), true); >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185065
:
339081
|
339084
|
339085