Skip to content

Commit b14bdc9

Browse files
committed
Intrinsify PyObject_CallMethod/CallMethodObjArgs
1 parent 8bf7d68 commit b14bdc9

File tree

3 files changed

+122
-66
lines changed

3 files changed

+122
-66
lines changed

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

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -244,46 +244,41 @@ PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ...) {
244244
return result;
245245
}
246246

247-
UPCALL_ID(PyObject_CallMethod);
247+
typedef PyObject *(*call_method_t)(PyObject *, void *, void *, int32_t);
248+
UPCALL_TYPED_ID(PyObject_CallMethod, call_method_t);
248249
PyObject* PyObject_CallMethod(PyObject* object, const char* method, const char* fmt, ...) {
249250
PyObject* args;
250251
if (fmt == NULL || fmt[0] == '\0') {
251-
args = Py_None;
252-
} else {
253-
va_list va;
254-
va_start(va, fmt);
255-
args = Py_VaBuildValue(fmt, va);
256-
va_end(va);
252+
return _jls_PyObject_CallMethod(native_to_java(object), polyglot_from_string(method, SRC_CS), NULL, 0);
257253
}
258-
return UPCALL_CEXT_O(_jls_PyObject_CallMethod, native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args));
254+
va_list va;
255+
va_start(va, fmt);
256+
args = Py_VaBuildValue(fmt, va);
257+
va_end(va);
258+
return _jls_PyObject_CallMethod(native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args), IS_SINGLE_ARG(fmt));
259259
}
260260

261+
typedef PyObject *(*call_meth_obj_args_t)(PyObject *, void *, void *);
262+
UPCALL_TYPED_ID(PyObject_CallMethodObjArgs, call_meth_obj_args_t);
261263
PyObject* PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) {
262264
va_list vargs;
263265
va_start(vargs, name);
264266
// the arguments are given as a variable list followed by NULL
265-
int argc = polyglot_get_array_size(vargs) - 1;
266-
PyObject* args = PyTuple_New(argc);
267-
for (int i = 0; i < argc; i++) {
268-
PyObject *arg = va_arg(vargs, PyObject*);
269-
Py_INCREF(arg);
270-
PyTuple_SetItem(args, i, arg);
271-
}
267+
PyObject *result = _jls_PyObject_CallMethodObjArgs(native_to_java(callable), native_to_java(name), &vargs);
272268
va_end(vargs);
273-
return UPCALL_CEXT_O(_jls_PyObject_CallMethod, native_to_java(callable), native_to_java(name), native_to_java(args));
269+
return result;
274270
}
275271

276272
PyObject* _PyObject_CallMethod_SizeT(PyObject* object, const char* method, const char* fmt, ...) {
277273
PyObject* args;
278274
if (fmt == NULL || fmt[0] == '\0') {
279-
args = Py_None;
280-
} else {
281-
va_list va;
282-
va_start(va, fmt);
283-
args = Py_VaBuildValue(fmt, va);
284-
va_end(va);
275+
return _jls_PyObject_CallMethod(native_to_java(object), polyglot_from_string(method, SRC_CS), NULL, 0);
285276
}
286-
return UPCALL_CEXT_O(_jls_PyObject_CallMethod, native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args));
277+
va_list va;
278+
va_start(va, fmt);
279+
args = Py_VaBuildValue(fmt, va);
280+
va_end(va);
281+
return _jls_PyObject_CallMethod(native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args), IS_SINGLE_ARG(fmt));
287282
}
288283

289284
typedef PyObject *(*fast_call_dict_fun_t)(PyObject *, void *, PyObject *);

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

Lines changed: 104 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
import com.oracle.graal.python.nodes.WriteUnraisableNode;
213213
import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode;
214214
import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode;
215+
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetAnyAttributeNode;
215216
import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
216217
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
217218
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
@@ -229,6 +230,7 @@
229230
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
230231
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
231232
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
233+
import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode;
232234
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
233235
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
234236
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
@@ -3300,56 +3302,125 @@ static Object doGeneric(VirtualFrame frame, Object callableObj, Object argsObj,
33003302
abstract static class PyObjectCallFunctionObjArgsNode extends PythonBinaryBuiltinNode {
33013303

33023304
@Specialization(limit = "1")
3303-
static Object doGeneric(VirtualFrame frame, Object callableObj, Object vaList,
3305+
static Object doFunction(VirtualFrame frame, Object callableObj, Object vaList,
33043306
@CachedLibrary("vaList") InteropLibrary argsArrayLib,
3305-
@CachedLibrary(limit = "2") InteropLibrary argLib,
3307+
@Shared("argLib") @CachedLibrary(limit = "2") InteropLibrary argLib,
3308+
@CachedLibrary(limit = "1") PythonObjectLibrary callableLib,
33063309
@Cached AsPythonObjectNode asPythonObjectNode,
3307-
@Cached CallNode callNode,
33083310
@Cached ToNewRefNode toNewRefNode,
33093311
@Cached GetNativeNullNode getNativeNullNode,
33103312
@Cached CExtNodes.ToSulongNode nullToSulongNode,
33113313
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
3314+
try {
3315+
Object callable = asPythonObjectNode.execute(callableObj);
3316+
return toNewRefNode.execute(callFunction(frame, callable, vaList, argsArrayLib, argLib, callableLib, asPythonObjectNode));
3317+
} catch (PException e) {
3318+
// transformExceptionToNativeNode acts as a branch profile
3319+
transformExceptionToNativeNode.execute(frame, e);
3320+
return nullToSulongNode.execute(getNativeNullNode.execute());
3321+
}
3322+
}
3323+
3324+
static Object callFunction(VirtualFrame frame, Object callable, Object vaList,
3325+
InteropLibrary argsArrayLib,
3326+
InteropLibrary argLib,
3327+
PythonObjectLibrary callableLib,
3328+
AsPythonObjectNode asPythonObjectNode) {
33123329
if (argsArrayLib.hasArrayElements(vaList)) {
33133330
try {
3314-
try {
3315-
/*
3316-
* Function 'PyObject_CallFunctionObjArgs' expects a va_list that contains
3317-
* just 'PyObject *' and is terminated by 'NULL'. Hence, we allocate an
3318-
* argument array with one element less than the va_list object says (since
3319-
* the last element is expected to be 'NULL'; this is best effort). However,
3320-
* we must also stop at the first 'NULL' element we encounter since a user
3321-
* could pass several 'NULL'.
3322-
*/
3323-
long arraySize = argsArrayLib.getArraySize(vaList);
3324-
Object[] args = new Object[PInt.intValueExact(arraySize) - 1];
3325-
for (int i = 0; i < args.length; i++) {
3326-
try {
3327-
Object object = argsArrayLib.readArrayElement(vaList, i);
3328-
if (argLib.isNull(object)) {
3329-
break;
3330-
}
3331-
args[i] = asPythonObjectNode.execute(object);
3332-
} catch (InvalidArrayIndexException e) {
3333-
throw CompilerDirectives.shouldNotReachHere();
3331+
/*
3332+
* Function 'PyObject_CallFunctionObjArgs' expects a va_list that contains just
3333+
* 'PyObject *' and is terminated by 'NULL'. Hence, we allocate an argument
3334+
* array with one element less than the va_list object says (since the last
3335+
* element is expected to be 'NULL'; this is best effort). However, we must also
3336+
* stop at the first 'NULL' element we encounter since a user could pass several
3337+
* 'NULL'.
3338+
*/
3339+
long arraySize = argsArrayLib.getArraySize(vaList);
3340+
Object[] args = new Object[PInt.intValueExact(arraySize) - 1];
3341+
for (int i = 0; i < args.length; i++) {
3342+
try {
3343+
Object object = argsArrayLib.readArrayElement(vaList, i);
3344+
if (argLib.isNull(object)) {
3345+
break;
33343346
}
3347+
args[i] = asPythonObjectNode.execute(object);
3348+
} catch (InvalidArrayIndexException e) {
3349+
throw CompilerDirectives.shouldNotReachHere();
33353350
}
3336-
Object callable = asPythonObjectNode.execute(callableObj);
3337-
return toNewRefNode.execute(callNode.execute(frame, callable, args, PKeyword.EMPTY_KEYWORDS));
3338-
} catch (UnsupportedMessageException | OverflowException e) {
3339-
// I think we can just assume that there won't be more than
3340-
// Integer.MAX_VALUE arguments.
3341-
throw CompilerDirectives.shouldNotReachHere();
33423351
}
3343-
} catch (PException e) {
3344-
// transformExceptionToNativeNode acts as a branch profile
3345-
transformExceptionToNativeNode.execute(frame, e);
3346-
return nullToSulongNode.execute(getNativeNullNode.execute());
3352+
return callableLib.callObject(callable, frame, args);
3353+
} catch (UnsupportedMessageException | OverflowException e) {
3354+
// I think we can just assume that there won't be more than
3355+
// Integer.MAX_VALUE arguments.
3356+
throw CompilerDirectives.shouldNotReachHere();
33473357
}
33483358
}
33493359
throw CompilerDirectives.shouldNotReachHere();
33503360
}
33513361
}
33523362

3363+
// directly called without landing function
3364+
@Builtin(name = "PyObject_CallMethodObjArgs", parameterNames = {"receiver", "method_name", "va_list"})
3365+
@GenerateNodeFactory
3366+
abstract static class PyObjectCallMethodObjArgsNode extends PythonTernaryBuiltinNode {
3367+
3368+
@Specialization(limit = "1")
3369+
static Object doMethod(VirtualFrame frame, Object receiverObj, Object methodNameObj, Object vaList,
3370+
@CachedLibrary(limit = "1") PythonObjectLibrary methodLib,
3371+
@CachedLibrary("vaList") InteropLibrary argsArrayLib,
3372+
@Shared("argLib") @CachedLibrary(limit = "2") InteropLibrary argLib,
3373+
@Cached GetAnyAttributeNode getAnyAttributeNode,
3374+
@Cached AsPythonObjectNode asPythonObjectNode,
3375+
@Cached ToNewRefNode toNewRefNode,
3376+
@Cached GetNativeNullNode getNativeNullNode,
3377+
@Cached CExtNodes.ToSulongNode nullToSulongNode,
3378+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
3379+
3380+
try {
3381+
Object receiver = asPythonObjectNode.execute(receiverObj);
3382+
Object methodName = asPythonObjectNode.execute(methodNameObj);
3383+
Object method = getAnyAttributeNode.executeObject(frame, receiver, methodName);
3384+
return toNewRefNode.execute(PyObjectCallFunctionObjArgsNode.callFunction(frame, method, vaList, argsArrayLib, argLib, methodLib, asPythonObjectNode));
3385+
} catch (PException e) {
3386+
// transformExceptionToNativeNode acts as a branch profile
3387+
transformExceptionToNativeNode.execute(frame, e);
3388+
return nullToSulongNode.execute(getNativeNullNode.execute());
3389+
}
3390+
}
3391+
}
3392+
3393+
// directly called without landing function
3394+
@Builtin(name = "PyObject_CallMethod", parameterNames = {"object", "method_name", "args", "single_arg"})
3395+
@GenerateNodeFactory
3396+
abstract static class PyObjectCallMethodNode extends PythonQuaternaryBuiltinNode {
3397+
@Specialization
3398+
static Object doGeneric(VirtualFrame frame, Object receiverObj, String methodName, Object argsObj, int singleArg,
3399+
@CachedLibrary(limit = "1") PythonObjectLibrary objectLib,
3400+
@Cached AsPythonObjectNode asPythonObjectNode,
3401+
@Cached CastArgsNode castArgsNode,
3402+
@Cached ToNewRefNode toNewRefNode,
3403+
@Cached GetNativeNullNode getNativeNullNode,
3404+
@Cached CExtNodes.ToSulongNode nullToSulongNode,
3405+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
3406+
3407+
try {
3408+
Object receiver = asPythonObjectNode.execute(receiverObj);
3409+
Object[] args;
3410+
if (singleArg != 0) {
3411+
args = new Object[]{asPythonObjectNode.execute(argsObj)};
3412+
} else {
3413+
args = castArgsNode.execute(frame, argsObj);
3414+
}
3415+
return toNewRefNode.execute(objectLib.lookupAndCallRegularMethod(receiver, frame, methodName, args));
3416+
} catch (PException e) {
3417+
// transformExceptionToNativeNode acts as a branch profile
3418+
transformExceptionToNativeNode.execute(frame, e);
3419+
return nullToSulongNode.execute(getNativeNullNode.execute());
3420+
}
3421+
}
3422+
}
3423+
33533424
// directly called without landing function
33543425
@Builtin(name = "PyObject_FastCallDict", parameterNames = {"callable", "argsArray", "kwargs"})
33553426
@GenerateNodeFactory

graalpython/lib-graalpython/python_cext.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,16 +1109,6 @@ def dict_from_list(lst):
11091109
return d
11101110

11111111

1112-
@may_raise
1113-
def PyObject_CallMethod(rcvr, method, args):
1114-
# TODO(fa) that seems to be a workaround
1115-
if type(args) is tuple:
1116-
return getattr(rcvr, method)(*args)
1117-
elif args is not None:
1118-
return getattr(rcvr, method)(args)
1119-
return getattr(rcvr, method)()
1120-
1121-
11221112
@may_raise(-1)
11231113
def PyObject_DelItem(obj, key):
11241114
del obj[key]

0 commit comments

Comments
 (0)