Skip to content

Commit 89e2548

Browse files
committed
Avoid slow-path materializtion of NativeCharSequence
1 parent 8455461 commit 89e2548

File tree

3 files changed

+61
-42
lines changed

3 files changed

+61
-42
lines changed

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

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,19 @@
4242

4343
import java.util.Objects;
4444

45+
import com.oracle.graal.python.PythonLanguage;
4546
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.PCallCapiFunction;
46-
import com.oracle.graal.python.builtins.objects.cext.NativeCAPISymbols;
47+
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodesFactory.UnicodeFromWcharNodeGen;
48+
import com.oracle.graal.python.builtins.objects.str.StringNodes.StringMaterializeNode;
49+
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
4750
import com.oracle.truffle.api.CompilerAsserts;
51+
import com.oracle.truffle.api.CompilerDirectives;
52+
import com.oracle.truffle.api.TruffleLogger;
53+
import com.oracle.truffle.api.interop.InteropLibrary;
54+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
4855

49-
public final class NativeCharSequence implements PCharSequence {
56+
public final class NativeCharSequence implements CharSequence {
57+
private static final TruffleLogger LOGGER = PythonLanguage.getLogger(NativeCharSequence.class);
5058

5159
/**
5260
* Pointer to the native buffer (most like a {@code char*} containing ASCII characters but could
@@ -68,6 +76,7 @@ public final class NativeCharSequence implements PCharSequence {
6876
private String materialized;
6977

7078
public NativeCharSequence(Object ptr, int elementSize, boolean asciiOnly) {
79+
assert elementSize == 1 || elementSize == 2 || elementSize == 4;
7180
this.ptr = ptr;
7281
this.elementSize = elementSize;
7382
this.asciiOnly = asciiOnly;
@@ -78,6 +87,16 @@ public int length() {
7887
return materialize().length();
7988
}
8089

90+
int length(InteropLibrary lib, CastToJavaIntExactNode castToJavaIntNode) {
91+
try {
92+
int arraySize = castToJavaIntNode.execute(lib.getArraySize(ptr));
93+
assert arraySize % elementSize == 0;
94+
return arraySize / elementSize;
95+
} catch (UnsupportedMessageException e) {
96+
throw CompilerDirectives.shouldNotReachHere("pointer of NativeCharSequence is not an array");
97+
}
98+
}
99+
81100
@Override
82101
public char charAt(int index) {
83102
return materialize().charAt(index);
@@ -88,22 +107,18 @@ public CharSequence subSequence(int start, int end) {
88107
return materialize().subSequence(start, end);
89108
}
90109

91-
@Override
92-
public boolean isMaterialized() {
110+
boolean isMaterialized() {
93111
return materialized != null;
94112
}
95113

96-
@Override
97-
public final String materialize() {
98-
if (!isMaterialized()) {
99-
materialized = (String) PCallCapiFunction.getUncached().call(NativeCAPISymbols.FUN_PY_TRUFFLE_CSTR_TO_STRING, ptr);
100-
}
114+
String getMaterialized() {
101115
return materialized;
102116
}
103117

104-
public String materialize(PCallCapiFunction node) {
118+
private String materialize() {
105119
if (!isMaterialized()) {
106-
materialized = (String) node.call(NativeCAPISymbols.FUN_PY_TRUFFLE_CSTR_TO_STRING, ptr);
120+
LOGGER.warning("uncached materialization of NativeCharSequence");
121+
materialized = StringMaterializeNode.materializeNativeCharSequence(this, PCallCapiFunction.getUncached(), UnicodeFromWcharNodeGen.getUncached());
107122
}
108123
return materialized;
109124
}

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

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,30 @@
2929

3030
import com.oracle.graal.python.PythonLanguage;
3131
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
32-
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.PCallCapiFunction;
3332
import com.oracle.graal.python.builtins.objects.cext.PythonNativeWrapperLibrary;
3433
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
3534
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
3635
import com.oracle.graal.python.builtins.objects.str.StringNodes.StringMaterializeNode;
36+
import com.oracle.graal.python.builtins.objects.str.StringNodesFactory.StringMaterializeNodeGen;
3737
import com.oracle.graal.python.nodes.ErrorMessages;
3838
import com.oracle.graal.python.nodes.PRaiseNode;
3939
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
4040
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
4141
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
4242
import com.oracle.graal.python.nodes.util.CannotCastException;
43+
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
4344
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
4445
import com.oracle.graal.python.runtime.sequence.PSequence;
4546
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
4647
import com.oracle.truffle.api.CompilerDirectives;
4748
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
49+
import com.oracle.truffle.api.dsl.Bind;
4850
import com.oracle.truffle.api.dsl.Cached;
4951
import com.oracle.truffle.api.dsl.Cached.Exclusive;
5052
import com.oracle.truffle.api.dsl.Cached.Shared;
5153
import com.oracle.truffle.api.dsl.Specialization;
5254
import com.oracle.truffle.api.interop.InteropLibrary;
55+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
5356
import com.oracle.truffle.api.library.CachedLibrary;
5457
import com.oracle.truffle.api.library.ExportLibrary;
5558
import com.oracle.truffle.api.library.ExportMessage;
@@ -69,19 +72,7 @@ public PString(Object clazz, Shape instanceShape, CharSequence value) {
6972
}
7073

7174
public String getValue() {
72-
return PString.getValue(value);
73-
}
74-
75-
public static String getValue(CharSequence charSequence) {
76-
if (charSequence instanceof LazyString) {
77-
LazyString s = (LazyString) charSequence;
78-
return s.materialize();
79-
} else if (charSequence instanceof NativeCharSequence) {
80-
NativeCharSequence s = (NativeCharSequence) charSequence;
81-
return s.materialize();
82-
} else {
83-
return (String) charSequence;
84-
}
75+
return StringMaterializeNodeGen.getUncached().execute(this);
8576
}
8677

8778
public CharSequence getCharSequence() {
@@ -127,7 +118,7 @@ static int string(PString self, @SuppressWarnings("unused") ThreadState state,
127118
@SuppressWarnings("unused") @Shared("builtinProfile") @Cached IsBuiltinClassProfile profile,
128119
@SuppressWarnings("unused") @Shared("lookupSelf") @Cached LookupInheritedAttributeNode.Dynamic lookupSelf,
129120
@SuppressWarnings("unused") @Shared("lookupString") @Cached LookupAttributeInMRONode.Dynamic lookupString) {
130-
return ((String) self.value).length();
121+
return CompilerDirectives.castExact(self.value, String.class).length();
131122
}
132123

133124
@Specialization(guards = {
@@ -138,7 +129,7 @@ static int lazyString(PString self, @SuppressWarnings("unused") ThreadState stat
138129
@SuppressWarnings("unused") @Shared("builtinProfile") @Cached IsBuiltinClassProfile profile,
139130
@SuppressWarnings("unused") @Shared("lookupSelf") @Cached LookupInheritedAttributeNode.Dynamic lookupSelf,
140131
@SuppressWarnings("unused") @Shared("lookupString") @Cached LookupAttributeInMRONode.Dynamic lookupString) {
141-
return ((LazyString) self.value).length();
132+
return CompilerDirectives.castExact(self.value, LazyString.class).length();
142133
}
143134

144135
@Specialization(guards = {
@@ -149,21 +140,21 @@ static int nativeString(PString self, @SuppressWarnings("unused") ThreadState st
149140
@SuppressWarnings("unused") @Shared("builtinProfile") @Cached IsBuiltinClassProfile profile,
150141
@SuppressWarnings("unused") @Shared("lookupSelf") @Cached LookupInheritedAttributeNode.Dynamic lookupSelf,
151142
@SuppressWarnings("unused") @Shared("lookupString") @Cached LookupAttributeInMRONode.Dynamic lookupString) {
152-
return ((NativeCharSequence) self.value).length();
143+
return CompilerDirectives.castExact(self.value, NativeCharSequence.class).getMaterialized().length();
153144
}
154145

155146
@Specialization(guards = {
156147
"isNativeString(self.getCharSequence())", "!isMaterialized(self.getCharSequence())",
157148
"isBuiltin(self, profile) || hasBuiltinLen(self, lookupSelf, lookupString)"
158149
}, replaces = "nativeString", limit = "1")
159-
static int nativeStringMat(PString self, @SuppressWarnings("unused") ThreadState state,
150+
static int nativeStringMat(@SuppressWarnings("unused") PString self, @SuppressWarnings("unused") ThreadState state,
151+
@Bind("getNativeCharSequence(self)") NativeCharSequence nativeCharSequence,
160152
@SuppressWarnings("unused") @Shared("builtinProfile") @Cached IsBuiltinClassProfile profile,
161153
@SuppressWarnings("unused") @Shared("lookupSelf") @Cached LookupInheritedAttributeNode.Dynamic lookupSelf,
162154
@SuppressWarnings("unused") @Shared("lookupString") @Cached LookupAttributeInMRONode.Dynamic lookupString,
163-
@Cached PCallCapiFunction callCapi) {
164-
NativeCharSequence ncs = (NativeCharSequence) self.value;
165-
ncs.materialize(callCapi);
166-
return ncs.length();
155+
@CachedLibrary("nativeCharSequence") InteropLibrary lib,
156+
@Cached CastToJavaIntExactNode castToJavaIntNode) {
157+
return nativeCharSequence.length(lib, castToJavaIntNode);
167158
}
168159

169160
@Specialization(replaces = {"string", "lazyString", "nativeString", "nativeStringMat"})
@@ -178,6 +169,10 @@ static int subclassedString(PString self, ThreadState state,
178169
// call the generic implementation in the superclass
179170
return self.lengthWithState(state, plib, methodLib, gotState, hasLen, ltZero, raiseNode, lib);
180171
}
172+
173+
static NativeCharSequence getNativeCharSequence(PString self) {
174+
return (NativeCharSequence) self.value;
175+
}
181176
}
182177

183178
@ExportMessage

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,22 @@
6363
import com.oracle.graal.python.nodes.control.GetNextNode;
6464
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
6565
import com.oracle.graal.python.nodes.util.CannotCastException;
66+
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
6667
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
6768
import com.oracle.graal.python.runtime.PythonOptions;
6869
import com.oracle.graal.python.runtime.exception.PException;
6970
import com.oracle.graal.python.runtime.sequence.PSequence;
7071
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
7172
import com.oracle.graal.python.util.OverflowException;
7273
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
74+
import com.oracle.truffle.api.dsl.Bind;
7375
import com.oracle.truffle.api.dsl.Cached;
7476
import com.oracle.truffle.api.dsl.Cached.Shared;
7577
import com.oracle.truffle.api.dsl.GenerateUncached;
7678
import com.oracle.truffle.api.dsl.ImportStatic;
7779
import com.oracle.truffle.api.dsl.Specialization;
7880
import com.oracle.truffle.api.frame.VirtualFrame;
81+
import com.oracle.truffle.api.interop.InteropLibrary;
7982
import com.oracle.truffle.api.library.CachedLibrary;
8083
import com.oracle.truffle.api.nodes.Node;
8184
import com.oracle.truffle.api.profiles.BranchProfile;
@@ -107,7 +110,7 @@ public abstract static class StringMaterializeNode extends Node {
107110

108111
@Specialization(guards = {"isNativeCharSequence(x)", "isNativeMaterialized(x)"})
109112
static String doMaterializedNative(PString x) {
110-
return ((NativeCharSequence) x.getCharSequence()).materialize();
113+
return ((NativeCharSequence) x.getCharSequence()).getMaterialized();
111114
}
112115

113116
@Specialization(guards = {"isNativeCharSequence(x)"}, replaces = "doMaterializedNative")
@@ -172,7 +175,7 @@ static int doString(String str) {
172175
@Specialization(guards = "isMaterialized(x)")
173176
static int doMaterialized(PString x) {
174177
// cast guaranteed by the guard
175-
return ((String) x.getCharSequence()).length();
178+
return CompilerDirectives.castExact(x.getCharSequence(), String.class).length();
176179
}
177180

178181
@Specialization(guards = "isNativeCharSequence(x)")
@@ -183,19 +186,21 @@ static int doNativeCharSequence(PString x, @Cached StringMaterializeNode materia
183186
@Specialization(guards = "isLazyCharSequence(x)")
184187
static int doLazyString(PString x) {
185188
// cast guaranteed by the guard
186-
return ((LazyString) x.getCharSequence()).length();
189+
return CompilerDirectives.castExact(x.getCharSequence(), LazyString.class).length();
187190
}
188191

189192
@Specialization(guards = {"isNativeCharSequence(x)", "isNativeMaterialized(x)"})
190193
static int nativeString(PString x) {
191-
return ((NativeCharSequence) x.getCharSequence()).length();
194+
// cast guaranteed by the guard
195+
return CompilerDirectives.castExact(x.getCharSequence(), NativeCharSequence.class).getMaterialized().length();
192196
}
193197

194-
@Specialization(guards = {"isNativeCharSequence(x)", "!isNativeMaterialized(x)"}, replaces = "nativeString")
195-
static int nativeStringMat(PString x, @Cached PCallCapiFunction callCapi) {
196-
NativeCharSequence ncs = (NativeCharSequence) x.getCharSequence();
197-
ncs.materialize(callCapi);
198-
return ncs.length();
198+
@Specialization(guards = {"isNativeCharSequence(x)", "!isNativeMaterialized(x)"}, replaces = "nativeString", limit = "3")
199+
static int nativeStringMat(@SuppressWarnings("unused") PString x,
200+
@Bind("getNativeCharSequence(x)") NativeCharSequence ncs,
201+
@CachedLibrary("ncs") InteropLibrary lib,
202+
@Cached CastToJavaIntExactNode castToJavaIntNode) {
203+
return ncs.length(lib, castToJavaIntNode);
199204
}
200205

201206
@Specialization(limit = "2")
@@ -219,6 +224,10 @@ static int doNativeObject(PythonNativeObject x,
219224
private static int intValue(Number result) {
220225
return result.intValue();
221226
}
227+
228+
static NativeCharSequence getNativeCharSequence(PString self) {
229+
return (NativeCharSequence) self.getCharSequence();
230+
}
222231
}
223232

224233
public abstract static class CastToJavaStringCheckedNode extends Node {

0 commit comments

Comments
 (0)