Skip to content

Commit a70a4e7

Browse files
committed
[GR-33231] Intrinsify libgraalpython/str.
PullRequest: graalpython/1955
2 parents 78bc2f1 + 971d6a9 commit a70a4e7

File tree

10 files changed

+712
-426
lines changed

10 files changed

+712
-426
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ private static String[] initializeCoreFiles() {
288288
"_descriptor",
289289
"object",
290290
"sys",
291-
"str",
292291
"type",
293292
"_imp",
294293
"function",

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ private static Object get(PythonContext ctx, String name) {
10091009
@ArgumentClinic(name = "encoding", conversion = ArgumentClinic.ClinicConversion.String, defaultValue = "\"utf-8\"", useDefaultForNone = true)
10101010
@ArgumentClinic(name = "errors", conversion = ArgumentClinic.ClinicConversion.String, defaultValue = "\"strict\"", useDefaultForNone = true)
10111011
@GenerateNodeFactory
1012-
abstract static class EncodeNode extends PythonTernaryClinicBuiltinNode {
1012+
public abstract static class EncodeNode extends PythonTernaryClinicBuiltinNode {
10131013

10141014
@Override
10151015
protected ArgumentClinicProvider getArgumentClinic() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/OperatorModuleBuiltins.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary;
5555
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
5656
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
57+
import com.oracle.graal.python.builtins.objects.dict.DictBuiltins;
5758
import com.oracle.graal.python.builtins.objects.dict.PDict;
5859
import com.oracle.graal.python.builtins.objects.ints.PInt;
5960
import com.oracle.graal.python.lib.PyNumberIndexNode;
@@ -156,19 +157,20 @@ public boolean doObject(VirtualFrame frame, Object value) {
156157
public abstract static class GetItemNode extends PythonBinaryBuiltinNode {
157158

158159
@Specialization
159-
public Object doDict(PDict dict, Object item) {
160-
return dict.getItem(item);
160+
public static Object doDict(VirtualFrame frame, PDict dict, Object item,
161+
@Cached DictBuiltins.GetItemNode getItem) {
162+
return getItem.execute(frame, dict, item);
161163
}
162164

163165
@Specialization
164-
public Object doSequence(VirtualFrame frame, PSequence value, Object index,
166+
public static Object doSequence(VirtualFrame frame, PSequence value, Object index,
165167
@Cached SequenceNodes.GetSequenceStorageNode getStorage,
166168
@Cached SequenceStorageNodes.GetItemNode getItemNode) {
167169
return getItemNode.execute(frame, getStorage.execute(value), index);
168170
}
169171

170172
@Specialization
171-
public Object doObject(VirtualFrame frame, Object value, Object index,
173+
public static Object doObject(VirtualFrame frame, Object value, Object index,
172174
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode getItemNode) {
173175
return getItemNode.executeObject(frame, value, index);
174176
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,92 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules;
4242

43-
import java.util.ArrayList;
43+
import com.oracle.graal.python.PythonLanguage;
44+
import com.oracle.graal.python.annotations.ArgumentClinic;
45+
import com.oracle.graal.python.builtins.Builtin;
4446
import java.util.List;
4547

4648
import com.oracle.graal.python.builtins.CoreFunctions;
4749
import com.oracle.graal.python.builtins.PythonBuiltins;
50+
import com.oracle.graal.python.builtins.objects.iterator.PSequenceIterator;
51+
import com.oracle.graal.python.builtins.objects.str.TemplateFormatter;
52+
import static com.oracle.graal.python.nodes.BuiltinNames.FORMATTER_FIELD_NAME_SPLIT;
53+
import static com.oracle.graal.python.nodes.BuiltinNames.FORMATTER_PARSER;
54+
import static com.oracle.graal.python.nodes.BuiltinNames._STRING;
4855
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
56+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode;
57+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
58+
import com.oracle.graal.python.runtime.ExecutionContext;
59+
import com.oracle.graal.python.runtime.PythonContext;
60+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
61+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
4962
import com.oracle.truffle.api.dsl.NodeFactory;
63+
import com.oracle.truffle.api.dsl.Specialization;
64+
import com.oracle.truffle.api.frame.VirtualFrame;
5065

51-
@CoreFunctions(defineModule = "_string")
66+
@CoreFunctions(defineModule = _STRING)
5267
public class StringModuleBuiltins extends PythonBuiltins {
5368
@Override
5469
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
55-
return new ArrayList<>();
70+
return StringModuleBuiltinsFactory.getFactories();
71+
}
72+
73+
@Builtin(name = FORMATTER_PARSER, minNumOfPositionalArgs = 1, parameterNames = {"self"})
74+
@ArgumentClinic(name = "self", conversion = ArgumentClinic.ClinicConversion.String)
75+
@GenerateNodeFactory
76+
abstract static class FormaterParserNode extends PythonUnaryClinicBuiltinNode {
77+
@Override
78+
protected ArgumentClinicProvider getArgumentClinic() {
79+
return StringModuleBuiltinsClinicProviders.FormaterParserNodeClinicProviderGen.INSTANCE;
80+
}
81+
82+
@Specialization
83+
PSequenceIterator formatterParser(VirtualFrame frame, String self) {
84+
TemplateFormatter formatter = new TemplateFormatter(self);
85+
List<Object[]> parserList;
86+
PythonLanguage language = PythonLanguage.get(this);
87+
PythonContext context = PythonContext.get(this);
88+
Object state = ExecutionContext.IndirectCallContext.enter(frame, language, context, this);
89+
try {
90+
parserList = formatter.formatterParser(this);
91+
} finally {
92+
ExecutionContext.IndirectCallContext.exit(frame, language, context, state);
93+
}
94+
return parserListToIterator(parserList, factory());
95+
}
96+
}
97+
98+
private static PSequenceIterator parserListToIterator(List<Object[]> parserList, PythonObjectFactory factory) {
99+
Object[] tuples = new Object[parserList.size()];
100+
for (int i = 0; i < tuples.length; i++) {
101+
tuples[i] = factory.createTuple(parserList.get(i));
102+
}
103+
return factory.createSequenceIterator(factory.createList(tuples));
104+
}
105+
106+
@Builtin(name = FORMATTER_FIELD_NAME_SPLIT, minNumOfPositionalArgs = 1, parameterNames = {"self"})
107+
@ArgumentClinic(name = "self", conversion = ArgumentClinic.ClinicConversion.String)
108+
@GenerateNodeFactory
109+
abstract static class FormaterFieldNameSplitNode extends PythonUnaryClinicBuiltinNode {
110+
@Override
111+
protected ArgumentClinicProvider getArgumentClinic() {
112+
return StringModuleBuiltinsClinicProviders.FormaterFieldNameSplitNodeClinicProviderGen.INSTANCE;
113+
}
114+
115+
@Specialization
116+
Object formatterParser(VirtualFrame frame, String self) {
117+
TemplateFormatter formatter = new TemplateFormatter(self);
118+
TemplateFormatter.FieldNameSplitResult result;
119+
PythonLanguage language = PythonLanguage.get(this);
120+
PythonContext context = PythonContext.get(this);
121+
Object state = ExecutionContext.IndirectCallContext.enter(frame, language, context, this);
122+
try {
123+
result = formatter.formatterFieldNameSplit(this);
124+
} finally {
125+
ExecutionContext.IndirectCallContext.exit(frame, language, context, state);
126+
}
127+
PythonObjectFactory factory = factory();
128+
return factory.createTuple(new Object[]{result.first, parserListToIterator(result.parserList, factory)});
129+
}
56130
}
57131
}

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

Lines changed: 109 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,12 @@
4444
import static com.oracle.graal.python.nodes.SpecialMethodNames.__RMUL__;
4545
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
4646
import static com.oracle.graal.python.runtime.exception.PythonErrorType.IndexError;
47-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.LookupError;
4847
import static com.oracle.graal.python.runtime.exception.PythonErrorType.MemoryError;
4948
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
50-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.UnicodeEncodeError;
5149
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
5250

53-
import java.nio.ByteBuffer;
54-
import java.nio.CharBuffer;
55-
import java.nio.charset.CharacterCodingException;
56-
import java.nio.charset.Charset;
5751
import java.nio.charset.CharsetEncoder;
58-
import java.nio.charset.CodingErrorAction;
59-
import java.nio.charset.IllegalCharsetNameException;
6052
import java.nio.charset.StandardCharsets;
61-
import java.nio.charset.UnsupportedCharsetException;
6253
import java.util.Arrays;
6354
import java.util.List;
6455
import java.util.Locale;
@@ -75,16 +66,22 @@
7566
import com.oracle.graal.python.builtins.CoreFunctions;
7667
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
7768
import com.oracle.graal.python.builtins.PythonBuiltins;
69+
import com.oracle.graal.python.builtins.modules.BuiltinFunctions;
70+
import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins;
71+
import com.oracle.graal.python.builtins.modules.OperatorModuleBuiltins;
7872
import com.oracle.graal.python.builtins.objects.PNone;
7973
import com.oracle.graal.python.builtins.objects.PNotImplemented;
8074
import com.oracle.graal.python.builtins.objects.bytes.BytesUtils;
75+
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
76+
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
8177
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
8278
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
8379
import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes;
8480
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
8581
import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
8682
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetObjectArrayNode;
8783
import com.oracle.graal.python.builtins.objects.common.SequenceNodesFactory.GetObjectArrayNodeGen;
84+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
8885
import com.oracle.graal.python.builtins.objects.dict.PDict;
8986
import com.oracle.graal.python.builtins.objects.iterator.PStringIterator;
9087
import com.oracle.graal.python.builtins.objects.list.ListBuiltins.ListReverseNode;
@@ -103,9 +100,17 @@
103100
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
104101
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
105102
import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsSameTypeNode;
103+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
104+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
106105
import com.oracle.graal.python.lib.PyNumberAsSizeNode;
107106
import com.oracle.graal.python.lib.PyObjectHashNode;
107+
import static com.oracle.graal.python.nodes.BuiltinNames.ENCODE;
108+
import static com.oracle.graal.python.nodes.BuiltinNames.FORMAT;
109+
import static com.oracle.graal.python.nodes.BuiltinNames.FORMAT_MAP;
108110
import com.oracle.graal.python.nodes.ErrorMessages;
111+
import static com.oracle.graal.python.nodes.ErrorMessages.ENCODER_RETURNED_P_INSTEAD_OF_BYTES;
112+
import static com.oracle.graal.python.nodes.ErrorMessages.OBJ_NOT_SUBSCRIPTABLE;
113+
import static com.oracle.graal.python.nodes.ErrorMessages.TAKES_EXACTLY_S_ARGUMENTS_D_GIVEN;
109114
import com.oracle.graal.python.nodes.PGuards;
110115
import com.oracle.graal.python.nodes.PRaiseNode;
111116
import com.oracle.graal.python.nodes.SpecialMethodNames;
@@ -227,6 +232,76 @@ private Spec getAndValidateSpec(String formatString) {
227232
}
228233
}
229234

235+
@Builtin(name = FORMAT, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true, declaresExplicitSelf = true)
236+
@GenerateNodeFactory
237+
abstract static class StrFormatNode extends PythonBuiltinNode {
238+
@Specialization
239+
String format(VirtualFrame frame, PString self, Object[] args, PKeyword[] kwargs,
240+
@Cached BuiltinFunctions.FormatNode format,
241+
@Cached OperatorModuleBuiltins.GetItemNode getItem) {
242+
return format(frame, self.getValue(), args, kwargs, format, getItem);
243+
}
244+
245+
@Specialization
246+
String format(VirtualFrame frame, String self, Object[] args, PKeyword[] kwargs,
247+
@Cached BuiltinFunctions.FormatNode format,
248+
@Cached OperatorModuleBuiltins.GetItemNode getItem) {
249+
250+
TemplateFormatter template = new TemplateFormatter(self);
251+
252+
PythonLanguage language = PythonLanguage.get(this);
253+
PythonContext context = PythonContext.get(this);
254+
Object state = IndirectCallContext.enter(frame, language, context, this);
255+
try {
256+
return template.build(this, args, kwargs, format, getItem);
257+
} finally {
258+
IndirectCallContext.exit(frame, language, context, state);
259+
}
260+
}
261+
}
262+
263+
@Builtin(name = FORMAT_MAP, minNumOfPositionalArgs = 1, declaresExplicitSelf = true, parameterNames = {"self", "mapping"})
264+
@ArgumentClinic(name = "self", conversion = ArgumentClinic.ClinicConversion.String)
265+
@GenerateNodeFactory
266+
@ImportStatic(SpecialMethodNames.class)
267+
abstract static class FormatMapNode extends PythonBinaryClinicBuiltinNode {
268+
@Override
269+
protected ArgumentClinicProvider getArgumentClinic() {
270+
return StringBuiltinsClinicProviders.FormatMapNodeClinicProviderGen.INSTANCE;
271+
}
272+
273+
@Specialization(guards = "lib.isMapping(mapping)", limit = "1")
274+
String format(VirtualFrame frame, String self, Object mapping,
275+
@Cached BuiltinFunctions.FormatNode format,
276+
@Cached OperatorModuleBuiltins.GetItemNode getItem,
277+
@SuppressWarnings("unused") @CachedLibrary("mapping") PythonObjectLibrary lib) {
278+
279+
TemplateFormatter template = new TemplateFormatter(self);
280+
281+
PythonLanguage language = PythonLanguage.get(this);
282+
PythonContext context = PythonContext.get(this);
283+
Object state = IndirectCallContext.enter(frame, language, context, this);
284+
try {
285+
return template.build(this, null, mapping, format, getItem);
286+
} finally {
287+
IndirectCallContext.exit(frame, language, context, state);
288+
}
289+
}
290+
291+
@SuppressWarnings("unused")
292+
@Specialization(guards = {"!lib.isMapping(obj)", "!isNone(obj)"}, limit = "1")
293+
String format(String self, Object obj,
294+
@SuppressWarnings("unused") @CachedLibrary("obj") PythonObjectLibrary lib) {
295+
throw raise(TypeError, OBJ_NOT_SUBSCRIPTABLE, obj);
296+
}
297+
298+
@SuppressWarnings("unused")
299+
@Specialization(guards = "isNone(obj)")
300+
String format(String self, PNone obj) {
301+
throw raise(TypeError, TAKES_EXACTLY_S_ARGUMENTS_D_GIVEN, "format_map", "one", 0);
302+
}
303+
}
304+
230305
@Builtin(name = __REPR__, minNumOfPositionalArgs = 1)
231306
@GenerateNodeFactory
232307
abstract static class ReprNode extends PythonUnaryBuiltinNode {
@@ -1743,8 +1818,15 @@ public int rindex(Object self, Object sub, int start, int end,
17431818
}
17441819
}
17451820

1746-
// This is only used during bootstrap and then replaced with Python code
1747-
@Builtin(name = "encode", minNumOfPositionalArgs = 1, parameterNames = {"self", "encoding", "errors"})
1821+
@Builtin(name = ENCODE, minNumOfPositionalArgs = 1, parameterNames = {"self", "encoding", "errors"}, doc = "Decode the bytes using the codec registered for encoding.\n\n" +
1822+
" encoding\n" +
1823+
" The encoding with which to decode the bytes.\n" +
1824+
" errors\n" +
1825+
" The error handling scheme to use for the handling of decoding errors.\n" +
1826+
" The default is 'strict' meaning that decoding errors raise a\n" +
1827+
" UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n" +
1828+
" as well as any other name registered with codecs.register_error that\n" +
1829+
" can handle UnicodeDecodeErrors.")
17481830
@ArgumentClinic(name = "encoding", conversion = ClinicConversion.String, defaultValue = "\"utf-8\"", useDefaultForNone = true)
17491831
@ArgumentClinic(name = "errors", conversion = ClinicConversion.String, defaultValue = "\"strict\"", useDefaultForNone = true)
17501832
@GenerateNodeFactory
@@ -1757,48 +1839,26 @@ protected ArgumentClinicProvider getArgumentClinic() {
17571839
}
17581840

17591841
@Specialization
1760-
Object doStringEncodingErrors(String self, String encoding, String errors) {
1761-
return encodeString(self, encoding, errors);
1842+
Object doStringEncoding(VirtualFrame frame, String self, String encoding, String errors,
1843+
@Cached CodecsModuleBuiltins.EncodeNode encodeNode,
1844+
@Cached SequenceStorageNodes.CopyNode copyNode) {
1845+
Object result = encodeNode.call(frame, self, encoding, errors);
1846+
if (!(result instanceof PBytes)) {
1847+
if (result instanceof PByteArray) {
1848+
return factory().createBytes(copyNode.execute(((PByteArray) result).getSequenceStorage()));
1849+
}
1850+
throw raise(TypeError, ENCODER_RETURNED_P_INSTEAD_OF_BYTES, encoding, result);
1851+
}
1852+
return result;
17621853
}
17631854

17641855
@Specialization
1765-
Object doGeneric(Object self, String encoding, String errors,
1766-
@Cached CastToJavaStringCheckedNode castSelfNode) {
1856+
Object doGeneric(VirtualFrame frame, Object self, String encoding, String errors,
1857+
@Cached CastToJavaStringCheckedNode castSelfNode,
1858+
@Cached CodecsModuleBuiltins.EncodeNode encodeNode,
1859+
@Cached SequenceStorageNodes.CopyNode copyNode) {
17671860
String selfStr = castSelfNode.cast(self, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, "index", self);
1768-
return encodeString(selfStr, encoding, errors);
1769-
}
1770-
1771-
@TruffleBoundary
1772-
private Object encodeString(String self, String encoding, String errors) {
1773-
// Note: to support custom actions, we can use CharsetEncoderICU from icu4j-charset
1774-
CodingErrorAction errorAction;
1775-
switch (errors) {
1776-
case "ignore":
1777-
errorAction = CodingErrorAction.IGNORE;
1778-
break;
1779-
case "replace":
1780-
errorAction = CodingErrorAction.REPLACE;
1781-
break;
1782-
default:
1783-
errorAction = CodingErrorAction.REPORT;
1784-
break;
1785-
}
1786-
1787-
Charset cs;
1788-
try {
1789-
cs = Charset.forName(encoding);
1790-
} catch (UnsupportedCharsetException | IllegalCharsetNameException e) {
1791-
throw raise(LookupError, ErrorMessages.UNKNOWN_ENCODING, encoding);
1792-
}
1793-
try {
1794-
ByteBuffer encoded = cs.newEncoder().onMalformedInput(errorAction).onUnmappableCharacter(errorAction).encode(CharBuffer.wrap(self));
1795-
int n = encoded.remaining();
1796-
byte[] data = new byte[n];
1797-
encoded.get(data);
1798-
return factory().createBytes(data);
1799-
} catch (CharacterCodingException e) {
1800-
throw raise(UnicodeEncodeError, e);
1801-
}
1861+
return doStringEncoding(frame, selfStr, encoding, errors, encodeNode, copyNode);
18021862
}
18031863
}
18041864

0 commit comments

Comments
 (0)