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 ;
173174import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
174175import com .oracle .graal .python .runtime .PythonContext ;
175176import com .oracle .graal .python .runtime .PythonCore ;
177+ import com .oracle .graal .python .runtime .PythonOptions ;
176178import com .oracle .graal .python .runtime .exception .ExceptionUtils ;
177179import com .oracle .graal .python .runtime .exception .PException ;
178180import com .oracle .graal .python .runtime .exception .PythonErrorType ;
206208import com .oracle .truffle .api .interop .UnsupportedMessageException ;
207209import com .oracle .truffle .api .interop .UnsupportedTypeException ;
208210import com .oracle .truffle .api .library .CachedLibrary ;
211+ import com .oracle .truffle .api .nodes .ExplodeLoop ;
209212import com .oracle .truffle .api .nodes .Node ;
210213import com .oracle .truffle .api .nodes .NodeVisitor ;
211214import com .oracle .truffle .api .nodes .RootNode ;
@@ -1071,44 +1074,50 @@ private <T> T raiseNative(VirtualFrame frame, T defaultValue, PythonBuiltinClass
10711074 }
10721075 }
10731076
1074- @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 3 )
1077+ @ Builtin (name = "PyTruffle_Unicode_FromWchar" , minNumOfPositionalArgs = 4 )
10751078 @ GenerateNodeFactory
10761079 @ TypeSystemReference (PythonArithmeticTypes .class )
1080+ @ ImportStatic (PythonOptions .class )
10771081 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 ) {
10821088 try {
10831089 ByteBuffer bytes ;
1084- if (elementSize == 2L ) {
1085- if (!lib .hasArrayElements (o )) {
1090+ if (cachedElementSize == 1L || cachedElementSize == 2L || cachedElementSize == 4L ) {
1091+ if (!lib .hasArrayElements (arr )) {
10861092 return raiseNative (frame , errorMarker , PythonErrorType .SystemError , "provided object is not an array" , elementSize );
10871093 }
1088- long size = lib .getArraySize (o );
1089- bytes = readWithSize (lib , o , (int ) size );
1094+ bytes = readWithSize (lib , elemLib , arr , PInt .intValueExact (n ), (int ) cachedElementSize );
10901095 bytes .flip ();
1091- } else if (elementSize == 4L ) {
1092- bytes = wrap (getByteArrayNode .execute (frame , o , -1 ));
10931096 } else {
10941097 return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "unsupported 'wchar_t' size; was: %d" , elementSize );
10951098 }
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" );
10971102 } catch (CharacterCodingException e ) {
10981103 return raiseNative (frame , errorMarker , PythonErrorType .UnicodeError , "%m" , e );
10991104 } catch (IllegalArgumentException e ) {
11001105 return raiseNative (frame , errorMarker , PythonErrorType .LookupError , "%m" , e );
11011106 } catch (InteropException e ) {
11021107 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 );
11031110 }
11041111 }
11051112
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 ) {
11101118 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 );
11121121 } catch (ArithmeticException e ) {
11131122 return raiseNative (frame , errorMarker , PythonErrorType .ValueError , "invalid parameters" );
11141123 }
@@ -1119,16 +1128,58 @@ private static String decode(ByteBuffer bytes) throws CharacterCodingException {
11191128 return getUTF32Charset (0 ).newDecoder ().decode (bytes ).toString ();
11201129 }
11211130
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 ));
11291136 }
11301137 return buf ;
11311138 }
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+ }
11321183 }
11331184
11341185 @ Builtin (name = "PyTruffle_Unicode_FromUTF8" , minNumOfPositionalArgs = 2 )
0 commit comments