Skip to content

Commit f8ae3fe

Browse files
committed
[GR-16481] Use polyglot casts to convert boxed primitives to C primitives.
PullRequest: graalpython/543
2 parents 66f8db2 + f1017f5 commit f8ae3fe

File tree

7 files changed

+91
-42
lines changed

7 files changed

+91
-42
lines changed

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ void *Py_NoValue;
4646

4747

4848
PyObject*(*PY_TRUFFLE_LANDING)(void *rcv, void* name, ...);
49-
PyObject*(*PY_TRUFFLE_LANDING_L)(void *rcv, void* name, ...);
50-
PyObject*(*PY_TRUFFLE_LANDING_D)(void *rcv, void* name, ...);
49+
uint64_t(*PY_TRUFFLE_LANDING_L)(void *rcv, void* name, ...);
50+
double(*PY_TRUFFLE_LANDING_D)(void *rcv, void* name, ...);
5151
void*(*PY_TRUFFLE_LANDING_PTR)(void *rcv, void* name, ...);
5252
PyObject*(*PY_TRUFFLE_CEXT_LANDING)(void* name, ...);
5353
uint64_t (*PY_TRUFFLE_CEXT_LANDING_L)(void* name, ...);
@@ -63,8 +63,8 @@ static void initialize_upcall_functions() {
6363
PY_BUILTIN = (void*)polyglot_eval("python", "import builtins\nbuiltins");
6464

6565
PY_TRUFFLE_LANDING = ((PyObject*(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall", SRC_CS)));
66-
PY_TRUFFLE_LANDING_L = ((PyObject*(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall_l", SRC_CS)));
67-
PY_TRUFFLE_LANDING_D = ((PyObject*(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall_d", SRC_CS)));
66+
PY_TRUFFLE_LANDING_L = ((uint64_t(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall_l", SRC_CS)));
67+
PY_TRUFFLE_LANDING_D = ((double(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall_d", SRC_CS)));
6868
PY_TRUFFLE_LANDING_PTR = ((void*(*)(void *rcv, void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Upcall_ptr", SRC_CS)));
6969
PY_TRUFFLE_CEXT_LANDING = ((PyObject*(*)(void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Cext_Upcall", SRC_CS)));
7070
PY_TRUFFLE_CEXT_LANDING_L = ((uint64_t (*)(void* name, ...))polyglot_get_member(PY_TRUFFLE_CEXT, polyglot_from_string("PyTruffle_Cext_Upcall_l", SRC_CS)));
@@ -364,7 +364,10 @@ const char* PyTruffle_StringToCstr(void* o, int32_t strLen) {
364364
return str;
365365
}
366366

367-
const char* PyTruffle_CstrToString(const char* o) {
367+
void* PyTruffle_CstrToString(void* o) {
368+
if (polyglot_fits_in_i64(o)) {
369+
return polyglot_from_string((const char*)polyglot_as_i64(o), SRC_CS);
370+
}
368371
return polyglot_from_string(o, SRC_CS);
369372
}
370373

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

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,31 @@ extern void *Py_NoValue;
8484
extern init_upcall upcalls[];
8585
extern unsigned init_upcall_n;
8686

87+
/* upcall helpers */
88+
MUST_INLINE
89+
PyObject* polyglot_ensure_ptr(void *obj) {
90+
return polyglot_fits_in_i64(obj) ? (PyObject*) polyglot_as_i64(obj) : (PyObject*) obj;
91+
}
92+
93+
MUST_INLINE
94+
int32_t polyglot_ensure_i32(void *obj) {
95+
return polyglot_fits_in_i32(obj) ? polyglot_as_i32(obj) : (int32_t) obj;
96+
}
97+
98+
MUST_INLINE
99+
int64_t polyglot_ensure_i64(void *obj) {
100+
return polyglot_fits_in_i64(obj) ? polyglot_as_i64(obj) : (int64_t) obj;
101+
}
102+
103+
MUST_INLINE
104+
double polyglot_ensure_double(void *obj) {
105+
return polyglot_fits_in_double(obj) ? polyglot_as_double(obj) : (double) ((int64_t)obj);
106+
}
107+
87108
/* upcall functions for calling into Python */
88109
extern PyObject*(*PY_TRUFFLE_LANDING)(void *rcv, void* name, ...);
89-
extern PyObject*(*PY_TRUFFLE_LANDING_L)(void *rcv, void* name, ...);
90-
extern PyObject*(*PY_TRUFFLE_LANDING_D)(void *rcv, void* name, ...);
110+
extern uint64_t(*PY_TRUFFLE_LANDING_L)(void *rcv, void* name, ...);
111+
extern double(*PY_TRUFFLE_LANDING_D)(void *rcv, void* name, ...);
91112
extern void*(*PY_TRUFFLE_LANDING_PTR)(void *rcv, void* name, ...);
92113
extern PyObject*(*PY_TRUFFLE_CEXT_LANDING)(void* name, ...);
93114
extern uint64_t (*PY_TRUFFLE_CEXT_LANDING_L)(void* name, ...);
@@ -101,16 +122,16 @@ extern void* (*PY_TRUFFLE_CEXT_LANDING_PTR)(void* name, ...);
101122
#define UPCALL_P(__recv__, __name__, ...) (PY_TRUFFLE_LANDING_L((__recv__), __name__, ##__VA_ARGS__))
102123

103124
/* Call function with return type 'int'; no polyglot cast but error handling */
104-
#define UPCALL_I(__recv__, __name__, ...) UPCALL_P(__recv__, __name__, ##__VA_ARGS__)
125+
#define UPCALL_I(__recv__, __name__, ...) (polyglot_ensure_i32(UPCALL_P(__recv__, __name__, ##__VA_ARGS__)))
105126

106127
/* Call function with return type 'long'; no polyglot cast but error handling */
107-
#define UPCALL_L(__recv__, __name__, ...) UPCALL_P(__recv__, __name__, ##__VA_ARGS__)
128+
#define UPCALL_L(__recv__, __name__, ...) (polyglot_ensure_i64(UPCALL_P(__recv__, __name__, ##__VA_ARGS__)))
108129

109130
/* Call function with return type 'double'; no polyglot cast but error handling */
110-
#define UPCALL_D(__recv__, __name__, ...) PY_TRUFFLE_LANDING_D((__recv__), __name__, ##__VA_ARGS__)
131+
#define UPCALL_D(__recv__, __name__, ...) (polyglot_ensure_double(PY_TRUFFLE_LANDING_D((__recv__), __name__, ##__VA_ARGS__)))
111132

112133
/* Call function with return type 'void*'; no polyglot cast and no error handling */
113-
#define UPCALL_PTR(__name__, ...) (PY_TRUFFLE_LANDING_PTR(__name__, ##__VA_ARGS__))
134+
#define UPCALL_PTR(__name__, ...) (polyglot_ensure_ptr(PY_TRUFFLE_LANDING_PTR(__name__, ##__VA_ARGS__)))
114135

115136
/* Call function of 'python_cext' module with return type 'PyObject *'; does polyglot cast and error handling */
116137
#define UPCALL_CEXT_O(__name__, ...) PY_TRUFFLE_CEXT_LANDING(__name__, ##__VA_ARGS__)
@@ -122,19 +143,19 @@ extern void* (*PY_TRUFFLE_CEXT_LANDING_PTR)(void* name, ...);
122143
#define UPCALL_CEXT_NOCAST(__name__, ...) PY_TRUFFLE_CEXT_LANDING(__name__, ##__VA_ARGS__)
123144

124145
/* Call function of 'python_cext' module with return type 'void*'; no polyglot cast and no error handling */
125-
#define UPCALL_CEXT_PTR(__name__, ...) (PY_TRUFFLE_CEXT_LANDING_PTR(__name__, ##__VA_ARGS__))
146+
#define UPCALL_CEXT_PTR(__name__, ...) (polyglot_ensure_ptr(PY_TRUFFLE_CEXT_LANDING_PTR(__name__, ##__VA_ARGS__)))
126147

127148
/* Call function of 'python_cext' module with a primitive return; no polyglot cast but error handling */
128149
#define UPCALL_CEXT_P(__name__, ...) (PY_TRUFFLE_CEXT_LANDING_L(__name__, ##__VA_ARGS__))
129150

130151
/* Call function of 'python_cext' module with return type 'int'; no polyglot cast but error handling */
131-
#define UPCALL_CEXT_I(__name__, ...) UPCALL_CEXT_P(__name__, ##__VA_ARGS__)
152+
#define UPCALL_CEXT_I(__name__, ...) (polyglot_ensure_i32(UPCALL_CEXT_P(__name__, ##__VA_ARGS__)))
132153

133154
/* Call function of 'python_cext' module with return type 'long'; no polyglot cast but error handling */
134-
#define UPCALL_CEXT_L(__name__, ...) UPCALL_CEXT_P(__name__, ##__VA_ARGS__)
155+
#define UPCALL_CEXT_L(__name__, ...) (polyglot_ensure_i64(UPCALL_CEXT_P(__name__, ##__VA_ARGS__)))
135156

136157
/* Call function of 'python_cext' module with return type 'double'; no polyglot cast but error handling */
137-
#define UPCALL_CEXT_D(__name__, ...) (PY_TRUFFLE_CEXT_LANDING_D(__name__, ##__VA_ARGS__))
158+
#define UPCALL_CEXT_D(__name__, ...) (polyglot_ensure_double(PY_TRUFFLE_CEXT_LANDING_D(__name__, ##__VA_ARGS__)))
138159

139160
#define UPCALL_ID(name) \
140161
static void* _jls_ ## name; \

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

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,8 @@ typedef struct _build_stack {
533533
PyObject* _Py_BuildValue_SizeT(const char *format, ...) {
534534
# define ARG polyglot_get_arg(value_idx)
535535
# define APPEND_VALUE(list, value) PyList_Append(list, value); value_idx++
536+
# define AS_I64(__arg__) (polyglot_fits_in_i64((__arg__)) ? polyglot_as_i64((__arg__)) : ((int64_t)(__arg__)))
537+
# define AS_DOUBLE(__arg__) (polyglot_fits_in_double((__arg__)) ? polyglot_as_double((__arg__)) : ((double)(unsigned long long)(__arg__)))
536538

537539
PyObject* (*converter)(void*) = NULL;
538540
char argchar[2] = {'\0'};
@@ -551,7 +553,7 @@ PyObject* _Py_BuildValue_SizeT(const char *format, ...) {
551553
case 'z':
552554
case 'U':
553555
if (format[format_idx + 1] == '#') {
554-
int size = (int)polyglot_get_arg(value_idx + 1);
556+
int size = (int) AS_I64(polyglot_get_arg(value_idx + 1));
555557
if (ARG == NULL) {
556558
APPEND_VALUE(list, Py_None);
557559
} else {
@@ -569,7 +571,7 @@ PyObject* _Py_BuildValue_SizeT(const char *format, ...) {
569571
break;
570572
case 'y':
571573
if (format[format_idx + 1] == '#') {
572-
int size = (int)polyglot_get_arg(value_idx + 1);
574+
int size = (int) AS_I64(polyglot_get_arg(value_idx + 1));
573575
if (ARG == NULL) {
574576
APPEND_VALUE(list, Py_None);
575577
} else {
@@ -591,39 +593,39 @@ PyObject* _Py_BuildValue_SizeT(const char *format, ...) {
591593
case 'i':
592594
case 'b':
593595
case 'h':
594-
APPEND_VALUE(list, PyLong_FromLong((int)ARG));
596+
APPEND_VALUE(list, PyLong_FromLong((int)AS_I64(ARG)));
595597
break;
596598
case 'l':
597-
APPEND_VALUE(list, PyLong_FromLong((long)ARG));
599+
APPEND_VALUE(list, PyLong_FromLong(AS_I64(ARG)));
598600
break;
599601
case 'B':
600602
case 'H':
601603
case 'I':
602-
APPEND_VALUE(list, PyLong_FromUnsignedLong((unsigned int)ARG));
604+
APPEND_VALUE(list, PyLong_FromUnsignedLong((unsigned int)AS_I64(ARG)));
603605
break;
604606
case 'k':
605-
APPEND_VALUE(list, PyLong_FromUnsignedLong((unsigned long)ARG));
607+
APPEND_VALUE(list, PyLong_FromUnsignedLong((unsigned long)AS_I64(ARG)));
606608
break;
607609
case 'L':
608-
APPEND_VALUE(list, PyLong_FromLongLong((long long)ARG));
610+
APPEND_VALUE(list, PyLong_FromLongLong((long long)AS_I64(ARG)));
609611
break;
610612
case 'K':
611-
APPEND_VALUE(list, PyLong_FromLongLong((unsigned long long)ARG));
613+
APPEND_VALUE(list, PyLong_FromLongLong((unsigned long long)AS_I64(ARG)));
612614
break;
613615
case 'n':
614-
APPEND_VALUE(list, PyLong_FromSsize_t((Py_ssize_t)ARG));
616+
APPEND_VALUE(list, PyLong_FromSsize_t((Py_ssize_t)AS_I64(ARG)));
615617
break;
616618
case 'c':
617-
argchar[0] = (char)ARG;
619+
argchar[0] = (char)AS_I64(ARG);
618620
APPEND_VALUE(list, PyBytes_FromStringAndSize(argchar, 1));
619621
break;
620622
case 'C':
621-
argchar[0] = (char)ARG;
623+
argchar[0] = (char)AS_I64(ARG);
622624
APPEND_VALUE(list, polyglot_from_string(argchar, "ascii"));
623625
break;
624626
case 'd':
625627
case 'f':
626-
APPEND_VALUE(list, PyFloat_FromDouble((double)(unsigned long long)ARG));
628+
APPEND_VALUE(list, PyFloat_FromDouble((double)AS_DOUBLE(ARG)));
627629
break;
628630
case 'D':
629631
fprintf(stderr, "error: unsupported format 'D'\n");

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_bytes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -80,7 +80,7 @@ def compile_module(self, name):
8080
test_PyBytes_FromStringAndSizeNULL = CPyExtFunction(
8181
lambda args: len(b"\x00"*args[0]),
8282
lambda: ( (128, ), ),
83-
code = """PyObject* PyBytes_FromStringAndSizeNULL(Py_ssize_t n) {
83+
code = """Py_ssize_t PyBytes_FromStringAndSizeNULL(Py_ssize_t n) {
8484
// we are return the length because the content is random (uninitialized)
8585
return PyBytes_Size(PyBytes_FromStringAndSize(NULL, n));
8686
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,8 @@ public abstract static class PKeyInfoNode extends Node {
567567

568568
@Specialization
569569
int access(Object object, String fieldName,
570-
@Cached ReadAttributeFromObjectNode readNode,
570+
@Cached("createForceType()") ReadAttributeFromObjectNode readTypeAttrNode,
571+
@Cached ReadAttributeFromObjectNode readObjectAttrNode,
571572
@Cached IsCallableNode isCallableNode,
572573
@Cached LookupInheritedAttributeNode.Dynamic getGetNode,
573574
@Cached LookupInheritedAttributeNode.Dynamic getSetNode,
@@ -596,15 +597,17 @@ int access(Object object, String fieldName,
596597
}
597598

598599
for (PythonAbstractClass c : getMroNode.execute(klass)) {
599-
attr = readNode.execute(c, attrKeyName);
600+
// n.b. we need to use a different node because it makes a difference if the type is
601+
// native
602+
attr = readTypeAttrNode.execute(c, attrKeyName);
600603
if (attr != PNone.NO_VALUE) {
601604
owner = c;
602605
break;
603606
}
604607
}
605608

606609
if (attr == PNone.NO_VALUE) {
607-
attr = readNode.execute(owner, attrKeyName);
610+
attr = readObjectAttrNode.execute(owner, attrKeyName);
608611
}
609612

610613
if (attr != PNone.NO_VALUE) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ExecutionContext.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference;
4646
import com.oracle.graal.python.builtins.objects.function.PArguments;
4747
import com.oracle.graal.python.nodes.PRootNode;
48+
import com.oracle.graal.python.nodes.control.TopLevelExceptionHandler;
4849
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode;
4950
import com.oracle.graal.python.nodes.frame.MaterializeFrameNodeGen;
5051
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
@@ -58,6 +59,7 @@
5859
import com.oracle.truffle.api.frame.VirtualFrame;
5960
import com.oracle.truffle.api.nodes.Node;
6061
import com.oracle.truffle.api.profiles.BranchProfile;
62+
import com.oracle.truffle.api.profiles.ConditionProfile;
6163

6264
/**
6365
* An ExecutionContext ensures proper entry and exit for Python calls on both sides of the call, and
@@ -73,6 +75,8 @@ public static final class CallContext extends Node {
7375

7476
private final boolean adoptable;
7577

78+
@CompilationFinal private ConditionProfile isPythonFrameProfile;
79+
7680
private CallContext(boolean adoptable) {
7781
this.adoptable = adoptable;
7882
}
@@ -91,14 +95,20 @@ public void prepareCall(VirtualFrame frame, Object[] callArguments, RootCallTarg
9195
// must only be used when calling from Python to Python
9296
PRootNode calleeRootNode = (PRootNode) callTarget.getRootNode();
9397
if (calleeRootNode.needsCallerFrame()) {
94-
PFrame.Reference thisInfo = PArguments.getCurrentFrameInfo(frame);
95-
96-
// We are handing the PFrame of the current frame to the caller, i.e., it does not
97-
// 'escape' since it is still on the stack.
98-
// Also, force synchronization of values
99-
PFrame pyFrame = materialize(frame, callNode, false, true);
100-
assert thisInfo.getPyFrame() == pyFrame;
101-
assert pyFrame.getRef() == thisInfo;
98+
PFrame.Reference thisInfo;
99+
100+
if (isPythonFrame(frame, callNode)) {
101+
thisInfo = PArguments.getCurrentFrameInfo(frame);
102+
103+
// We are handing the PFrame of the current frame to the caller, i.e., it does
104+
// not 'escape' since it is still on the stack.Also, force synchronization of
105+
// values
106+
PFrame pyFrame = materialize(frame, callNode, false, true);
107+
assert thisInfo.getPyFrame() == pyFrame;
108+
assert pyFrame.getRef() == thisInfo;
109+
} else {
110+
thisInfo = PFrame.Reference.EMPTY;
111+
}
102112

103113
thisInfo.setCallNode(callNode);
104114
PArguments.setCallerFrameInfo(callArguments, thisInfo);
@@ -127,6 +137,16 @@ private PFrame materialize(VirtualFrame frame, Node callNode, boolean markAsEsca
127137
return MaterializeFrameNode.getUnadoptable().execute(frame, callNode, markAsEscaped, forceSync);
128138
}
129139

140+
private boolean isPythonFrame(VirtualFrame frame, Node callNode) {
141+
if (isPythonFrameProfile == null) {
142+
CompilerDirectives.transferToInterpreterAndInvalidate();
143+
isPythonFrameProfile = ConditionProfile.createBinaryProfile();
144+
}
145+
boolean result = isPythonFrameProfile.profile(PArguments.isPythonFrame(frame));
146+
assert result || callNode.getRootNode() instanceof TopLevelExceptionHandler : "calling from non-Python or non-top-level frame";
147+
return result;
148+
}
149+
130150
private MaterializeFrameNode ensureMaterializeNode() {
131151
if (materializeNode == null) {
132152
CompilerDirectives.transferToInterpreterAndInvalidate();

mx.graalpython/suite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@
4444
},
4545
{
4646
"name": "sulong",
47-
"version": "5dc4d8b4f772e90475a00c2093846cf11b2fd480",
47+
"version": "25ca64c37716cdf4679b535fa2207224e8520c2f",
4848
"subdir": True,
4949
"urls": [
5050
{"url": "https://github.com/oracle/graal", "kind": "git"},
5151
]
5252
},
5353
{
5454
"name": "regex",
55-
"version": "5dc4d8b4f772e90475a00c2093846cf11b2fd480",
55+
"version": "25ca64c37716cdf4679b535fa2207224e8520c2f",
5656
"subdir": True,
5757
"urls": [
5858
{"url": "https://github.com/oracle/graal", "kind": "git"},

0 commit comments

Comments
 (0)