49
49
import java .io .PrintWriter ;
50
50
import java .math .BigInteger ;
51
51
import java .nio .ByteBuffer ;
52
+ import java .nio .ByteOrder ;
52
53
import java .nio .CharBuffer ;
53
54
import java .nio .charset .CharacterCodingException ;
54
55
import java .nio .charset .Charset ;
174
175
import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
175
176
import com .oracle .graal .python .runtime .PythonContext ;
176
177
import com .oracle .graal .python .runtime .PythonCore ;
178
+ import com .oracle .graal .python .runtime .PythonOptions ;
177
179
import com .oracle .graal .python .runtime .exception .ExceptionUtils ;
178
180
import com .oracle .graal .python .runtime .exception .PException ;
179
181
import com .oracle .graal .python .runtime .exception .PythonErrorType ;
207
209
import com .oracle .truffle .api .interop .UnsupportedMessageException ;
208
210
import com .oracle .truffle .api .interop .UnsupportedTypeException ;
209
211
import com .oracle .truffle .api .library .CachedLibrary ;
212
+ import com .oracle .truffle .api .nodes .ExplodeLoop ;
210
213
import com .oracle .truffle .api .nodes .Node ;
211
214
import com .oracle .truffle .api .nodes .NodeVisitor ;
212
215
import com .oracle .truffle .api .nodes .RootNode ;
@@ -1072,44 +1075,50 @@ private <T> T raiseNative(VirtualFrame frame, T defaultValue, PythonBuiltinClass
1072
1075
}
1073
1076
}
1074
1077
1075
- @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 3 )
1078
+ @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 4 )
1076
1079
@ GenerateNodeFactory
1077
1080
@ TypeSystemReference (PythonArithmeticTypes .class )
1081
+ @ ImportStatic (PythonOptions .class )
1078
1082
abstract static class PyTruffle_Unicode_FromWchar extends NativeUnicodeBuiltin {
1079
- @ Specialization
1080
- Object doBytes (VirtualFrame frame , Object o , long elementSize , Object errorMarker ,
1081
- @ Shared ("getByteArrayNode" ) @ Cached GetByteArrayNode getByteArrayNode ,
1082
- @ Shared ("lib" ) @ CachedLibrary (limit = "3" ) InteropLibrary lib ) {
1083
+ @ Specialization (guards = "elementSize == cachedElementSize" , limit = "getVariableArgumentInlineCacheLimit()" )
1084
+ Object doBytes (VirtualFrame frame , Object arr , long n , long elementSize , Object errorMarker ,
1085
+ @ Cached CExtNodes .ToSulongNode toSulongNode ,
1086
+ @ Cached ("elementSize" ) long cachedElementSize ,
1087
+ @ CachedLibrary ("arr" ) InteropLibrary lib ,
1088
+ @ CachedLibrary (limit = "1" ) InteropLibrary elemLib ) {
1083
1089
try {
1084
1090
ByteBuffer bytes ;
1085
- if (elementSize == 2L ) {
1086
- if (!lib .hasArrayElements (o )) {
1091
+ if (cachedElementSize == 1L || cachedElementSize == 2L || cachedElementSize == 4L ) {
1092
+ if (!lib .hasArrayElements (arr )) {
1087
1093
return raiseNative (frame , errorMarker , PythonErrorType .SystemError , "provided object is not an array" , elementSize );
1088
1094
}
1089
- long size = lib .getArraySize (o );
1090
- bytes = readWithSize (lib , o , (int ) size );
1095
+ bytes = readWithSize (lib , elemLib , arr , PInt .intValueExact (n ), (int ) cachedElementSize );
1091
1096
bytes .flip ();
1092
- } else if (elementSize == 4L ) {
1093
- bytes = wrap (getByteArrayNode .execute (frame , o , -1 ));
1094
1097
} else {
1095
1098
return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "unsupported 'wchar_t' size; was: %d" , elementSize );
1096
1099
}
1097
- return decode (bytes );
1100
+ return toSulongNode .execute (decode (bytes ));
1101
+ } catch (ArithmeticException e ) {
1102
+ return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "array size too large" );
1098
1103
} catch (CharacterCodingException e ) {
1099
1104
return raiseNative (frame , errorMarker , PythonErrorType .UnicodeError , "%m" , e );
1100
1105
} catch (IllegalArgumentException e ) {
1101
1106
return raiseNative (frame , errorMarker , PythonErrorType .LookupError , "%m" , e );
1102
1107
} catch (InteropException e ) {
1103
1108
return raiseNative (frame , errorMarker , PythonErrorType .TypeError , "%m" , e );
1109
+ } catch (IllegalElementTypeException e ) {
1110
+ return raiseNative (frame , errorMarker , PythonErrorType .UnicodeDecodeError , "Invalid input element type '%p'" , e .elem );
1104
1111
}
1105
1112
}
1106
1113
1107
- @ Specialization
1108
- Object doBytes (VirtualFrame frame , Object o , PInt elementSize , Object errorMarker ,
1109
- @ Shared ("getByteArrayNode" ) @ Cached GetByteArrayNode getByteArrayNode ,
1110
- @ Shared ("lib" ) @ CachedLibrary (limit = "3" ) InteropLibrary lib ) {
1114
+ @ Specialization (limit = "getVariableArgumentInlineCacheLimit()" )
1115
+ Object doBytes (VirtualFrame frame , Object arr , PInt n , PInt elementSize , Object errorMarker ,
1116
+ @ Cached CExtNodes .ToSulongNode toSulongNode ,
1117
+ @ CachedLibrary ("arr" ) InteropLibrary lib ,
1118
+ @ CachedLibrary (limit = "1" ) InteropLibrary elemLib ) {
1111
1119
try {
1112
- return doBytes (frame , o , elementSize .longValueExact (), errorMarker , getByteArrayNode , lib );
1120
+ long es = elementSize .longValueExact ();
1121
+ return doBytes (frame , arr , n .longValueExact (), es , errorMarker , toSulongNode , es , lib , elemLib );
1113
1122
} catch (ArithmeticException e ) {
1114
1123
return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "invalid parameters" );
1115
1124
}
@@ -1120,16 +1129,58 @@ private static String decode(ByteBuffer bytes) throws CharacterCodingException {
1120
1129
return getUTF32Charset (0 ).newDecoder ().decode (bytes ).toString ();
1121
1130
}
1122
1131
1123
- @ TruffleBoundary
1124
- private static ByteBuffer readWithSize (InteropLibrary interopLib , Object o , int size ) throws UnsupportedMessageException , InvalidArrayIndexException {
1125
- ByteBuffer buf = ByteBuffer .allocate (size * Integer .BYTES );
1126
- for (long i = 0 ; i < size ; i ++) {
1127
- Object elem = interopLib .readArrayElement (o , i );
1128
- assert elem instanceof Number && 0 <= ((Number ) elem ).intValue () && ((Number ) elem ).intValue () < (1 << 16 );
1129
- buf .putInt (((Number ) elem ).intValue ());
1132
+ private static ByteBuffer readWithSize (InteropLibrary arrLib , InteropLibrary elemLib , Object o , int size , int elementSize )
1133
+ throws UnsupportedMessageException , InvalidArrayIndexException , IllegalElementTypeException {
1134
+ ByteBuffer buf = allocate (size * Integer .BYTES );
1135
+ for (int i = 0 ; i < size ; i += elementSize ) {
1136
+ putInt (buf , readElement (arrLib , elemLib , o , i , elementSize ));
1130
1137
}
1131
1138
return buf ;
1132
1139
}
1140
+
1141
+ @ ExplodeLoop
1142
+ private static int readElement (InteropLibrary arrLib , InteropLibrary elemLib , Object arr , int i , int elementSize )
1143
+ throws InvalidArrayIndexException , UnsupportedMessageException , IllegalElementTypeException {
1144
+ byte [] barr = new byte [4 ];
1145
+ for (int j = 0 ; j < elementSize ; j ++) {
1146
+ Object elem = arrLib .readArrayElement (arr , i + j );
1147
+ // The array object could be one of our wrappers (e.g. 'PySequenceArrayWrapper').
1148
+ // Since the Interop library does not allow to specify how many bytes we want to
1149
+ // read when we do readArrayElement, our wrappers always return long. So, we check
1150
+ // for 'long' here and cast down to 'byte'.
1151
+ if (elemLib .fitsInLong (elem )) {
1152
+ barr [j ] = (byte ) elemLib .asLong (elem );
1153
+ } else {
1154
+ CompilerDirectives .transferToInterpreter ();
1155
+ throw new IllegalElementTypeException (elem );
1156
+ }
1157
+ }
1158
+ return toInt (barr );
1159
+ }
1160
+
1161
+ @ TruffleBoundary (allowInlining = true )
1162
+ private static int toInt (byte [] barr ) {
1163
+ return ByteBuffer .wrap (barr ).order (ByteOrder .LITTLE_ENDIAN ).getInt ();
1164
+ }
1165
+
1166
+ @ TruffleBoundary (allowInlining = true )
1167
+ private static ByteBuffer allocate (int cap ) {
1168
+ return ByteBuffer .allocate (cap );
1169
+ }
1170
+
1171
+ @ TruffleBoundary (allowInlining = true )
1172
+ private static void putInt (ByteBuffer buf , int element ) {
1173
+ buf .putInt (element );
1174
+ }
1175
+
1176
+ private static final class IllegalElementTypeException extends Exception {
1177
+ private static final long serialVersionUID = 0L ;
1178
+ private final Object elem ;
1179
+
1180
+ IllegalElementTypeException (Object elem ) {
1181
+ this .elem = elem ;
1182
+ }
1183
+ }
1133
1184
}
1134
1185
1135
1186
@ Builtin (name = "PyTruffle_Unicode_FromUTF8" , minNumOfPositionalArgs = 2 )
0 commit comments