Skip to content

Commit 2a9488b

Browse files
committed
[GR-10346] Support writing multiple bytes to 'ob_sval'/'ob_start'.
PullRequest: graalpython/257
2 parents f55f64b + 83da2e5 commit 2a9488b

File tree

8 files changed

+122
-51
lines changed

8 files changed

+122
-51
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,19 @@ void* native_to_java_exported(PyObject* obj) {
199199
return native_to_java(obj);
200200
}
201201

202+
void* native_pointer_to_java(PyObject* obj) {
203+
if (obj == NULL) {
204+
return Py_NoValue;
205+
} else if (obj == Py_None) {
206+
return Py_None;
207+
} else if (polyglot_is_string(obj)) {
208+
return obj;
209+
} else if (!truffle_cannot_be_handle(obj)) {
210+
return resolve_handle(cache, (uint64_t)obj);
211+
}
212+
return obj;
213+
}
214+
202215
__attribute__((always_inline))
203216
inline void* to_java(PyObject* obj) {
204217
return polyglot_invoke(PY_TRUFFLE_CEXT, "to_java", native_to_java(obj));

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ extern void* (*PY_TRUFFLE_CEXT_LANDING_PTR)(void* name, ...);
144144

145145
#define as_char_pointer(obj) ((const char*)UPCALL_CEXT_PTR(polyglot_from_string("to_char_pointer", "ascii"), native_to_java(obj)))
146146
#define as_long(obj) ((long)polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "to_long", to_java(obj))))
147-
#define as_long_long(obj) ((long long)polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyLong_AsPrimitive", to_java(obj), 1, sizeof(long long), polyglot_from_string("long long", "utf-8"))))
148-
#define as_unsigned_long_long(obj) ((unsigned long long)polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyLong_AsPrimitive", to_java(obj), 0, sizeof(unsigned long long), polyglot_from_string("unsigned long long", "utf-8"))))
147+
#define as_long_long(obj) ((long long)polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyLong_AsPrimitive", to_java(obj), 1, sizeof(long long))))
148+
#define as_unsigned_long_long(obj) ((unsigned long long)polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyLong_AsPrimitive", to_java(obj), 0, sizeof(unsigned long long))))
149149
#define as_int(obj) ((int)as_long(obj))
150150
#define as_short(obj) ((short)as_long(obj))
151151
#define as_uchar(obj) ((unsigned char)as_long(obj))

graalpython/com.oracle.graal.python.test/src/tests/test_math.py

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ def ftest(self, name, got, expected, ulp_tol=5, abs_tol=0.0):
178178
"""
179179
failure = result_check(expected, got, ulp_tol, abs_tol)
180180
if failure is not None:
181-
self.fail("{}: {}".format(name, failure))
181+
raise RuntimeError("{}: {}".format(name, failure))
182+
#self.fail("{}: {}".format(name, failure))
182183

183184
def testConstants(self):
184185
# Ref: Abramowitz & Stegun (Dover, 1965)
@@ -223,8 +224,7 @@ def __float__(self):
223224
def testAcosh(self):
224225
self.assertRaises(TypeError, math.acosh)
225226
self.ftest('acosh(1)', math.acosh(1), 0)
226-
# TODO uncomment when GR-10346 will be fixed
227-
#self.ftest('acosh(2)', math.acosh(2), 1.3169578969248168)
227+
self.ftest('acosh(2)', math.acosh(2), 1.3169578969248168)
228228
self.assertRaises(ValueError, math.acosh, 0)
229229
self.assertRaises(ValueError, math.acosh, -1)
230230
self.assertEqual(math.acosh(INF), INF)
@@ -233,9 +233,8 @@ def testAcosh(self):
233233

234234
class MyFF:
235235
def __float__(self):
236-
return 6
237-
# TODO uncomment when GR-10346 will be fixed
238-
#self.ftest('acos(MyFloat())', math.acosh(MyFF()), 0.9272952180016123)
236+
return 1.4616427410996713
237+
self.ftest('acos(MyFloat())', math.acosh(MyFF()), 0.9272952180016123)
239238
self.assertRaises(ValueError, math.acosh, MyFloat())
240239
math.acosh(BIG_INT)
241240
self.assertRaises(TypeError, math.acosh, 'ahoj')
@@ -279,8 +278,7 @@ def testLog(self):
279278
self.ftest('log(32,2)', math.log(32,2), 5)
280279
self.ftest('log(10**40, 10)', math.log(10**40, 10), 40)
281280
self.ftest('log(10**40, 10**20)', math.log(10**40, 10**20), 2)
282-
# TODO uncomment when GR-10346 will be fixed
283-
#self.ftest('log(10**1000)', math.log(10**1000), 2302.5850929940457)
281+
self.ftest('log(10**1000)', math.log(10**1000), 2302.5850929940457)
284282
self.assertRaises(ValueError, math.log, -1.5)
285283
self.assertRaises(ValueError, math.log, -10**1000)
286284
self.assertRaises(ValueError, math.log, NINF)
@@ -357,11 +355,9 @@ def testLog10(self):
357355
self.assertTrue(math.isnan(math.log10(NAN)))
358356

359357
# test of specializations
360-
# TODO uncomment when GR-10346 will be fixed
361-
#self.ftest('log10(MyFloat())', math.log10(MyFloat()), -0.22184874961635637)
358+
self.ftest('log10(MyFloat())', math.log10(MyFloat()), -0.22184874961635637)
362359
self.assertRaises(TypeError, math.log10, 'ahoj')
363-
# TODO uncomment when GR-10346 will be fixed
364-
#self.ftest('log10(BIG_INT)', math.log10(BIG_INT), 30.999999671364986)
360+
self.ftest('log10(BIG_INT)', math.log10(BIG_INT), 30.999999671364986)
365361

366362
def testIsfinite(self):
367363
self.assertTrue(math.isfinite(0.0))
@@ -761,11 +757,9 @@ def testAtan2(self):
761757

762758
def testCos(self):
763759
self.assertRaises(TypeError, math.cos)
764-
# TODO uncomment when GR-10346 will be fixed
765-
#self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0, abs_tol=ulp(1))
760+
self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0, abs_tol=ulp(1))
766761
self.ftest('cos(0)', math.cos(0), 1)
767-
# TODO uncomment when GR-10346 will be fixed
768-
#self.ftest('cos(pi/2)', math.cos(math.pi/2), 0, abs_tol=ulp(1))
762+
self.ftest('cos(pi/2)', math.cos(math.pi/2), 0, abs_tol=ulp(1))
769763
self.ftest('cos(pi)', math.cos(math.pi), -1)
770764
try:
771765
self.assertTrue(math.isnan(math.cos(INF)))
@@ -774,7 +768,7 @@ def testCos(self):
774768
self.assertRaises(ValueError, math.cos, INF)
775769
self.assertRaises(ValueError, math.cos, NINF)
776770
self.assertTrue(math.isnan(math.cos(NAN)))
777-
771+
778772
#test of specializations
779773
self.ftest('cos(BIG_INT)', math.cos(BIG_INT), 0.4145587418469303)
780774
self.ftest('cos(MyFloat())', math.cos(MyFloat()), 0.8253356149096783)
@@ -783,8 +777,7 @@ def testCos(self):
783777
def testCosh(self):
784778
self.assertRaises(TypeError, math.cosh)
785779
self.ftest('cosh(0)', math.cosh(0), 1)
786-
# TODO uncomment when GR-10346 will be fixed
787-
#self.ftest('cosh(2)-2*cosh(1)**2', math.cosh(2)-2*math.cosh(1)**2, -1) # Thanks to Lambert
780+
self.ftest('cosh(2)-2*cosh(1)**2', math.cosh(2)-2*math.cosh(1)**2, -1) # Thanks to Lambert
788781
self.assertEqual(math.cosh(INF), INF)
789782
self.assertEqual(math.cosh(NINF), INF)
790783
self.assertTrue(math.isnan(math.cosh(NAN)))
@@ -815,8 +808,7 @@ def testSin(self):
815808
def testSinh(self):
816809
self.assertRaises(TypeError, math.sinh)
817810
self.ftest('sinh(0)', math.sinh(0), 0)
818-
# TODO uncomment when GR-10346 will be fixed
819-
#self.ftest('sinh(1)**2-cosh(1)**2', math.sinh(1)**2-math.cosh(1)**2, -1)
811+
self.ftest('sinh(1)**2-cosh(1)**2', math.sinh(1)**2-math.cosh(1)**2, -1)
820812
self.ftest('sinh(1)+sinh(-1)', math.sinh(1)+math.sinh(-1), 0)
821813
self.assertEqual(math.sinh(INF), INF)
822814
self.assertEqual(math.sinh(NINF), NINF)
@@ -830,9 +822,8 @@ def testSinh(self):
830822
def testTan(self):
831823
self.assertRaises(TypeError, math.tan)
832824
self.ftest('tan(0)', math.tan(0), 0)
833-
# TODO uncomment when GR-10346 will be fixed
834-
#self.ftest('tan(pi/4)', math.tan(math.pi/4), 1)
835-
#self.ftest('tan(-pi/4)', math.tan(-math.pi/4), -1)
825+
self.ftest('tan(pi/4)', math.tan(math.pi/4), 1)
826+
self.ftest('tan(-pi/4)', math.tan(-math.pi/4), -1)
836827
try:
837828
self.assertTrue(math.isnan(math.tan(INF)))
838829
self.assertTrue(math.isnan(math.tan(NINF)))
@@ -849,8 +840,7 @@ def testTan(self):
849840
def testTanh(self):
850841
self.assertRaises(TypeError, math.tanh)
851842
self.ftest('tanh(0)', math.tanh(0), 0)
852-
# TODO uncomment when GR-10346 will be fixed
853-
#self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0, abs_tol=ulp(1))
843+
self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0, abs_tol=ulp(1))
854844
self.ftest('tanh(inf)', math.tanh(INF), 1)
855845
self.ftest('tanh(-inf)', math.tanh(NINF), -1)
856846
self.assertTrue(math.isnan(math.tanh(NAN)))
@@ -863,9 +853,8 @@ def testTanh(self):
863853
def testAsinh(self):
864854
self.assertRaises(TypeError, math.asinh)
865855
self.ftest('asinh(0)', math.asinh(0), 0)
866-
# TODO uncomment when GR-10346 will be fixed
867-
#self.ftest('asinh(1)', math.asinh(1), 0.88137358701954305)
868-
#self.ftest('asinh(-1)', math.asinh(-1), -0.88137358701954305)
856+
self.ftest('asinh(1)', math.asinh(1), 0.88137358701954305)
857+
self.ftest('asinh(-1)', math.asinh(-1), -0.88137358701954305)
869858
self.assertEqual(math.asinh(INF), INF)
870859
self.assertEqual(math.asinh(NINF), NINF)
871860
self.assertTrue(math.isnan(math.asinh(NAN)))
@@ -892,8 +881,7 @@ def testAtan(self):
892881
def testAtanh(self):
893882
self.assertRaises(TypeError, math.atan)
894883
self.ftest('atanh(0)', math.atanh(0), 0)
895-
# TODO uncomment when GR-10346 will be fixed
896-
#self.ftest('atanh(0.5)', math.atanh(0.5), 0.54930614433405489)
884+
self.ftest('atanh(0.5)', math.atanh(0.5), 0.54930614433405489)
897885
#self.ftest('atanh(-0.5)', math.atanh(-0.5), -0.54930614433405489)
898886
self.assertRaises(ValueError, math.atanh, 1)
899887
self.assertRaises(ValueError, math.atanh, -1)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TruffleCextBuiltins.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,11 +1701,6 @@ PBytes doPIntOvf(PInt size, Object errorMarker) {
17011701
Object doGeneric(Object size, Object errorMarker) {
17021702
return raiseNative(errorMarker, TypeError, "expected 'int', but was '%p'", size);
17031703
}
1704-
1705-
@TruffleBoundary
1706-
private static void addToSet(PythonClass base, PythonClass value) {
1707-
base.getSubClasses().add(value);
1708-
}
17091704
}
17101705

17111706
@Builtin(name = "PyTruffle_Upcall", minNumOfPositionalArgs = 3, takesVarArgs = true, declaresExplicitSelf = true)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/CExtNodes.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,8 @@ public abstract static class ToJavaNode extends CExtBaseNode {
593593
@Child private PCallNativeNode callNativeNode;
594594
@Child private AsPythonObjectNode toJavaNode = AsPythonObjectNode.create();
595595

596-
@CompilationFinal TruffleObject nativeToJavaFunction;
596+
@CompilationFinal private TruffleObject nativeToJavaFunction;
597+
@CompilationFinal private TruffleObject nativePointerToJavaFunction;
597598

598599
public abstract Object execute(Object value);
599600

@@ -627,25 +628,48 @@ boolean doBoolean(boolean b) {
627628
return b;
628629
}
629630

631+
@Specialization
632+
Object doInt(int i) {
633+
// Unfortunately, an int could be a native pointer and therefore a handle. So, we must
634+
// try resolving it. At least we know that it's not a native type.
635+
return native_pointer_to_java(i);
636+
}
637+
638+
@Specialization
639+
Object doLong(long l) {
640+
// Unfortunately, a long could be a native pointer and therefore a handle. So, we must
641+
// try resolving it. At least we know that it's not a native type.
642+
return native_pointer_to_java(l);
643+
}
644+
630645
@Specialization
631646
byte doLong(byte b) {
632647
return b;
633648
}
634649

635650
@Fallback
636651
Object doForeign(Object value) {
637-
if (callNativeNode == null) {
652+
if (nativeToJavaFunction == null) {
638653
CompilerDirectives.transferToInterpreterAndInvalidate();
639-
callNativeNode = insert(PCallNativeNode.create());
654+
nativeToJavaFunction = importCAPISymbol(NativeCAPISymbols.FUN_NATIVE_TO_JAVA);
640655
}
641-
if (callNativeNode == null) {
656+
return call_native_conversion(nativeToJavaFunction, value);
657+
}
658+
659+
private Object native_pointer_to_java(Object value) {
660+
if (nativePointerToJavaFunction == null) {
642661
CompilerDirectives.transferToInterpreterAndInvalidate();
662+
nativePointerToJavaFunction = importCAPISymbol(NativeCAPISymbols.FUN_NATIVE_POINTER_TO_JAVA);
643663
}
644-
if (nativeToJavaFunction == null) {
664+
return call_native_conversion(nativePointerToJavaFunction, value);
665+
}
666+
667+
private Object call_native_conversion(TruffleObject target, Object value) {
668+
if (callNativeNode == null) {
645669
CompilerDirectives.transferToInterpreterAndInvalidate();
646-
nativeToJavaFunction = importCAPISymbol(NativeCAPISymbols.FUN_NATIVE_TO_JAVA);
670+
callNativeNode = insert(PCallNativeNode.create());
647671
}
648-
return toJavaNode.execute(callNativeNode.execute(nativeToJavaFunction, new Object[]{value}));
672+
return toJavaNode.execute(callNativeNode.execute(target, new Object[]{value}));
649673
}
650674

651675
public static ToJavaNode create() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/NativeCAPISymbols.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
public abstract class NativeCAPISymbols {
4444

45+
public static final String FUN_NATIVE_POINTER_TO_JAVA = "native_pointer_to_java";
4546
public static final String FUN_NATIVE_TO_JAVA = "native_to_java_exported";
4647
public static final String FUN_PY_TRUFFLE_STRING_TO_CSTR = "PyTruffle_StringToCstr";
4748
public static final String FUN_PY_OBJECT_HANDLE_FOR_JAVA_OBJECT = "PyObjectHandle_ForJavaObject";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/PySequenceArrayWrapperMR.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.ToNativeArrayNodeGen;
5454
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.ToNativeStorageNodeGen;
5555
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.WriteArrayItemNodeGen;
56+
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
57+
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetSequenceStorageNode;
5658
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
5759
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode;
5860
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.NormalizeIndexNode;
@@ -85,6 +87,7 @@
8587
import com.oracle.truffle.api.interop.Resolve;
8688
import com.oracle.truffle.api.interop.TruffleObject;
8789
import com.oracle.truffle.api.interop.UnsupportedMessageException;
90+
import com.oracle.truffle.api.nodes.ExplodeLoop;
8891
import com.oracle.truffle.api.nodes.Node;
8992
import com.oracle.truffle.api.profiles.ConditionProfile;
9093
import com.oracle.truffle.api.profiles.ValueProfile;
@@ -235,20 +238,32 @@ public static ReadArrayItemNode create() {
235238
abstract static class WriteArrayItemNode extends Node {
236239
@Child private CExtNodes.ToJavaNode toJavaNode;
237240
@Child private LookupAndCallTernaryNode setItemNode;
241+
@Child private SequenceNodes.GetSequenceStorageNode getSequenceStorageNode;
242+
@Child private SequenceStorageNodes.SetItemNode setByteItemNode;
238243

239244
public abstract Object execute(Object arrayObject, Object idx, Object value);
240245

241246
@Specialization
242-
Object doBytes(PBytes s, long idx, byte value,
243-
@Cached("createSetItem()") SequenceStorageNodes.SetItemNode setBytesItemNode) {
244-
setBytesItemNode.executeLong(s.getSequenceStorage(), idx, value);
247+
Object doBytes(PIBytesLike s, long idx, byte value) {
248+
getSetByteItemNode().executeLong(getSequenceStorage(s), idx, value);
245249
return value;
246250
}
247251

248252
@Specialization
249-
Object doByteArray(PByteArray s, long idx, byte value,
250-
@Cached("createSetItem()") SequenceStorageNodes.SetItemNode setByteArrayItemNode) {
251-
setByteArrayItemNode.executeLong(s.getSequenceStorage(), idx, value);
253+
@ExplodeLoop
254+
Object doBytes(PIBytesLike s, long idx, int value) {
255+
for (int offset = 0; offset < Integer.BYTES; offset++) {
256+
getSetByteItemNode().executeLong(getSequenceStorage(s), idx + offset, (byte) (value >> (8 * offset)) & 0xFF);
257+
}
258+
return value;
259+
}
260+
261+
@Specialization
262+
@ExplodeLoop
263+
Object doBytes(PIBytesLike s, long idx, long value) {
264+
for (int offset = 0; offset < Long.BYTES; offset++) {
265+
getSetByteItemNode().executeLong(getSequenceStorage(s), idx + offset, (byte) (value >> (8 * offset)) & 0xFF);
266+
}
252267
return value;
253268
}
254269

@@ -293,6 +308,22 @@ private CExtNodes.ToJavaNode getToJavaNode() {
293308
return toJavaNode;
294309
}
295310

311+
private SequenceStorage getSequenceStorage(PIBytesLike seq) {
312+
if (getSequenceStorageNode == null) {
313+
CompilerDirectives.transferToInterpreterAndInvalidate();
314+
getSequenceStorageNode = insert(GetSequenceStorageNode.create());
315+
}
316+
return getSequenceStorageNode.execute(seq);
317+
}
318+
319+
private SequenceStorageNodes.SetItemNode getSetByteItemNode() {
320+
if (setByteItemNode == null) {
321+
CompilerDirectives.transferToInterpreterAndInvalidate();
322+
setByteItemNode = insert(createSetItem());
323+
}
324+
return setByteItemNode;
325+
}
326+
296327
private LookupAndCallTernaryNode setItemNode() {
297328
if (setItemNode == null) {
298329
CompilerDirectives.transferToInterpreterAndInvalidate();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceNodes.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,19 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.common;
4242

43+
import com.oracle.graal.python.builtins.objects.common.SequenceNodesFactory.GetSequenceStorageNodeGen;
4344
import com.oracle.graal.python.builtins.objects.common.SequenceNodesFactory.LenNodeGen;
4445
import com.oracle.graal.python.builtins.objects.range.PRange;
4546
import com.oracle.graal.python.builtins.objects.str.PString;
4647
import com.oracle.graal.python.nodes.PGuards;
4748
import com.oracle.graal.python.nodes.PNodeWithContext;
4849
import com.oracle.graal.python.runtime.sequence.PSequence;
50+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
51+
import com.oracle.truffle.api.CompilerDirectives;
4952
import com.oracle.truffle.api.dsl.Cached;
5053
import com.oracle.truffle.api.dsl.ImportStatic;
5154
import com.oracle.truffle.api.dsl.Specialization;
55+
import com.oracle.truffle.api.nodes.Node;
5256
import com.oracle.truffle.api.profiles.ValueProfile;
5357

5458
public abstract class SequenceNodes {
@@ -80,4 +84,19 @@ public static LenNode create() {
8084
}
8185
}
8286

87+
public abstract static class GetSequenceStorageNode extends Node {
88+
89+
public abstract SequenceStorage execute(Object seq);
90+
91+
@Specialization(guards = {"seq.getClass() == cachedClass"})
92+
SequenceStorage doWithStorage(PSequence seq,
93+
@Cached("seq.getClass()") Class<? extends PSequence> cachedClass) {
94+
return CompilerDirectives.castExact(seq, cachedClass).getSequenceStorage();
95+
}
96+
97+
public static GetSequenceStorageNode create() {
98+
return GetSequenceStorageNodeGen.create();
99+
}
100+
}
101+
83102
}

0 commit comments

Comments
 (0)