Skip to content

Commit fc5dd91

Browse files
committed
Refactor str.startswith() and str.endswith()
1 parent 3643569 commit fc5dd91

File tree

3 files changed

+68
-96
lines changed

3 files changed

+68
-96
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextModuleBuiltins.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor;
6969
import com.oracle.graal.python.builtins.objects.module.PythonModule;
7070
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
71-
import com.oracle.graal.python.builtins.objects.str.StringBuiltins.EndsWithNode;
71+
import com.oracle.graal.python.builtins.objects.str.StringBuiltins.PrefixSuffixNode;
7272
import com.oracle.graal.python.lib.PyObjectLookupAttr;
7373
import com.oracle.graal.python.nodes.PRaiseNode;
7474
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
@@ -126,15 +126,15 @@ Object run(TruffleString name,
126126
@Cached CallNode callNode,
127127
@Cached ObjectBuiltins.SetattrNode setattrNode,
128128
@Cached TruffleString.CodePointLengthNode codePointLengthNode,
129-
@Cached EndsWithNode endsWithNode,
129+
@Cached PrefixSuffixNode prefixSuffixNode,
130130
@Cached TruffleString.LastIndexOfCodePointNode lastIndexNode,
131131
@Cached TruffleString.SubstringNode substringNode) {
132132
// see CPython's Objects/moduleobject.c - _PyModule_CreateInitialized for
133133
// comparison how they handle _Py_PackageContext
134134
TruffleString newModuleName = name;
135135
PythonContext ctx = getContext();
136136
TruffleString pyPackageContext = ctx.getPyPackageContext() == null ? null : ctx.getPyPackageContext();
137-
if (pyPackageContext != null && endsWithNode.executeBoolean(null, pyPackageContext, newModuleName, 0, codePointLengthNode.execute(pyPackageContext, TS_ENCODING))) {
137+
if (pyPackageContext != null && prefixSuffixNode.endsWith(pyPackageContext, newModuleName, 0, codePointLengthNode.execute(pyPackageContext, TS_ENCODING))) {
138138
newModuleName = pyPackageContext;
139139
ctx.setPyPackageContext(null);
140140
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/CtypesModuleBuiltins.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
import com.oracle.graal.python.builtins.objects.function.PKeyword;
136136
import com.oracle.graal.python.builtins.objects.module.PythonModule;
137137
import com.oracle.graal.python.builtins.objects.object.PythonObject;
138-
import com.oracle.graal.python.builtins.objects.str.StringBuiltins.EndsWithNode;
138+
import com.oracle.graal.python.builtins.objects.str.StringBuiltins.PrefixSuffixNode;
139139
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
140140
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
141141
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassNode;
@@ -739,7 +739,7 @@ static Object py_dl_open(VirtualFrame frame, PythonModule self, TruffleString na
739739
@Cached PyObjectHashNode hashNode,
740740
@Cached AuditNode auditNode,
741741
@Cached CodePointLengthNode codePointLengthNode,
742-
@Cached EndsWithNode endsWithNode,
742+
@Cached PrefixSuffixNode prefixSuffixNode,
743743
@Cached EqualNode eqNode,
744744
@Cached PythonObjectFactory factory,
745745
@Cached PRaiseNode.Lazy raiseNode) {
@@ -755,7 +755,7 @@ static Object py_dl_open(VirtualFrame frame, PythonModule self, TruffleString na
755755
Exception exception = null;
756756
boolean loadWithLLVM = !context.getEnv().isNativeAccessAllowed() || //
757757
(!context.getOption(PythonOptions.UseSystemToolchain) &&
758-
endsWithNode.executeBoolean(frame, name, context.getSoAbi(), 0, codePointLengthNode.execute(name, TS_ENCODING)));
758+
prefixSuffixNode.endsWith(name, context.getSoAbi(), 0, codePointLengthNode.execute(name, TS_ENCODING)));
759759
try {
760760
if (loadWithLLVM) {
761761
Object handler = loadLLVMLibrary(context, inliningTarget, name);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java

Lines changed: 62 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@
121121
import com.oracle.graal.python.builtins.objects.slice.SliceNodes.ComputeIndices;
122122
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsClinicProviders.FormatNodeClinicProviderGen;
123123
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsClinicProviders.SplitNodeClinicProviderGen;
124-
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsFactory.EndsWithNodeFactory;
125124
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsFactory.EqNodeFactory;
126125
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsFactory.LtNodeFactory;
127-
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsFactory.StartsWithNodeFactory;
128126
import com.oracle.graal.python.builtins.objects.str.StringNodes.CastToJavaStringCheckedNode;
129127
import com.oracle.graal.python.builtins.objects.str.StringNodes.CastToTruffleStringCheckedNode;
130128
import com.oracle.graal.python.builtins.objects.str.StringNodes.JoinInternalNode;
@@ -175,6 +173,7 @@
175173
import com.oracle.truffle.api.dsl.Cached;
176174
import com.oracle.truffle.api.dsl.Cached.Exclusive;
177175
import com.oracle.truffle.api.dsl.Cached.Shared;
176+
import com.oracle.truffle.api.dsl.GenerateInline;
178177
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
179178
import com.oracle.truffle.api.dsl.GenerateUncached;
180179
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -588,72 +587,77 @@ static Object doNoString(Object self, @SuppressWarnings("unused") Object other,
588587
}
589588
}
590589

591-
abstract static class PrefixSuffixBaseNode extends PythonQuaternaryClinicBuiltinNode {
590+
@GenerateInline(false) // footprint reduction 56 -> 39
591+
@ImportStatic(PGuards.class)
592+
public abstract static class PrefixSuffixNode extends Node {
592593

593-
public abstract boolean executeBoolean(VirtualFrame frame, TruffleString self, TruffleString subStr, int start, int end);
594+
enum Op {
595+
PREFIX,
596+
SUFFIX;
594597

595-
@Override
596-
protected ArgumentClinicProvider getArgumentClinic() {
597-
// must be implemented here, because DSL creates a generated node for this class
598-
CompilerDirectives.transferToInterpreterAndInvalidate();
599-
throw new AbstractMethodError();
598+
TruffleString methodName() {
599+
return this == PREFIX ? T_STARTSWITH : T_ENDSWITH;
600+
}
601+
}
602+
603+
abstract boolean execute(Object self, Object subStr, int start, int end, Op op);
604+
605+
public final boolean startsWith(Object self, Object subStr, int start, int end) {
606+
return execute(self, subStr, start, end, Op.PREFIX);
607+
}
608+
609+
public final boolean endsWith(Object self, Object subStr, int start, int end) {
610+
return execute(self, subStr, start, end, Op.SUFFIX);
600611
}
601612

602613
@Specialization(guards = "!isPTuple(subStrObj)")
603-
boolean doStringPrefixStartEnd(Object selfObj, Object subStrObj, int start, int end,
614+
static boolean doString(Object selfObj, Object subStrObj, int start, int end, Op op,
604615
@Bind("this") Node inliningTarget,
605616
@Exclusive @Cached CastToTruffleStringCheckedNode castSelfNode,
606617
@Exclusive @Cached CastToTruffleStringCheckedNode castPrefixNode,
607-
@Shared("cpLen") @Cached TruffleString.CodePointLengthNode codePointLengthNode,
608-
@Shared("regionEqual") @Cached TruffleString.RegionEqualNode regionEqualNode) {
609-
TruffleString self = castSelfNode.cast(inliningTarget, selfObj, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, getMethodName(), selfObj);
610-
TruffleString subStr = castPrefixNode.cast(inliningTarget, subStrObj, ErrorMessages.FIRST_ARG_MUST_BE_S_OR_TUPLE_NOT_P, getMethodName(), "str", subStrObj);
618+
@Shared @Cached TruffleString.CodePointLengthNode codePointLengthNode,
619+
@Shared @Cached TruffleString.RegionEqualNode regionEqualNode) {
620+
TruffleString self = castSelfNode.cast(inliningTarget, selfObj, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, op.methodName(), selfObj);
621+
TruffleString subStr = castPrefixNode.cast(inliningTarget, subStrObj, ErrorMessages.FIRST_ARG_MUST_BE_S_OR_TUPLE_NOT_P, op.methodName(), "str", subStrObj);
611622
int selfLen = codePointLengthNode.execute(self, TS_ENCODING);
612623
int subStrLen = codePointLengthNode.execute(subStr, TS_ENCODING);
613-
return doIt(self, subStr, adjustStartIndex(start, selfLen), adjustEndIndex(end, selfLen), selfLen, subStrLen, regionEqualNode);
624+
return doIt(self, subStr, adjustStartIndex(start, selfLen), adjustEndIndex(end, selfLen), selfLen, subStrLen, regionEqualNode, op);
614625
}
615626

616627
@Specialization
617-
@SuppressWarnings("truffle-static-method")
618-
boolean doTuplePrefixStartEnd(Object selfObj, PTuple subStrs, int start, int end,
628+
static boolean doTuple(Object selfObj, PTuple subStrs, int start, int end, Op op,
619629
@Bind("this") Node inliningTarget,
620-
@Exclusive @Cached GetObjectArrayNode getObjectArrayNode,
621-
@Exclusive @Cached CastToTruffleStringNode castPrefixNode,
622-
@Shared("cpLen") @Cached TruffleString.CodePointLengthNode codePointLengthNode,
623-
@Shared("regionEqual") @Cached TruffleString.RegionEqualNode regionEqualNode,
630+
@Cached GetObjectArrayNode getObjectArrayNode,
624631
@Exclusive @Cached CastToTruffleStringCheckedNode castSelfNode,
625-
@Cached PRaiseNode.Lazy raiseNode) {
626-
TruffleString self = castSelfNode.cast(inliningTarget, selfObj, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, getMethodName(), selfObj);
632+
@Exclusive @Cached CastToTruffleStringCheckedNode castPrefixNode,
633+
@Shared @Cached TruffleString.CodePointLengthNode codePointLengthNode,
634+
@Shared @Cached TruffleString.RegionEqualNode regionEqualNode) {
635+
TruffleString self = castSelfNode.cast(inliningTarget, selfObj, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, op.methodName(), selfObj);
627636

628637
int selfLen = codePointLengthNode.execute(self, TS_ENCODING);
629638
int cpStart = adjustStartIndex(start, selfLen);
630639
int cpEnd = adjustEndIndex(end, selfLen);
631640

632641
for (Object element : getObjectArrayNode.execute(inliningTarget, subStrs)) {
633-
try {
634-
TruffleString subStr = castPrefixNode.execute(inliningTarget, element);
635-
int subStrLen = codePointLengthNode.execute(subStr, TS_ENCODING);
636-
if (doIt(self, subStr, cpStart, cpEnd, selfLen, subStrLen, regionEqualNode)) {
637-
return true;
638-
}
639-
} catch (CannotCastException e) {
640-
throw raiseNode.get(inliningTarget).raise(TypeError, ErrorMessages.INVALID_ELEMENT_TYPE, getMethodName(), element);
642+
TruffleString subStr = castPrefixNode.cast(inliningTarget, element, ErrorMessages.INVALID_ELEMENT_TYPE, op.methodName(), element);
643+
int subStrLen = codePointLengthNode.execute(subStr, TS_ENCODING);
644+
if (doIt(self, subStr, cpStart, cpEnd, selfLen, subStrLen, regionEqualNode, op)) {
645+
return true;
641646
}
642647
}
643648
return false;
644649
}
645650

646-
// the actual operation; will be overridden by subclasses
647-
@SuppressWarnings("unused")
648-
boolean doIt(TruffleString text, TruffleString subStr, int start, int end, int textLen, int subStrLen, TruffleString.RegionEqualNode regionEqualNode) {
649-
CompilerAsserts.neverPartOfCompilation();
650-
throw new IllegalStateException("should not reach");
651-
}
651+
private static boolean doIt(TruffleString text, TruffleString subStr, int start, int end, int textLen, int subStrLen, TruffleString.RegionEqualNode regionEqualNode, Op op) {
652+
// start and end must be normalized indices for 'text'
653+
assert start >= 0;
654+
assert end >= 0 && end <= textLen;
652655

653-
@SuppressWarnings("unused")
654-
protected TruffleString getMethodName() {
655-
CompilerAsserts.neverPartOfCompilation();
656-
throw new IllegalStateException("should not reach");
656+
if (end - start < subStrLen) {
657+
return false;
658+
}
659+
int fromIndex = op == Op.PREFIX ? start : end - subStrLen;
660+
return regionEqualNode.execute(text, fromIndex, subStr, 0, subStrLen, TS_ENCODING);
657661
}
658662
}
659663

@@ -662,33 +666,17 @@ protected TruffleString getMethodName() {
662666
@ArgumentClinic(name = "start", conversion = ArgumentClinic.ClinicConversion.SliceIndex, defaultValue = "0", useDefaultForNone = true)
663667
@ArgumentClinic(name = "end", conversion = ArgumentClinic.ClinicConversion.SliceIndex, defaultValue = "Integer.MAX_VALUE", useDefaultForNone = true)
664668
@GenerateNodeFactory
665-
public abstract static class StartsWithNode extends PrefixSuffixBaseNode {
669+
public abstract static class StartsWithNode extends PythonQuaternaryClinicBuiltinNode {
666670

667671
@Override
668672
protected ArgumentClinicProvider getArgumentClinic() {
669673
return StringBuiltinsClinicProviders.StartsWithNodeClinicProviderGen.INSTANCE;
670674
}
671675

672-
@Override
673-
boolean doIt(TruffleString text, TruffleString prefix, int start, int end, int textLen, int prefixLen, TruffleString.RegionEqualNode regionEqualNode) {
674-
// start and end must be normalized indices for 'text'
675-
assert start >= 0;
676-
assert end >= 0 && end <= textLen;
677-
678-
if (end - start < prefixLen) {
679-
return false;
680-
}
681-
return regionEqualNode.execute(text, start, prefix, 0, prefixLen, TS_ENCODING);
682-
}
683-
684-
@Override
685-
protected TruffleString getMethodName() {
686-
return T_STARTSWITH;
687-
}
688-
689-
@NeverDefault
690-
public static StartsWithNode create() {
691-
return StartsWithNodeFactory.create();
676+
@Specialization
677+
static boolean doStartsWith(Object self, Object prefix, int start, int end,
678+
@Cached PrefixSuffixNode prefixSuffixNode) {
679+
return prefixSuffixNode.startsWith(self, prefix, start, end);
692680
}
693681
}
694682

@@ -697,33 +685,17 @@ public static StartsWithNode create() {
697685
@ArgumentClinic(name = "start", conversion = ArgumentClinic.ClinicConversion.SliceIndex, defaultValue = "0", useDefaultForNone = true)
698686
@ArgumentClinic(name = "end", conversion = ArgumentClinic.ClinicConversion.SliceIndex, defaultValue = "Integer.MAX_VALUE", useDefaultForNone = true)
699687
@GenerateNodeFactory
700-
public abstract static class EndsWithNode extends PrefixSuffixBaseNode {
688+
public abstract static class EndsWithNode extends PythonQuaternaryClinicBuiltinNode {
701689

702690
@Override
703691
protected ArgumentClinicProvider getArgumentClinic() {
704692
return StringBuiltinsClinicProviders.EndsWithNodeClinicProviderGen.INSTANCE;
705693
}
706694

707-
@Override
708-
boolean doIt(TruffleString text, TruffleString suffix, int start, int end, int textLen, int suffixLen, TruffleString.RegionEqualNode regionEqualNode) {
709-
// start and end must be normalized indices for 'text'
710-
assert start >= 0;
711-
assert end >= 0 && end <= textLen;
712-
713-
if (end - start < suffixLen) {
714-
return false;
715-
}
716-
return regionEqualNode.execute(text, end - suffixLen, suffix, 0, suffixLen, TS_ENCODING);
717-
}
718-
719-
@Override
720-
protected TruffleString getMethodName() {
721-
return T_ENDSWITH;
722-
}
723-
724-
@NeverDefault
725-
public static EndsWithNode create() {
726-
return EndsWithNodeFactory.create();
695+
@Specialization
696+
static boolean doEndsWith(Object self, Object prefix, int start, int end,
697+
@Cached PrefixSuffixNode prefixSuffixNode) {
698+
return prefixSuffixNode.endsWith(self, prefix, start, end);
727699
}
728700
}
729701

@@ -1029,7 +1001,7 @@ static PDict doString(VirtualFrame frame, Object cls, Object from, Object to, Ob
10291001
}
10301002

10311003
@Specialization(guards = {"isNoValue(to)", "isNoValue(z)"})
1032-
@SuppressWarnings({"unused", "truffle-static-method"})
1004+
@SuppressWarnings("unused")
10331005
static PDict doDict(VirtualFrame frame, Object cls, PDict from, Object to, Object z,
10341006
@Bind("this") Node inliningTarget,
10351007
@Cached HashingCollectionNodes.GetHashingStorageNode getHashingStorageNode,
@@ -2694,12 +2666,12 @@ protected ArgumentClinicProvider getArgumentClinic() {
26942666
}
26952667

26962668
@Specialization
2697-
TruffleString remove(VirtualFrame frame, TruffleString self, TruffleString prefix,
2698-
@Cached StartsWithNode startsWith,
2669+
static TruffleString remove(TruffleString self, TruffleString prefix,
2670+
@Cached PrefixSuffixNode prefixSuffixNode,
26992671
@Cached TruffleString.CodePointLengthNode codePointLengthNode,
27002672
@Cached TruffleString.SubstringNode substringNode) {
27012673
int prefixLen = codePointLengthNode.execute(prefix, TS_ENCODING);
2702-
if (startsWith.executeBoolean(frame, self, prefix, 0, prefixLen)) {
2674+
if (prefixSuffixNode.startsWith(self, prefix, 0, prefixLen)) {
27032675
int selfLen = codePointLengthNode.execute(self, TS_ENCODING);
27042676
return substringNode.execute(self, prefixLen, selfLen - prefixLen, TS_ENCODING, false);
27052677
}
@@ -2719,14 +2691,14 @@ protected ArgumentClinicProvider getArgumentClinic() {
27192691
}
27202692

27212693
@Specialization
2722-
TruffleString remove(VirtualFrame frame, TruffleString self, TruffleString suffix,
2694+
static TruffleString remove(TruffleString self, TruffleString suffix,
27232695
@Bind("this") Node inliningTarget,
2724-
@Cached EndsWithNode endsWith,
2696+
@Cached PrefixSuffixNode prefixSuffixNode,
27252697
@Cached TruffleString.CodePointLengthNode codePointLengthNode,
27262698
@Cached TruffleString.SubstringNode substringNode,
27272699
@Cached InlinedConditionProfile profile) {
27282700
int selfLen = codePointLengthNode.execute(self, TS_ENCODING);
2729-
if (profile.profile(inliningTarget, endsWith.executeBoolean(frame, self, suffix, 0, selfLen))) {
2701+
if (profile.profile(inliningTarget, prefixSuffixNode.endsWith(self, suffix, 0, selfLen))) {
27302702
int suffixLen = codePointLengthNode.execute(suffix, TS_ENCODING);
27312703
return substringNode.execute(self, 0, selfLen - suffixLen, TS_ENCODING, false);
27322704
}

0 commit comments

Comments
 (0)