Skip to content

Commit b145d84

Browse files
committed
support allocating and filling native subtypes of floats
1 parent 44a2b30 commit b145d84

File tree

4 files changed

+92
-14
lines changed

4 files changed

+92
-14
lines changed

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/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
}

0 commit comments

Comments
 (0)