Skip to content

Commit a1dce91

Browse files
committed
Introduce 'add_slot'
1 parent eca3288 commit a1dce91

File tree

2 files changed

+97
-20
lines changed

2 files changed

+97
-20
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,20 @@ static void add_method_or_slot(PyTypeObject* cls, PyObject* type_dict, char* nam
402402
doc);
403403
}
404404

405+
typedef int (*add_slot_fun_t)(PyTypeObject *, PyObject *, void *, void *, int , int, char *);
406+
UPCALL_TYPED_ID(add_slot, add_slot_fun_t);
407+
static void add_slot(PyTypeObject* cls, PyObject* type_dict, char* name, void* meth, int flags, int signature, char* doc) {
408+
if (meth) {
409+
_jls_add_slot(cls,
410+
native_to_java(type_dict),
411+
polyglot_from_string(name, SRC_CS),
412+
function_pointer_to_java(meth),
413+
flags,
414+
(signature != 0 ? signature : get_method_flags_wrapper(flags)),
415+
doc);
416+
}
417+
}
418+
405419
#define ADD_MEMBER(__javacls__, __tpdict__, __mname__, __mtype__, __moffset__, __mflags__, __mdoc__) \
406420
add_member((__javacls__), (__tpdict__), (__mname__), (__mtype__), (__moffset__), (__mflags__), (__mdoc__))
407421

@@ -423,13 +437,11 @@ int PyType_Ready(PyTypeObject* cls) {
423437

424438
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
425439
#define ADD_METHOD(m) ADD_METHOD_OR_SLOT(m.ml_name, NULL, m.ml_meth, m.ml_flags, NULL, m.ml_doc)
426-
#define ADD_SLOT(name, meth, flags) ADD_METHOD_OR_SLOT(name, NULL, meth, flags, NULL, name)
427-
#define ADD_SLOT_PRIMITIVE(name, meth, flags) ADD_METHOD_OR_SLOT(name, NULL, meth, flags, NULL, name)
428-
#define ADD_SLOT_CONV(name, result_conversion, meth, flags, signature) ADD_METHOD_OR_SLOT(name, result_conversion, meth, flags, signature, name)
429440
#define ADD_METHOD_OR_SLOT(__name__, __res_conv__, __meth__, __flags__, __signature__, __doc__) \
430441
if (__meth__) { \
431442
add_method_or_slot(cls, dict, (__name__), (__res_conv__), (__meth__), (__flags__), (__signature__), (__doc__)); \
432443
}
444+
#define ADD_SLOT_CONV(__name__, __meth__, __flags__, __signature__) add_slot(cls, dict, (__name__), (__meth__), (__flags__), (__signature__), NULL)
433445

434446
Py_ssize_t n;
435447
Py_ssize_t i;

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

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import com.oracle.graal.python.builtins.Python3Core;
7878
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
7979
import com.oracle.graal.python.builtins.PythonBuiltins;
80+
import com.oracle.graal.python.builtins.modules.PythonCextBuiltinsFactory.CreateFunctionNodeGen;
8081
import com.oracle.graal.python.builtins.objects.PNone;
8182
import com.oracle.graal.python.builtins.objects.bytes.BytesBuiltins;
8283
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
@@ -3478,6 +3479,71 @@ static Object getOwner(AsPythonObjectNode asPythonObjectNode, Object primary) {
34783479
}
34793480
}
34803481

3482+
/**
3483+
* Signature: {@code add_slot(primary, tpDict, name", cfunc, flags, wrapper, doc)}
3484+
*/
3485+
// directly called without landing function
3486+
@Builtin(name = "add_slot", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true, declaresExplicitSelf = true)
3487+
@GenerateNodeFactory
3488+
abstract static class AddSlotNode extends PythonVarargsBuiltinNode {
3489+
3490+
@Override
3491+
public final Object varArgExecute(VirtualFrame frame, Object self, Object[] arguments, PKeyword[] keywords) {
3492+
return execute(frame, self, arguments, keywords);
3493+
}
3494+
3495+
@Specialization
3496+
int doWithPrimitives(@SuppressWarnings("unused") Object self, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
3497+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
3498+
try {
3499+
if (arguments.length != 7) {
3500+
CompilerDirectives.transferToInterpreterAndInvalidate();
3501+
throw PRaiseNode.raiseUncached(this, TypeError, ErrorMessages.TAKES_EXACTLY_D_ARGUMENTS_D_GIVEN, "add_slot", 7, arguments.length);
3502+
}
3503+
addSlot(arguments[0], arguments[1], arguments[2], arguments[3], castInt(arguments[4]), castInt(arguments[5]), arguments[6],
3504+
AsPythonObjectNodeGen.getUncached(), CastToJavaStringNode.getUncached(), FromCharPointerNodeGen.getUncached(), InteropLibrary.getUncached(),
3505+
CreateFunctionNodeGen.getUncached(), WriteAttributeToDynamicObjectNode.getUncached(), HashingStorageLibrary.getUncached());
3506+
return 0;
3507+
} catch (PException e) {
3508+
transformExceptionToNativeNode.execute(e);
3509+
return -1;
3510+
}
3511+
}
3512+
3513+
@TruffleBoundary
3514+
private static void addSlot(Object clsPtr, Object tpDictPtr, Object namePtr, Object cfunc, int flags, int wrapper, Object docPtr,
3515+
AsPythonObjectNode asPythonObjectNode,
3516+
CastToJavaStringNode castToJavaStringNode,
3517+
FromCharPointerNode fromCharPointerNode,
3518+
InteropLibrary docPtrLib,
3519+
CreateFunctionNode createFunctionNode,
3520+
WriteAttributeToDynamicObjectNode writeDocNode,
3521+
HashingStorageLibrary dictStorageLib) {
3522+
Object clazz = asPythonObjectNode.execute(clsPtr);
3523+
PDict tpDict = castPDict(asPythonObjectNode.execute(tpDictPtr));
3524+
3525+
String memberName;
3526+
try {
3527+
memberName = castToJavaStringNode.execute(asPythonObjectNode.execute(namePtr));
3528+
} catch (CannotCastException e) {
3529+
throw CompilerDirectives.shouldNotReachHere("Cannot cast member name to string");
3530+
}
3531+
// note: 'doc' may be NULL; in this case, we would store 'None'
3532+
Object memberDoc = CharPtrToJavaObjectNode.run(docPtr, fromCharPointerNode, docPtrLib);
3533+
3534+
// create wrapper descriptor
3535+
Object wrapperDescriptor = createFunctionNode.execute(memberName, cfunc, wrapper, clazz, flags, PythonObjectFactory.getUncached());
3536+
writeDocNode.execute(wrapperDescriptor, SpecialAttributeNames.__DOC__, memberDoc);
3537+
3538+
// add wrapper descriptor to tp_dict
3539+
HashingStorage dictStorage = tpDict.getDictStorage();
3540+
HashingStorage updatedStorage = dictStorageLib.setItem(dictStorage, memberName, wrapperDescriptor);
3541+
if (dictStorage != updatedStorage) {
3542+
tpDict.setDictStorage(updatedStorage);
3543+
}
3544+
}
3545+
}
3546+
34813547
// directly called without landing function
34823548
@Builtin(name = "PyDescr_NewClassMethod", minNumOfPositionalArgs = 6, parameterNames = {"name", "doc", "flags", "wrapper", "cfunc", "primary"})
34833549
@ArgumentClinic(name = "name", conversion = ArgumentClinic.ClinicConversion.String)
@@ -3993,25 +4059,25 @@ private static void addMember(PythonLanguage language, Object clsPtr, Object tpD
39934059
tpDict.setDictStorage(updatedStorage);
39944060
}
39954061
}
4062+
}
39964063

3997-
private static PDict castPDict(Object tpDictObj) {
3998-
if (tpDictObj instanceof PDict) {
3999-
return (PDict) tpDictObj;
4000-
}
4001-
throw CompilerDirectives.shouldNotReachHere("tp_dict object must be a Python dict");
4064+
static PDict castPDict(Object tpDictObj) {
4065+
if (tpDictObj instanceof PDict) {
4066+
return (PDict) tpDictObj;
40024067
}
4068+
throw CompilerDirectives.shouldNotReachHere("tp_dict object must be a Python dict");
4069+
}
40034070

4004-
private static int castInt(Object object) {
4005-
if (object instanceof Integer) {
4006-
return (int) object;
4007-
} else if (object instanceof Long) {
4008-
long lval = (long) object;
4009-
if (PInt.isIntRange(lval)) {
4010-
return (int) lval;
4011-
}
4071+
static int castInt(Object object) {
4072+
if (object instanceof Integer) {
4073+
return (int) object;
4074+
} else if (object instanceof Long) {
4075+
long lval = (long) object;
4076+
if (PInt.isIntRange(lval)) {
4077+
return (int) lval;
40124078
}
4013-
throw CompilerDirectives.shouldNotReachHere("expected Java int");
40144079
}
4080+
throw CompilerDirectives.shouldNotReachHere("expected Java int");
40154081
}
40164082

40174083
abstract static class CreateGetSetNode extends Node {
@@ -4101,9 +4167,8 @@ int doGeneric(Object cls, Object tpDict, String name, Object getter, Object sett
41014167
@CachedLibrary(limit = "1") HashingStorageLibrary dictStorageLib,
41024168
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
41034169
try {
4104-
GetSetDescriptor descr = createGetSetNode.execute(name, cls, getter, setter, doc, closure,
4105-
getLanguage(), factory());
4106-
PDict dict = AddMemberNode.castPDict(asPythonObjectNode.execute(tpDict));
4170+
GetSetDescriptor descr = createGetSetNode.execute(name, cls, getter, setter, doc, closure, getLanguage(), factory());
4171+
PDict dict = PythonCextBuiltins.castPDict(asPythonObjectNode.execute(tpDict));
41074172
HashingStorage dictStorage = dict.getDictStorage();
41084173
HashingStorage updatedStorage = dictStorageLib.setItem(dictStorage, name, descr);
41094174
if (dictStorage != updatedStorage) {

0 commit comments

Comments
 (0)