Skip to content

Commit b1daaf0

Browse files
committed
[GR-10719] Progress towards Cython modules
PullRequest: graalpython/112
2 parents 34f99e7 + 648693e commit b1daaf0

File tree

14 files changed

+155
-37
lines changed

14 files changed

+155
-37
lines changed

ci.jsonnet

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@
124124

125125
local labsjdk8Mixin = {
126126
downloads +: {
127-
JAVA_HOME: utils.download("labsjdk", "8u161-jvmci-0.42"),
128-
EXTRA_JAVA_HOMES : { pathlist: [utils.download("oraclejdk", "9.0.4+11")] },
127+
JAVA_HOME: utils.download("labsjdk", "8u172-jvmci-0.46"),
128+
EXTRA_JAVA_HOMES : { pathlist: [utils.download("oraclejdk", "11+20")] },
129129
},
130130
environment +: {
131131
CI: "true",

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#define HAVE_SYS_WAIT_H
4747

4848
#define PYPY_VERSION 0
49+
#define PYPY_VERSION_NUM 0
4950

5051
#include <truffle.h>
5152
#include <polyglot.h>
@@ -113,6 +114,7 @@
113114
#include "frameobject.h"
114115
#include "traceback.h"
115116
#include "classobject.h"
117+
#include "pythread.h"
116118

117119
#define PY_TRUFFLE_CEXT ((void*)polyglot_import("python_cext"))
118120
#define PY_BUILTIN ((void*)polyglot_import("python_builtins"))

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,14 @@ int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
4747
PyObject* PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs) {
4848
return PyObject_Call(func, args, kwargs);
4949
}
50+
51+
PyThreadState* PyEval_SaveThread() {
52+
return NULL;
53+
}
54+
55+
void PyEval_RestoreThread(PyThreadState *ptr) {
56+
}
57+
58+
void* PyThread_allocate_lock() {
59+
return NULL;
60+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,15 @@ double PyFloat_AsDouble(PyObject *op) {
6262
PyObject* PyFloat_FromDouble(double fval) {
6363
return UPCALL_CEXT_O("PyFloat_FromDouble", fval);
6464
}
65+
66+
// not quite as in CPython, this assumes that x is already a double. The rest of
67+
// the implementation is in the Float constructor in Java
68+
PyObject* float_subtype_new(PyTypeObject *type, double x) {
69+
PyObject* newobj = type->tp_alloc(type, 0);
70+
if (newobj == NULL) {
71+
Py_DECREF(tmp);
72+
return NULL;
73+
}
74+
((PyFloatObject *)newobj)->ob_fval = x;
75+
return newobj;
76+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@
3737
* SOFTWARE.
3838
*/
3939
#include "capi.h"
40+
41+
PyObject* PyClassMethod_New(PyObject* method) {
42+
return UPCALL_O(PY_BUILTIN, "classmethod", native_to_java(method));
43+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
4242

4343
PyTypeObject PyCFunction_Type = PY_TRUFFLE_TYPE("builtin_function_or_method", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyCFunctionObject));
44+
PyTypeObject PyWrapperDescr_Type = PY_TRUFFLE_TYPE("builtin_function_or_method", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyWrapperDescr_Type));;
4445

4546
PyObject* PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
4647
PyObject* func = to_sulong(polyglot_invoke(PY_TRUFFLE_CEXT,

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

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
6767
import com.oracle.graal.python.builtins.objects.bytes.PIBytesLike;
6868
import com.oracle.graal.python.builtins.objects.cell.PCell;
69+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes;
70+
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
6971
import com.oracle.graal.python.builtins.objects.code.PCode;
7072
import com.oracle.graal.python.builtins.objects.common.HashingStorage.DictEntry;
7173
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes;
@@ -128,6 +130,7 @@
128130
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
129131
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
130132
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
133+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
131134
import com.oracle.graal.python.nodes.control.GetIteratorNode;
132135
import com.oracle.graal.python.nodes.control.GetNextNode;
133136
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -426,51 +429,55 @@ public Object reversed(PythonClass cls, Object sequence,
426429
public abstract static class FloatNode extends PythonBuiltinNode {
427430
private final ConditionProfile isPrimitiveProfile = ConditionProfile.createBinaryProfile();
428431

429-
private boolean isPrimitiveFloat(Object cls) {
430-
return isPrimitiveProfile.profile(cls == getCore().lookupType(PythonBuiltinClassType.PFloat));
432+
protected boolean isPrimitiveFloat(Object cls) {
433+
return isPrimitiveProfile.profile(cls == getBuiltinFloatClass());
431434
}
432435

433-
@Specialization
436+
protected PythonBuiltinClass getBuiltinFloatClass() {
437+
return getCore().lookupType(PythonBuiltinClassType.PFloat);
438+
}
439+
440+
@Specialization(guards = "!isNativeClass(cls)")
434441
public Object floatFromInt(PythonClass cls, int arg) {
435442
if (isPrimitiveFloat(cls)) {
436443
return (double) arg;
437444
}
438445
return factory().createFloat(cls, arg);
439446
}
440447

441-
@Specialization
448+
@Specialization(guards = "!isNativeClass(cls)")
442449
public Object floatFromBoolean(PythonClass cls, boolean arg) {
443450
if (isPrimitiveFloat(cls)) {
444451
return arg ? 1d : 0d;
445452
}
446453
return factory().createFloat(cls, arg ? 1d : 0d);
447454
}
448455

449-
@Specialization
456+
@Specialization(guards = "!isNativeClass(cls)")
450457
public Object floatFromLong(PythonClass cls, long arg) {
451458
if (isPrimitiveFloat(cls)) {
452459
return (double) arg;
453460
}
454461
return factory().createFloat(cls, arg);
455462
}
456463

457-
@Specialization
464+
@Specialization(guards = "!isNativeClass(cls)")
458465
public Object floatFromPInt(PythonClass cls, PInt arg) {
459466
if (isPrimitiveFloat(cls)) {
460467
return arg.doubleValue();
461468
}
462469
return factory().createFloat(cls, arg.doubleValue());
463470
}
464471

465-
@Specialization
472+
@Specialization(guards = "!isNativeClass(cls)")
466473
public Object floatFromFloat(PythonClass cls, double arg) {
467474
if (isPrimitiveFloat(cls)) {
468475
return arg;
469476
}
470477
return factory().createFloat(cls, arg);
471478
}
472479

473-
@Specialization
480+
@Specialization(guards = "!isNativeClass(cls)")
474481
public Object floatFromString(PythonClass cls, String arg) {
475482
double value = JavaTypeConversions.convertStringToDouble(arg);
476483
if (isPrimitiveFloat(cls)) {
@@ -479,34 +486,59 @@ public Object floatFromString(PythonClass cls, String arg) {
479486
return factory().createFloat(cls, value);
480487
}
481488

482-
@Specialization
489+
@Specialization(guards = "!isNativeClass(cls)")
483490
public Object floatFromNone(PythonClass cls, @SuppressWarnings("unused") PNone arg) {
484491
if (isPrimitiveFloat(cls)) {
485492
return 0.0;
486493
}
487494
return factory().createFloat(cls, 0.0);
488495
}
489496

490-
@Specialization
491-
Object doPythonObject(PythonClass cls, Object obj,
497+
@Specialization(guards = "isPrimitiveFloat(cls)")
498+
double doubleFromObject(@SuppressWarnings("unused") PythonClass cls, Object obj,
492499
@Cached("create(__FLOAT__)") LookupAndCallUnaryNode callFloatNode,
493500
@Cached("create()") BranchProfile gotException) {
494501
try {
495-
return floatFromFloat(cls, callFloatNode.executeDouble(obj));
502+
return callFloatNode.executeDouble(obj);
496503
} catch (UnexpectedResultException e) {
497504
gotException.enter();
498505
Object result = e.getResult();
499506
if (result == PNone.NO_VALUE) {
500507
throw raise(TypeError, "must be real number, not %p", obj);
501-
} else if (PGuards.isPFloat(result)) {
508+
} else if (result instanceof PFloat) {
502509
// TODO Issue warning if 'result' is a subclass of Python type 'float'
503-
return result;
510+
return ((PFloat) result).getValue();
504511
} else {
505512
throw raise(TypeError, "%p.__float__ returned non-float (type %p)", obj, result);
506513
}
507514
}
508515
}
509516

517+
@Specialization(guards = "!isNativeClass(cls)")
518+
Object doPythonObject(PythonClass cls, Object obj,
519+
@Cached("create(__FLOAT__)") LookupAndCallUnaryNode callFloatNode,
520+
@Cached("create()") BranchProfile gotException) {
521+
return floatFromFloat(cls, doubleFromObject(cls, obj, callFloatNode, gotException));
522+
}
523+
524+
protected CExtNodes.SubtypeNew createSubtypeNew() {
525+
return new CExtNodes.SubtypeNew("float");
526+
}
527+
528+
// logic similar to float_subtype_new(PyTypeObject *type, PyObject *x) from CPython
529+
// floatobject.c we have to first create a temporary float, then fill it into
530+
// a natively allocated subtype structure
531+
@Specialization(guards = "isSubtype.execute(cls, floatCls)", limit = "1")
532+
Object doPythonObject(PythonNativeClass cls, Object obj,
533+
@Cached("getBuiltinFloatClass()") PythonBuiltinClass floatCls,
534+
@SuppressWarnings("unused") @Cached("create()") IsSubtypeNode isSubtype,
535+
@Cached("create(__FLOAT__)") LookupAndCallUnaryNode callFloatNode,
536+
@Cached("create()") BranchProfile gotException,
537+
@Cached("createSubtypeNew()") CExtNodes.SubtypeNew subtypeNew) {
538+
double realFloat = doubleFromObject(floatCls, obj, callFloatNode, gotException);
539+
return subtypeNew.execute(cls, realFloat);
540+
}
541+
510542
@Fallback
511543
@TruffleBoundary
512544
public Object floatFromObject(@SuppressWarnings("unused") Object cls, Object arg) {

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,35 @@
7575

7676
public abstract class CExtNodes {
7777

78+
/**
79+
* For some builtin classes, the CPython approach to creating a subclass instance is to just
80+
* call the alloc function and then assign some fields. This needs to be done in C. This node
81+
* will call that subtype C function with two arguments, the C type object and an object
82+
* argument to fill in from.
83+
*/
84+
public static class SubtypeNew extends PBaseNode {
85+
private final TruffleObject subtypeFunc;
86+
@Child private Node executeNode = Message.createExecute(2).createNode();
87+
@Child private ToSulongNode toSulongNode = ToSulongNode.create();
88+
@Child private ToJavaNode toJavaNode = ToJavaNode.create();
89+
90+
/**
91+
* @param typenamePrefix the <code>typename</code> in <code>typename_subtype_new</code>
92+
*/
93+
public SubtypeNew(String typenamePrefix) {
94+
subtypeFunc = (TruffleObject) getContext().getEnv().importSymbol(typenamePrefix + "_subtype_new");
95+
assert subtypeFunc != null;
96+
}
97+
98+
public Object execute(PythonNativeClass object, Object arg) {
99+
try {
100+
return toJavaNode.execute(ForeignAccess.sendExecute(executeNode, subtypeFunc, toSulongNode.execute(object), arg));
101+
} catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) {
102+
throw new IllegalStateException("C subtype_new function failed", e);
103+
}
104+
}
105+
}
106+
78107
public static class FromNativeSubclassNode extends PBaseNode {
79108
private final PythonBuiltinClassType expectedType;
80109
private final String conversionFuncName;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
4343
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
4444
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
45+
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
4546
import com.oracle.graal.python.builtins.objects.dict.PDict;
4647
import com.oracle.graal.python.builtins.objects.floats.PFloat;
4748
import com.oracle.graal.python.builtins.objects.function.PArguments;
@@ -259,6 +260,10 @@ public static boolean isPythonBuiltinClass(Object klass) {
259260
return klass instanceof PythonBuiltinClass;
260261
}
261262

263+
public static boolean isNativeClass(Object klass) {
264+
return klass instanceof PythonNativeClass;
265+
}
266+
262267
public static boolean isPRange(Object obj) {
263268
return obj instanceof PRange;
264269
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromObjectNode.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import com.oracle.graal.python.builtins.objects.PNone;
4242
import com.oracle.graal.python.builtins.objects.object.PythonObject;
43+
import com.oracle.graal.python.builtins.objects.str.PString;
4344
import com.oracle.graal.python.nodes.PNode;
4445
import com.oracle.truffle.api.Assumption;
4546
import com.oracle.truffle.api.CompilerDirectives;
@@ -85,6 +86,14 @@ protected static boolean checkShape(@SuppressWarnings("unused") PythonObject obj
8586
return cachedObject.getStorage().getShape() == cachedShape;
8687
}
8788

89+
protected Object attrKey(Object key) {
90+
if (key instanceof PString) {
91+
return ((PString) key).getValue();
92+
} else {
93+
return key;
94+
}
95+
}
96+
8897
@SuppressWarnings("unused")
8998
@Specialization(limit = "1", //
9099
guards = {
@@ -101,12 +110,13 @@ protected static boolean checkShape(@SuppressWarnings("unused") PythonObject obj
101110
protected Object readDirectFinal(PythonObject object, Object key,
102111
@Cached("object") PythonObject cachedObject,
103112
@Cached("key") Object cachedKey,
113+
@Cached("attrKey(key)") Object attrKey,
104114
@Cached("object.getStorage().getShape()") Shape cachedShape,
105115
@Cached("cachedShape.getValidAssumption()") Assumption layoutAssumption,
106-
@Cached("getLocationOrNull(cachedShape.getProperty(key))") Location loc,
116+
@Cached("getLocationOrNull(cachedShape.getProperty(attrKey))") Location loc,
107117
@Cached("loc.getFinalAssumption()") Assumption finalAssumption,
108118
@Cached("readFinalValue(object, loc)") Object cachedValue) {
109-
assert assertFinal(object, key, cachedValue);
119+
assert assertFinal(object, attrKey, cachedValue);
110120
return cachedValue;
111121
}
112122

@@ -125,9 +135,10 @@ private static boolean assertFinal(PythonObject object, Object key, Object cache
125135
assumptions = "layoutAssumption")
126136
protected Object readDirect(PythonObject object, Object key,
127137
@Cached("key") Object cachedKey,
138+
@Cached("attrKey(cachedKey)") Object attrKey,
128139
@Cached("object.getStorage().getShape()") Shape cachedShape,
129140
@Cached("cachedShape.getValidAssumption()") Assumption layoutAssumption,
130-
@Cached("getLocationOrNull(cachedShape.getProperty(key))") Location loc) {
141+
@Cached("getLocationOrNull(cachedShape.getProperty(attrKey))") Location loc) {
131142
if (loc == null) {
132143
return PNone.NO_VALUE;
133144
} else {
@@ -151,7 +162,7 @@ protected Object updateShapeAndRead(PythonObject object, Object key,
151162

152163
@Specialization(replaces = "readDirect")
153164
protected Object readIndirect(PythonObject object, Object key) {
154-
Object value = object.getStorage().get(key);
165+
Object value = object.getStorage().get(attrKey(key));
155166
if (value == null) {
156167
return PNone.NO_VALUE;
157168
} else {
@@ -163,7 +174,7 @@ protected Object readIndirect(PythonObject object, Object key) {
163174
protected Object readForeign(TruffleObject object, Object key,
164175
@Cached("createReadNode()") Node readNode) {
165176
try {
166-
return ForeignAccess.sendRead(readNode, object, key);
177+
return ForeignAccess.sendRead(readNode, object, attrKey(key));
167178
} catch (UnknownIdentifierException | UnsupportedMessageException e) {
168179
return PNone.NO_VALUE;
169180
}

0 commit comments

Comments
 (0)