4949import java .io .PrintWriter ;
5050import java .math .BigInteger ;
5151import java .nio .ByteBuffer ;
52+ import java .nio .ByteOrder ;
5253import java .nio .CharBuffer ;
5354import java .nio .charset .CharacterCodingException ;
5455import java .nio .charset .Charset ;
174175import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
175176import com .oracle .graal .python .runtime .PythonContext ;
176177import com .oracle .graal .python .runtime .PythonCore ;
178+ import com .oracle .graal .python .runtime .PythonOptions ;
177179import com .oracle .graal .python .runtime .exception .ExceptionUtils ;
178180import com .oracle .graal .python .runtime .exception .PException ;
179181import com .oracle .graal .python .runtime .exception .PythonErrorType ;
207209import com .oracle .truffle .api .interop .UnsupportedMessageException ;
208210import com .oracle .truffle .api .interop .UnsupportedTypeException ;
209211import com .oracle .truffle .api .library .CachedLibrary ;
212+ import com .oracle .truffle .api .nodes .ExplodeLoop ;
210213import com .oracle .truffle .api .nodes .Node ;
211214import com .oracle .truffle .api .nodes .NodeVisitor ;
212215import com .oracle .truffle .api .nodes .RootNode ;
@@ -1072,44 +1075,50 @@ private <T> T raiseNative(VirtualFrame frame, T defaultValue, PythonBuiltinClass
10721075 }
10731076 }
10741077
1075- @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 3 )
1078+ @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 4 )
10761079 @ GenerateNodeFactory
10771080 @ TypeSystemReference (PythonArithmeticTypes .class )
1081+ @ ImportStatic (PythonOptions .class )
10781082 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 ) {
10831089 try {
10841090 ByteBuffer bytes ;
1085- if (elementSize == 2L ) {
1086- if (!lib .hasArrayElements (o )) {
1091+ if (cachedElementSize == 1L || cachedElementSize == 2L || cachedElementSize == 4L ) {
1092+ if (!lib .hasArrayElements (arr )) {
10871093 return raiseNative (frame , errorMarker , PythonErrorType .SystemError , "provided object is not an array" , elementSize );
10881094 }
1089- long size = lib .getArraySize (o );
1090- bytes = readWithSize (lib , o , (int ) size );
1095+ bytes = readWithSize (lib , elemLib , arr , PInt .intValueExact (n ), (int ) cachedElementSize );
10911096 bytes .flip ();
1092- } else if (elementSize == 4L ) {
1093- bytes = wrap (getByteArrayNode .execute (frame , o , -1 ));
10941097 } else {
10951098 return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "unsupported 'wchar_t' size; was: %d" , elementSize );
10961099 }
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" );
10981103 } catch (CharacterCodingException e ) {
10991104 return raiseNative (frame , errorMarker , PythonErrorType .UnicodeError , "%m" , e );
11001105 } catch (IllegalArgumentException e ) {
11011106 return raiseNative (frame , errorMarker , PythonErrorType .LookupError , "%m" , e );
11021107 } catch (InteropException e ) {
11031108 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 );
11041111 }
11051112 }
11061113
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 ) {
11111119 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 );
11131122 } catch (ArithmeticException e ) {
11141123 return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "invalid parameters" );
11151124 }
@@ -1120,16 +1129,58 @@ private static String decode(ByteBuffer bytes) throws CharacterCodingException {
11201129 return getUTF32Charset (0 ).newDecoder ().decode (bytes ).toString ();
11211130 }
11221131
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 ));
11301137 }
11311138 return buf ;
11321139 }
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+ }
11331184 }
11341185
11351186 @ Builtin (name = "PyTruffle_Unicode_FromUTF8" , minNumOfPositionalArgs = 2 )
0 commit comments