Skip to content

Commit 797f64a

Browse files
committed
Fix creating lists and tuples from strings with surrogates
1 parent ae460fb commit 797f64a

File tree

4 files changed

+23
-39
lines changed

4 files changed

+23
-39
lines changed

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.str;
4242

43-
import com.oracle.truffle.api.CompilerDirectives;
43+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4444

4545
public final class StringUtils {
4646
public enum StripKind {
@@ -203,8 +203,24 @@ public static String strip(String str, String chars, StripKind stripKind) {
203203
return str.substring(i, j);
204204
}
205205

206-
@CompilerDirectives.TruffleBoundary
206+
@TruffleBoundary
207207
public static boolean containsNullCharacter(String value) {
208208
return value.indexOf(0) > 0;
209209
}
210+
211+
@TruffleBoundary
212+
public static Object[] toCharacterArray(String arg) {
213+
Object[] values = new Object[arg.codePointCount(0, arg.length())];
214+
for (int i = 0, o = 0; i < arg.length(); o++) {
215+
int codePoint = arg.codePointAt(i);
216+
int charCount = Character.charCount(codePoint);
217+
if (charCount == 1) {
218+
values[o] = String.valueOf((char) codePoint);
219+
} else {
220+
values[o] = String.valueOf(Character.toChars(codePoint));
221+
}
222+
i += charCount;
223+
}
224+
return values;
225+
}
210226
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/ListNodes.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
import com.oracle.graal.python.builtins.objects.list.PList;
5454
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
5555
import com.oracle.graal.python.builtins.objects.slice.PSlice;
56-
import com.oracle.graal.python.builtins.objects.str.PString;
56+
import com.oracle.graal.python.builtins.objects.str.StringUtils;
5757
import com.oracle.graal.python.nodes.ErrorMessages;
5858
import com.oracle.graal.python.nodes.PGuards;
5959
import com.oracle.graal.python.nodes.PNodeWithContext;
@@ -95,25 +95,10 @@ public final PList execute(Object value) {
9595

9696
protected abstract PList execute(Object cls, Object value);
9797

98-
@Specialization
99-
PList listString(Object cls, PString arg,
100-
@Shared("appendNode") @Cached AppendNode appendNode,
101-
@Shared("factory") @Cached PythonObjectFactory factory) {
102-
return listString(cls, arg.getValue(), appendNode, factory);
103-
}
104-
10598
@Specialization
10699
PList listString(Object cls, String arg,
107-
@Shared("appendNode") @Cached AppendNode appendNode,
108100
@Shared("factory") @Cached PythonObjectFactory factory) {
109-
char[] chars = arg.toCharArray();
110-
PList list = factory.createList(cls);
111-
112-
for (char c : chars) {
113-
appendNode.execute(list, Character.toString(c));
114-
}
115-
116-
return list;
101+
return factory.createList(cls, StringUtils.toCharacterArray(arg));
117102
}
118103

119104
@Specialization(guards = "isNoValue(none)")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.graal.python.builtins.objects.PNone;
4545
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.CreateStorageFromIteratorNode;
4646
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
47+
import com.oracle.graal.python.builtins.objects.str.StringUtils;
4748
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
4849
import com.oracle.graal.python.nodes.PGuards;
4950
import com.oracle.graal.python.nodes.PNodeWithContext;
@@ -79,11 +80,7 @@ PTuple tuple(Object cls, @SuppressWarnings("unused") PNone none) {
7980

8081
@Specialization
8182
PTuple tuple(Object cls, String arg) {
82-
Object[] values = new Object[arg.length()];
83-
for (int i = 0; i < arg.length(); i++) {
84-
values[i] = String.valueOf(arg.charAt(i));
85-
}
86-
return factory.createTuple(cls, values);
83+
return factory.createTuple(cls, StringUtils.toCharacterArray(arg));
8784
}
8885

8986
@Specialization(guards = {"cannotBeOverridden(cls)", "cannotBeOverridden(plib.getLazyPythonClass(iterable))"}, limit = "2")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/DestructuringAssignmentNode.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
2929

30-
import com.oracle.graal.python.PythonLanguage;
3130
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
3231
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
3332
import com.oracle.graal.python.builtins.objects.list.PList;
@@ -38,14 +37,10 @@
3837
import com.oracle.graal.python.nodes.expression.ExpressionNode;
3938
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
4039
import com.oracle.graal.python.nodes.statement.StatementNode;
41-
import com.oracle.graal.python.runtime.PythonContext;
42-
import com.oracle.graal.python.runtime.PythonCore;
4340
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
4441
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
4542
import com.oracle.truffle.api.CompilerAsserts;
4643
import com.oracle.truffle.api.CompilerDirectives;
47-
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
48-
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
4944
import com.oracle.truffle.api.dsl.Cached;
5045
import com.oracle.truffle.api.dsl.Cached.Shared;
5146
import com.oracle.truffle.api.dsl.Specialization;
@@ -56,7 +51,6 @@
5651
public abstract class DestructuringAssignmentNode extends StatementNode implements WriteNode {
5752
/* Lazily initialized helpers, also acting as branch profiles */
5853
@Child private PRaiseNode raiseNode;
59-
@CompilationFinal private ContextReference<PythonContext> contextRef;
6054

6155
/* Syntactic children */
6256
@Child private ExpressionNode rhs;
@@ -128,7 +122,7 @@ private void writeSequenceStorage(VirtualFrame frame, SequenceStorage sequenceSt
128122
int len = lenNode.execute(sequenceStorage);
129123
if (len > slots.length) {
130124
CompilerDirectives.transferToInterpreter();
131-
throw getCore().raise(ValueError, ErrorMessages.TOO_MANY_VALUES_TO_UNPACK, slots.length);
125+
throw ensureRaiseNode().raise(ValueError, ErrorMessages.TOO_MANY_VALUES_TO_UNPACK, slots.length);
132126
} else if (len < slots.length) {
133127
throw ensureRaiseNode().raise(ValueError, ErrorMessages.NOT_ENOUGH_VALUES_TO_UNPACK, slots.length, len);
134128
} else {
@@ -187,14 +181,6 @@ void writeIterableStarred(VirtualFrame frame, Object iterable,
187181
performAssignments(frame);
188182
}
189183

190-
private PythonCore getCore() {
191-
if (contextRef == null) {
192-
CompilerDirectives.transferToInterpreterAndInvalidate();
193-
contextRef = lookupContextReference(PythonLanguage.class);
194-
}
195-
return contextRef.get().getCore();
196-
}
197-
198184
private PRaiseNode ensureRaiseNode() {
199185
if (raiseNode == null) {
200186
CompilerDirectives.transferToInterpreterAndInvalidate();

0 commit comments

Comments
 (0)