WebKit Bugzilla
Attachment 358678 Details for
Bug 170657
: [DFG] Handle String.prototype.indexOf
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-170657-20190109000157.patch (text/plain), 35.28 KB, created by
Yusuke Suzuki
on 2019-01-09 00:01:58 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2019-01-09 00:01:58 PST
Size:
35.28 KB
patch
obsolete
>Subversion Revision: 239659 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index ef46089a850bdc2a4206b553d0b522e5b16d5ed7..7a6efbb278cfb711589e7c4c3d1a2312307b1732 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,52 @@ >+2019-01-09 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ [DFG] Handle String.prototype.indexOf >+ https://bugs.webkit.org/show_bug.cgi?id=170657 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * assembler/MacroAssemblerX86Common.h: >+ (JSC::MacroAssemblerX86Common::supportsFloatingPointRounding): >+ (JSC::MacroAssemblerX86Common::supportsStringAndTextProcessing): >+ (JSC::MacroAssemblerX86Common::supportsAVX): >+ (JSC::MacroAssemblerX86Common::isSSE41Present): >+ (JSC::MacroAssemblerX86Common::isSSE42Present): >+ * assembler/MacroAssemblerX86_64.h: >+ (JSC::MacroAssemblerX86_64::indexOf): >+ * assembler/X86Assembler.h: >+ (JSC::X86Assembler::pcmpestri_rr): >+ (JSC::X86Assembler::pcmpestrm_rr): >+ (JSC::X86Assembler::pcmpistri_rr): >+ (JSC::X86Assembler::pcmpistrm_rr): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileStringIndexOf): >+ * runtime/Intrinsic.cpp: >+ (JSC::intrinsicName): >+ * runtime/Intrinsic.h: >+ * runtime/StringPrototype.cpp: >+ (JSC::StringPrototype::finishCreation): >+ > 2019-01-04 Tadeu Zagallo <tzagallo@apple.com> > > Baseline version of get_by_id may corrupt metadata >diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >index 12434225acd9e4cb7ac93a4bafdd5613a884fcac..a2dc1aa456bc4a48d5586f59847d17c53964d0d5 100644 >--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >@@ -3957,13 +3957,6 @@ class MacroAssemblerX86Common : public AbstractMacroAssembler<Assembler> { > return X86Assembler::patchableJumpSize(); > } > >- static bool supportsFloatingPointRounding() >- { >- if (s_sse4_1CheckState == CPUIDCheckState::NotChecked) >- collectCPUFeatures(); >- return s_sse4_1CheckState == CPUIDCheckState::Set; >- } >- > static bool supportsCountPopulation() > { > if (s_popcntCheckState == CPUIDCheckState::NotChecked) >@@ -3971,9 +3964,22 @@ class MacroAssemblerX86Common : public AbstractMacroAssembler<Assembler> { > return s_popcntCheckState == CPUIDCheckState::Set; > } > >+ static bool supportsFloatingPointRounding() >+ { >+ return isSSE41Present(); >+ } >+ >+ static bool supportsStringAndTextProcessing() >+ { >+ return isSSE42Present(); >+ } >+ > static bool supportsAVX() > { >- // AVX still causes mysterious regressions and those regressions can be massive. >+ // Using AVX ad-hocly causes massive performance regression. This is because of >+ // mixing of SSE and AVX operations. If we want to use AVX, we should select >+ // AVX operations instead of SSE operations. For example, we should use vroundss >+ // instead of roundss. > return false; > } > >@@ -4283,6 +4289,20 @@ class MacroAssemblerX86Common : public AbstractMacroAssembler<Assembler> { > > #endif > >+ static bool isSSE41Present() >+ { >+ if (s_sse4_1CheckState == CPUIDCheckState::NotChecked) >+ collectCPUFeatures(); >+ return s_sse4_1CheckState == CPUIDCheckState::Set; >+ } >+ >+ static bool isSSE42Present() >+ { >+ if (s_sse4_2CheckState == CPUIDCheckState::NotChecked) >+ collectCPUFeatures(); >+ return s_sse4_2CheckState == CPUIDCheckState::Set; >+ } >+ > using CPUID = std::array<unsigned, 4>; > static CPUID getCPUID(unsigned level); > static CPUID getCPUIDEx(unsigned level, unsigned count); >diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >index 0f6a714f01a2de709543183da38ea0c2043714d8..9f5fa501fd2651ac3457a80dd7915514ceaa5678 100644 >--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >@@ -1862,6 +1862,14 @@ class MacroAssemblerX86_64 : public MacroAssemblerX86Common { > m_assembler.linkJump(done, m_assembler.label()); > } > >+#if 0 >+ void indexOf(RegisterID src, RegisterID character, FPRegisterID scratch1, FPRegisterID scratch2) >+ { >+ ASSERT(src == X86Registers::eax); >+ ASSERT(src == X86Registers::edx); >+ } >+#endif >+ > static bool supportsFloatingPoint() { return true; } > static bool supportsFloatingPointTruncate() { return true; } > static bool supportsFloatingPointSqrt() { return true; } >diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h >index 06cb9e171afb1dc53e48545a0c0aa0c6abebc89b..8a23107ac04a6cf2e1070f4b5ca00129e6dddbda 100644 >--- a/Source/JavaScriptCore/assembler/X86Assembler.h >+++ b/Source/JavaScriptCore/assembler/X86Assembler.h >@@ -352,11 +352,15 @@ class X86Assembler { > } TwoByteOpcodeID; > > typedef enum { >- OP3_ROUNDSS_VssWssIb = 0x0A, >- OP3_ROUNDSD_VsdWsdIb = 0x0B, >- OP3_LFENCE = 0xE8, >- OP3_MFENCE = 0xF0, >- OP3_SFENCE = 0xF8, >+ OP3_ROUNDSS_VssWssIb = 0x0A, >+ OP3_ROUNDSD_VsdWsdIb = 0x0B, >+ OP3_PCMPESTRM_VdqWdqIb = 0x60, >+ OP3_PCMPESTRI_VdqWdqIb = 0x61, >+ OP3_PCMPISTRM_VdqWdqIb = 0x62, >+ OP3_PCMPISTRI_VdqWdqIb = 0x63, >+ OP3_LFENCE = 0xE8, >+ OP3_MFENCE = 0xF0, >+ OP3_SFENCE = 0xF8, > } ThreeByteOpcodeID; > > struct VexPrefix { >@@ -3277,6 +3281,34 @@ class X86Assembler { > m_formatter.vexNdsLigWigTwoByteOp(PRE_SSE_F3, OP2_MULSD_VsdWsd, (RegisterID)dst, (RegisterID)b, offset, base, index, scale); > } > >+ void pcmpestri_rr(XMMRegisterID a, XMMRegisterID b, int imm) >+ { >+ m_formatter.prefix(PRE_SSE_66); >+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_PCMPESTRI_VdqWdqIb, (RegisterID)a, (RegisterID)b); >+ m_formatter.immediate8(imm); >+ } >+ >+ void pcmpestrm_rr(XMMRegisterID a, XMMRegisterID b, int imm) >+ { >+ m_formatter.prefix(PRE_SSE_66); >+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_PCMPESTRM_VdqWdqIb, (RegisterID)a, (RegisterID)b); >+ m_formatter.immediate8(imm); >+ } >+ >+ void pcmpistri_rr(XMMRegisterID a, XMMRegisterID b, int imm) >+ { >+ m_formatter.prefix(PRE_SSE_66); >+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_PCMPISTRI_VdqWdqIb, (RegisterID)a, (RegisterID)b); >+ m_formatter.immediate8(imm); >+ } >+ >+ void pcmpistrm_rr(XMMRegisterID a, XMMRegisterID b, int imm) >+ { >+ m_formatter.prefix(PRE_SSE_66); >+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_PCMPISTRM_VdqWdqIb, (RegisterID)a, (RegisterID)b); >+ m_formatter.immediate8(imm); >+ } >+ > void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst) > { > m_formatter.prefix(PRE_SSE_66); >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index a8113f31380ce12d6603fd753e6b380d18e60127..d44e19017aca6414f87ea7df50c100a5096b34c5 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -1233,6 +1233,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case StringIndexOf: { >+ setNonCellTypeForNode(node, SpecInt32Only); >+ break; >+ } >+ > case ToLowerCase: { > setTypeForNode(node, SpecString); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index 93529db0f13f5a48333e80bb723d74e6a22e90f7..19254d42c6ed5c841de6ec37d68d676e7c504397 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -2793,7 +2793,27 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, VirtualRegister result, I > set(result, resultNode); > return true; > } >- >+ >+ case StringPrototypeIndexOfIntrinsic: { >+ if (argumentCountIncludingThis != 2 && argumentCountIncludingThis != 3) >+ return false; >+ >+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) >+ return false; >+ >+ insertChecks(); >+ Node* base = get(virtualRegisterForArgument(0, registerOffset)); >+ Node* searcher = get(virtualRegisterForArgument(1, registerOffset)); >+ Node* position = nullptr; >+ if (argumentCountIncludingThis == 2) >+ position = jsConstant(jsNumber(0)); >+ else >+ position = get(virtualRegisterForArgument(2, registerOffset)); >+ Node* resultNode = addToGraph(StringIndexOf, base, searcher, position); >+ set(result, resultNode); >+ return true; >+ } >+ > case RoundIntrinsic: > case FloorIntrinsic: > case CeilIntrinsic: >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index fcb3c6b6bcd0b00ad9eb369a4832e19836d690cc..da2fdd786c6fa7e90fb5d6ba37be0e5da277692e 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -1787,6 +1787,10 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > def(PureValue(node)); > return; > >+ case StringIndexOf: >+ def(PureValue(node)); >+ return; >+ > case ToLowerCase: > def(PureValue(node)); > return; >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index ddbfa5d83cf5977a07dc37af8d2890222d33f1db..7c312a0d37bdc3b4dcd45ef1d59e5668ace9e2a0 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -375,6 +375,7 @@ bool doesGC(Graph& graph, Node* node) > case ObjectToString: > case CreateRest: > case ToLowerCase: >+ case StringIndexOf: > case CallDOMGetter: > case CallDOM: > case ArraySlice: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index d7860ea9c1334324f2efd201350b34c23eaf4103..71578d6a3e0f8cb9bd4eaf34dff212db029a583c 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -2169,6 +2169,13 @@ class FixupPhase : public Phase { > break; > } > >+ case StringIndexOf: { >+ fixEdge<StringUse>(node->child1()); >+ fixEdge<StringUse>(node->child2()); >+ fixEdge<Int32Use>(node->child3()); >+ break; >+ } >+ > case NumberToStringWithRadix: { > if (node->child1()->shouldSpeculateInt32()) > fixEdge<Int32Use>(node->child1()); >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index 03fe46b95184da166aeff5dce1ec157107e693d9..d87529ffcf0fd38ca1223e9dffe484a55eea4083 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -479,6 +479,7 @@ namespace JSC { namespace DFG { > macro(StringValueOf, NodeMustGenerate | NodeResultJS) \ > macro(StringSlice, NodeResultJS) \ > macro(ToLowerCase, NodeResultJS) \ >+ macro(StringIndexOf, NodeResultInt32) \ > /* Nodes for DOM JIT */\ > macro(CallDOMGetter, NodeResultJS | NodeMustGenerate) \ > macro(CallDOM, NodeResultJS | NodeMustGenerate) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index dfced10bf264f41040c0d47e3854dcb0dc91c999..fe0e2290c7f41569e866cbfba73871714a2faf79 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -2630,6 +2630,50 @@ int64_t JIT_OPERATION operationConvertDoubleToInt52(double value) > return tryConvertToInt52(value); > } > >+int32_t JIT_OPERATION operationStringIndexOfOneChar(void* pointer, LChar character, int32_t length, int32_t position) >+{ >+ const LChar* characters = static_cast<const LChar*>(pointer); >+ const LChar* result = static_cast<const LChar*>(memchr(characters, character, length)); >+ if (!result) >+ return -1; >+ return (result - characters) + position; >+} >+ >+int32_t JIT_OPERATION operationStringIndexOf(void* pointer, int32_t length, void* searcher, int32_t searcherLength, int32_t position) >+{ >+ const LChar* characters = static_cast<const LChar*>(pointer); >+ const LChar* result = static_cast<const LChar*>(memmem(characters, length, static_cast<const LChar*>(searcher), searcherLength)); >+ if (!result) >+ return -1; >+ return (result - characters) + position; >+} >+ >+int32_t JIT_OPERATION operationStringIndexOfGeneric(ExecState* exec, JSString* thisJSString, JSString* otherJSString, int32_t position) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ int32_t length = thisJSString->length(); >+ RELEASE_ASSERT(length >= 0); >+ if (position >= 0) >+ position = std::min<int32_t>(position, length); >+ else >+ position = 0; >+ >+ if (thisJSString->length() < otherJSString->length() + position) >+ return -1; >+ >+ auto thisViewWithString = thisJSString->viewWithUnderlyingString(exec); >+ RETURN_IF_EXCEPTION(scope, 0); >+ auto otherViewWithString = otherJSString->viewWithUnderlyingString(exec); >+ RETURN_IF_EXCEPTION(scope, 0); >+ size_t result = thisViewWithString.view.find(otherViewWithString.view, position); >+ if (result == notFound) >+ return -1; >+ return result; >+} >+ > char* JIT_OPERATION operationNewRawObject(ExecState* exec, Structure* structure, int32_t length, Butterfly* butterfly) > { > VM& vm = exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index 8b76f4d6bf37401de2c4a97c1c3205527cc63951..01e05d3a93e3eee8f7c8aff3b80b8ad336e1a328 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -274,6 +274,10 @@ int64_t JIT_OPERATION operationConvertDoubleToInt52(double); > > int32_t JIT_OPERATION operationNumberIsInteger(ExecState*, EncodedJSValue); > >+int32_t JIT_OPERATION operationStringIndexOf(void*, int32_t, void*, int32_t, int32_t position); >+int32_t JIT_OPERATION operationStringIndexOfOneChar(void*, LChar, int32_t length, int32_t position); >+int32_t JIT_OPERATION operationStringIndexOfGeneric(ExecState*, JSString*, JSString*, int32_t position); >+ > size_t JIT_OPERATION operationDefaultHasInstance(ExecState*, JSCell* value, JSCell* proto); > > char* JIT_OPERATION operationNewRawObject(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index 1ba4eff373c8a570ea88cd71ae11210f493ff6d1..6850b372bf14d21c7878db997c9e7482b27a14fc 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -888,6 +888,10 @@ class PredictionPropagationPhase : public Phase { > setPrediction(SpecString); > break; > >+ case StringIndexOf: >+ setPrediction(SpecInt32Only); >+ break; >+ > case ArithPow: > case ArithSqrt: > case ArithFRound: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 06da94f441f85d2456100cb18547104c58951b0f..84c396dd352d76c650521ce58ed29b65901df446 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -452,6 +452,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case StringValueOf: > case StringSlice: > case ToLowerCase: >+ case StringIndexOf: > case ObjectToString: > case GetMapBucket: > case GetMapBucketHead: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 5d58fda3e76dd6b47f7e6d7ef826c46bad5565d8..344f6554110d377e1614437ef62bf43f2ad14c9a 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -4227,6 +4227,112 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case StringIndexOf: { >+ SpeculateCellOperand base(this, node->child1()); >+ SpeculateCellOperand searcher(this, node->child2()); >+ SpeculateInt32Operand position(this, node->child3()); >+ >+ GPRTemporary temp(this); >+ GPRTemporary temp2(this); >+ GPRTemporary length(this); >+ GPRTemporary length2(this); >+ >+ GPRReg baseGPR = base.gpr(); >+ GPRReg searcherGPR = searcher.gpr(); >+ GPRReg positionGPR = position.gpr(); >+ GPRReg tempGPR = temp.gpr(); >+ GPRReg temp2GPR = temp2.gpr(); >+ GPRReg lengthGPR = length.gpr(); >+ GPRReg length2GPR = length2.gpr(); >+ >+ speculateString(node->child1(), baseGPR); >+ speculateString(node->child2(), searcherGPR); >+ >+ if (JSString* string = node->child2()->dynamicCastConstant<JSString*>(*m_jit.vm())) { >+ const StringImpl* impl = string->tryGetValueImpl(); >+ if (!impl || !impl->is8Bit()) { >+ flushRegisters(); >+ callOperation(operationStringIndexOfGeneric, lengthGPR, baseGPR, searcherGPR, positionGPR); >+ int32Result(lengthGPR, node); >+ break; >+ } >+ //m_jit.graph().freezeStrong(string); >+ >+ //CCallHelpers::JumpList slowPath; >+ >+ //m_jit.loadPtr(CCallHelpers::Address(baseGPR, JSString::offsetOfValue()), temp2GPR); >+ //slowPath.append(m_jit.branchTestPtr(CCallHelpers::Zero, temp2GPR)); >+ //slowPath.append(m_jit.branchTest32( >+ //CCallHelpers::Zero, CCallHelpers::Address(temp2GPR, StringImpl::flagsOffset()), >+ //CCallHelpers::TrustedImm32(StringImpl::flagIs8Bit()))); >+ //m_jit.load32(CCallHelpers::Address(temp2GPR, StringImpl::lengthMemoryOffset()), lengthGPR); >+ //m_jit.loadPtr(CCallHelpers::Address(temp2GPR, StringImpl::dataOffset()), temp2GPR); >+ //slowPath.append(m_jit.branch32(CCallHelpers::AboveOrEqual, positionGPR, lengthGPR)); >+ //m_jit.sub32(positionGPR, lengthGPR); >+ //m_jit.zeroExtend32ToPtr(positionGPR, tempGPR); >+ //m_jit.addPtr(tempGPR, temp2GPR); >+ //flushRegisters(); >+ >+ //if (impl->length() == 1) { >+ //LChar character = (*impl)[0]; >+ //m_jit.move(CCallHelpers::TrustedImm32(character), tempGPR); >+ //callOperation(operationStringIndexOfOneChar, lengthGPR, temp2GPR, tempGPR, lengthGPR, positionGPR); >+ >+ //addSlowPathGenerator(slowPathCall(slowPath, this, operationStringIndexOfGeneric, lengthGPR, baseGPR, searcherGPR, positionGPR)); >+ >+ //int32Result(lengthGPR, node); >+ //break; >+ //} >+ >+ //m_jit.move(CCallHelpers::TrustedImm32(impl->length()), length2GPR); >+ //m_jit.move(CCallHelpers::TrustedImmPtr(impl->characters8()), tempGPR); >+ //callOperation(operationStringIndexOf, lengthGPR, temp2GPR, lengthGPR, tempGPR, length2GPR, positionGPR); >+ >+ //addSlowPathGenerator(slowPathCall(slowPath, this, operationStringIndexOfGeneric, lengthGPR, baseGPR, searcherGPR, positionGPR)); >+ >+ //int32Result(lengthGPR, node); >+ //break; >+ } >+ >+ CCallHelpers::JumpList slowPath; >+ >+ m_jit.loadPtr(CCallHelpers::Address(baseGPR, JSString::offsetOfValue()), temp2GPR); >+ slowPath.append(m_jit.branchTestPtr(CCallHelpers::Zero, temp2GPR)); >+ slowPath.append(m_jit.branchTest32( >+ CCallHelpers::Zero, CCallHelpers::Address(temp2GPR, StringImpl::flagsOffset()), >+ CCallHelpers::TrustedImm32(StringImpl::flagIs8Bit()))); >+ m_jit.load32(CCallHelpers::Address(temp2GPR, StringImpl::lengthMemoryOffset()), lengthGPR); >+ m_jit.loadPtr(CCallHelpers::Address(temp2GPR, StringImpl::dataOffset()), temp2GPR); >+ slowPath.append(m_jit.branch32(CCallHelpers::AboveOrEqual, positionGPR, lengthGPR)); >+ m_jit.sub32(positionGPR, lengthGPR); >+ m_jit.zeroExtend32ToPtr(positionGPR, tempGPR); >+ m_jit.addPtr(tempGPR, temp2GPR); >+ >+ m_jit.loadPtr(CCallHelpers::Address(searcherGPR, JSString::offsetOfValue()), tempGPR); >+ slowPath.append(m_jit.branchTestPtr(CCallHelpers::Zero, tempGPR)); >+ slowPath.append(m_jit.branchTest32( >+ CCallHelpers::Zero, CCallHelpers::Address(tempGPR, StringImpl::flagsOffset()), >+ CCallHelpers::TrustedImm32(StringImpl::flagIs8Bit()))); >+ m_jit.load32(CCallHelpers::Address(tempGPR, StringImpl::lengthMemoryOffset()), length2GPR); >+ m_jit.loadPtr(CCallHelpers::Address(tempGPR, StringImpl::dataOffset()), tempGPR); >+ >+ flushRegisters(); >+ //auto notOneCharCase = m_jit.branch32(CCallHelpers::NotEqual, length2GPR, CCallHelpers::TrustedImm32(1)); >+ >+ //m_jit.load8(CCallHelpers::Address(tempGPR), tempGPR); >+ //callOperateon(operationStringIndexOfOneChar, lengthGPR, temp2GPR, tempGPR, lengthGPR, positionGPR); >+ //auto done = m_jit.jump(); >+ >+ //notOneCharCase.link(&m_jit); >+ callOperation(operationStringIndexOf, lengthGPR, temp2GPR, lengthGPR, tempGPR, length2GPR, positionGPR); >+ >+ addSlowPathGenerator(slowPathCall(slowPath, this, operationStringIndexOfGeneric, lengthGPR, baseGPR, searcherGPR, positionGPR)); >+ >+ //done.link(&m_jit); >+ int32Result(lengthGPR, node); >+ break; >+ } >+ > case NumberToStringWithRadix: { > compileNumberToStringWithRadix(node); > break; >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 6b7d0fc989fb6a52d3d2fe77211d996b4fd7f5f0..af7c33b4787c0ef2efe2e1982e32707f95a7e651 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -333,6 +333,7 @@ inline CapabilityLevel canCompile(Node* node) > case StringValueOf: > case StringSlice: > case ToLowerCase: >+ case StringIndexOf: > case ObjectToString: > case NumberToStringWithRadix: > case NumberToStringWithValidRadixConstant: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 9156a4838ce9dbc469747e7a5a59c9ce2e33e65f..09f03b89c6863c57e2140ff9d9b9e74e0e58c427 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -1317,6 +1317,9 @@ class LowerDFGToB3 { > case ToLowerCase: > compileToLowerCase(); > break; >+ case StringIndexOf: >+ compileStringIndexOf(); >+ break; > case NumberToStringWithRadix: > compileNumberToStringWithRadix(); > break; >@@ -12213,6 +12216,115 @@ class LowerDFGToB3 { > setJSValue(m_out.phi(pointerType(), fastResult, slowResult)); > } > >+ void compileStringIndexOf() >+ { >+ LBasicBlock slowPath = m_out.newBlock(); >+ LBasicBlock baseNotRope = m_out.newBlock(); >+ LBasicBlock baseIs8Bit = m_out.newBlock(); >+ LBasicBlock positionIsInRange = m_out.newBlock(); >+ LBasicBlock searcherNotRope = m_out.newBlock(); >+ LBasicBlock searcherIs8Bit = m_out.newBlock(); >+ LBasicBlock searcherOneByte = m_out.newBlock(); >+ LBasicBlock generic = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ LValue base = lowString(m_node->child1()); >+ LValue searcher = lowString(m_node->child2()); >+ LValue position = lowInt32(m_node->child3()); >+ >+ if (JSString* string = m_node->child2()->dynamicCastConstant<JSString*>(vm())) { >+ const StringImpl* impl = string->tryGetValueImpl(); >+ if (!impl || !impl->is8Bit()) { >+ setInt32(vmCall(Int32, m_out.operation(operationStringIndexOfGeneric), m_callFrame, base, searcher, position)); >+ return; >+ } >+ m_graph.freezeStrong(string); >+ >+ LValue baseImpl = m_out.loadPtr(base, m_heaps.JSString_value); >+ m_out.branch(m_out.isZero64(baseImpl), unsure(slowPath), unsure(baseNotRope)); >+ >+ LBasicBlock lastNext = m_out.appendTo(baseNotRope, baseIs8Bit); >+ m_out.branch( >+ m_out.testIsZero32( >+ m_out.load32(baseImpl, m_heaps.StringImpl_hashAndFlags), >+ m_out.constInt32(StringImpl::flagIs8Bit())), >+ unsure(slowPath), unsure(baseIs8Bit)); >+ >+ m_out.appendTo(baseIs8Bit, positionIsInRange); >+ LValue baseLength = m_out.load32(baseImpl, m_heaps.StringImpl_length); >+ m_out.branch(m_out.aboveOrEqual(position, baseLength), unsure(slowPath), unsure(positionIsInRange)); >+ >+ m_out.appendTo(positionIsInRange, slowPath); >+ LValue targetLength = m_out.sub(baseLength, position); >+ LValue baseBuffer = m_out.loadPtr(baseImpl, m_heaps.StringImpl_data); >+ LValue targetBuffer = m_out.add(baseBuffer, m_out.zeroExtPtr(position)); >+ >+ ValueFromBlock fastResult; >+ if (impl->length() == 1) >+ fastResult = m_out.anchor(m_out.call(Int32, m_out.operation(operationStringIndexOfOneChar), targetBuffer, m_out.constInt32((*impl)[0]), targetLength, position)); >+ else >+ fastResult = m_out.anchor(m_out.call(Int32, m_out.operation(operationStringIndexOf), targetBuffer, targetLength, m_out.constIntPtr(impl->characters8()), m_out.constInt32(impl->length()), position)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(slowPath, continuation); >+ ValueFromBlock slowResult = m_out.anchor(vmCall(Int32, m_out.operation(operationStringIndexOfGeneric), m_callFrame, base, searcher, position)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setInt32(m_out.phi(Int32, fastResult, slowResult)); >+ return; >+ } >+ >+ LValue baseImpl = m_out.loadPtr(base, m_heaps.JSString_value); >+ m_out.branch(m_out.isZero64(baseImpl), unsure(slowPath), unsure(baseNotRope)); >+ >+ LBasicBlock lastNext = m_out.appendTo(baseNotRope, baseIs8Bit); >+ m_out.branch( >+ m_out.testIsZero32( >+ m_out.load32(baseImpl, m_heaps.StringImpl_hashAndFlags), >+ m_out.constInt32(StringImpl::flagIs8Bit())), >+ unsure(slowPath), unsure(baseIs8Bit)); >+ >+ m_out.appendTo(baseIs8Bit, positionIsInRange); >+ LValue baseLength = m_out.load32(baseImpl, m_heaps.StringImpl_length); >+ m_out.branch(m_out.aboveOrEqual(position, baseLength), unsure(slowPath), unsure(positionIsInRange)); >+ >+ m_out.appendTo(positionIsInRange, searcherNotRope); >+ LValue targetLength = m_out.sub(baseLength, position); >+ LValue baseBuffer = m_out.loadPtr(baseImpl, m_heaps.StringImpl_data); >+ LValue targetBuffer = m_out.add(baseBuffer, m_out.zeroExtPtr(position)); >+ LValue impl = m_out.loadPtr(searcher, m_heaps.JSString_value); >+ m_out.branch(m_out.isZero64(impl), unsure(slowPath), unsure(searcherNotRope)); >+ >+ m_out.appendTo(searcherNotRope, searcherIs8Bit); >+ m_out.branch( >+ m_out.testIsZero32( >+ m_out.load32(impl, m_heaps.StringImpl_hashAndFlags), >+ m_out.constInt32(StringImpl::flagIs8Bit())), >+ unsure(slowPath), unsure(searcherIs8Bit)); >+ >+ m_out.appendTo(searcherIs8Bit, searcherOneByte); >+ LValue buffer = m_out.loadPtr(impl, m_heaps.StringImpl_data); >+ LValue length = m_out.load32(impl, m_heaps.StringImpl_length); >+ m_out.branch(m_out.notEqual(length, m_out.constInt32(1)), unsure(generic), unsure(searcherOneByte)); >+ >+ m_out.appendTo(searcherOneByte, generic); >+ LValue character = m_out.load8ZeroExt32(buffer, m_heaps.characters8[0]); >+ ValueFromBlock fastResult = m_out.anchor(m_out.call(Int32, m_out.operation(operationStringIndexOfOneChar), targetBuffer, character, targetLength, position)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(generic, slowPath); >+ ValueFromBlock genericResult = m_out.anchor(m_out.call(Int32, m_out.operation(operationStringIndexOf), targetBuffer, targetLength, buffer, length, position)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(slowPath, continuation); >+ ValueFromBlock slowResult = m_out.anchor(vmCall(Int32, m_out.operation(operationStringIndexOfGeneric), m_callFrame, base, searcher, position)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setInt32(m_out.phi(Int32, fastResult, genericResult, slowResult)); >+ } >+ > void compileNumberToStringWithRadix() > { > bool validRadixIsGuaranteed = false; >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.cpp b/Source/JavaScriptCore/runtime/Intrinsic.cpp >index f3db584349abe12237e5db58e9e5074e91d6d6e8..f1a6ff5b49c2a9591d8b9793ad38c32aefe15398 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.cpp >+++ b/Source/JavaScriptCore/runtime/Intrinsic.cpp >@@ -125,6 +125,8 @@ const char* intrinsicName(Intrinsic intrinsic) > return "ObjectPrototypeToStringIntrinsic"; > case ReflectGetPrototypeOfIntrinsic: > return "ReflectGetPrototypeOfIntrinsic"; >+ case StringPrototypeIndexOfIntrinsic: >+ return "StringPrototypeIndexOfIntrinsic"; > case StringPrototypeValueOfIntrinsic: > return "StringPrototypeValueOfIntrinsic"; > case StringPrototypeReplaceIntrinsic: >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h >index 15eab26bac6a562c8e2f24e35cd82e2ef4b24d05..86f73758a52c922b0c727ee41df2cf559fbf1bc7 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.h >+++ b/Source/JavaScriptCore/runtime/Intrinsic.h >@@ -75,6 +75,7 @@ enum Intrinsic { > ObjectKeysIntrinsic, > ObjectPrototypeToStringIntrinsic, > ReflectGetPrototypeOfIntrinsic, >+ StringPrototypeIndexOfIntrinsic, > StringPrototypeValueOfIntrinsic, > StringPrototypeReplaceIntrinsic, > StringPrototypeReplaceRegExpIntrinsic, >diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp >index 240ba5ef549a623c4d4fd256d09bc0ccc102c85c..0edbeea708ef48c35f5aee2942ce83c707b325d0 100644 >--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp >+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp >@@ -136,7 +136,7 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr > JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charAt", stringProtoFuncCharAt, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, CharAtIntrinsic); > JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charCodeAt", stringProtoFuncCharCodeAt, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, CharCodeAtIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("codePointAt", stringProtoFuncCodePointAt, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, StringPrototypeIndexOfIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); > JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().replaceUsingRegExpPrivateName(), stringProtoFuncReplaceUsingRegExp, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, StringPrototypeReplaceRegExpIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().replaceUsingStringSearchPrivateName(), stringProtoFuncReplaceUsingStringSearch, static_cast<unsigned>(PropertyAttribute::DontEnum), 2); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 12c1b7814fd12982d1b51de168fe824785acc29e..5a422d463705e84ea9181e93be432d134f3d8c8e 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,17 @@ >+2019-01-09 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ [DFG] Handle String.prototype.indexOf >+ https://bugs.webkit.org/show_bug.cgi?id=170657 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * microbenchmarks/string-index-of-one-char.js: Added. >+ (indexOf): >+ (string_appeared_here.forEach): >+ * microbenchmarks/string-index-of.js: Added. >+ (indexOf): >+ (string_appeared_here.forEach): >+ > 2019-01-04 Tadeu Zagallo <tzagallo@apple.com> > > Baseline version of get_by_id may corrupt metadata >diff --git a/JSTests/microbenchmarks/string-index-of-one-char.js b/JSTests/microbenchmarks/string-index-of-one-char.js >new file mode 100644 >index 0000000000000000000000000000000000000000..01a490590d0c14ab34814cdef324f407871a4911 >--- /dev/null >+++ b/JSTests/microbenchmarks/string-index-of-one-char.js >@@ -0,0 +1,17 @@ >+function indexOf(string, character) >+{ >+ return string.indexOf(character); >+} >+noInline(indexOf); >+ >+[ >+ "Hello", >+ "World", >+ "This is a pen", >+ "What happens?", >+ "Cocoa", >+ "Cappuccino" >+].forEach(function (string) { >+ for (var i = 0; i < 1e4; ++i) >+ indexOf(string, 'a'); >+}); >diff --git a/JSTests/microbenchmarks/string-index-of.js b/JSTests/microbenchmarks/string-index-of.js >new file mode 100644 >index 0000000000000000000000000000000000000000..0e52626dffd4716afcc1a89ba4689b44e5020562 >--- /dev/null >+++ b/JSTests/microbenchmarks/string-index-of.js >@@ -0,0 +1,17 @@ >+function indexOf(string, character) >+{ >+ return string.indexOf(character); >+} >+noInline(indexOf); >+ >+[ >+ "Hello", >+ "World", >+ "This is a pen", >+ "What happens?", >+ "Cocoa", >+ "Cappuccino" >+].forEach(function (string) { >+ for (var i = 0; i < 1e4; ++i) >+ indexOf(string, 'en'); >+}); >diff --git a/PerformanceTests/ChangeLog b/PerformanceTests/ChangeLog >index e3244041bc49a8815d701b362cb647c454178d54..fb827762fb9d18357cc354f59995a563edd92edb 100644 >--- a/PerformanceTests/ChangeLog >+++ b/PerformanceTests/ChangeLog >@@ -1,3 +1,12 @@ >+2019-01-05 Yusuke Suzuki <utatane.tea@gmail.com> >+ >+ [DFG] Handle String.prototype.indexOf >+ https://bugs.webkit.org/show_bug.cgi?id=170657 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * ARES-6/glue.js: >+ > 2018-12-20 Caio Lima <ticaiolima@gmail.com> > > [BigInt] We should enable CSE into arithmetic operations that speculate BigIntUse
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 170657
:
306993
|
307079
| 358678