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