Skip to content

Commit 0a58d6a

Browse files
committed
Implement ml_meth and ml_flags for PyMethodDescrWrapper
1 parent 2099895 commit 0a58d6a

File tree

2 files changed

+109
-25
lines changed

2 files changed

+109
-25
lines changed

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

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,36 @@
4242

4343
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DOC__;
4444

45+
import com.oracle.graal.python.builtins.Builtin;
46+
import com.oracle.graal.python.builtins.objects.PNone;
4547
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
48+
import com.oracle.graal.python.builtins.objects.cext.capi.CArrayWrappers.CStringWrapper;
4649
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.AsCharPointerNode;
4750
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.FromCharPointerNode;
4851
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.GetNativeNullNode;
4952
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.ToSulongNode;
53+
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
54+
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
55+
import com.oracle.graal.python.builtins.objects.function.Signature;
56+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
5057
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
5158
import com.oracle.graal.python.builtins.objects.object.PythonObject;
5259
import com.oracle.graal.python.nodes.PGuards;
5360
import com.oracle.graal.python.nodes.SpecialAttributeNames;
5461
import com.oracle.graal.python.nodes.SpecialMethodNames;
5562
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
5663
import com.oracle.graal.python.nodes.attributes.WriteAttributeToDynamicObjectNode;
64+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
65+
import com.oracle.graal.python.nodes.util.CannotCastException;
66+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
5767
import com.oracle.graal.python.runtime.interop.InteropArray;
68+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5869
import com.oracle.truffle.api.dsl.Cached;
5970
import com.oracle.truffle.api.dsl.Cached.Exclusive;
6071
import com.oracle.truffle.api.dsl.Cached.Shared;
6172
import com.oracle.truffle.api.dsl.GenerateUncached;
6273
import com.oracle.truffle.api.dsl.ImportStatic;
74+
import com.oracle.truffle.api.dsl.NodeFactory;
6375
import com.oracle.truffle.api.dsl.Specialization;
6476
import com.oracle.truffle.api.interop.InteropLibrary;
6577
import com.oracle.truffle.api.interop.UnknownIdentifierException;
@@ -73,26 +85,42 @@
7385
/**
7486
* Wraps a PythonObject to provide a native view with a shape like {@code PyMethodDescr}.
7587
*/
88+
/**
89+
* Wrapper object that emulate the ABI for {@code PyMethodDef}.
90+
*
91+
* <pre>
92+
* struct PyMethodDef {
93+
* const char *ml_name; // The name of the built-in function/method
94+
* PyCFunction ml_meth; // The C function that implements it
95+
* int ml_flags; // Combination of METH_xxx flags, which mostly describe the args expected by the C
96+
* const char*ml_doc; // The __doc__ attribute, or NULL
97+
* };
98+
* </pre>
99+
*/
76100
@ExportLibrary(InteropLibrary.class)
77101
@ExportLibrary(NativeTypeLibrary.class)
78102
public class PyMethodDescrWrapper extends PythonNativeWrapper {
79-
public static final String NAME = "ml_name";
80-
public static final String DOC = "ml_doc";
103+
public static final String ML_NAME = "ml_name";
104+
public static final String ML_METH = "ml_meth";
105+
public static final String ML_FLAGS = "ml_flags";
106+
public static final String ML_DOC = "ml_doc";
81107

82108
public PyMethodDescrWrapper(PythonObject delegate) {
83109
super(delegate);
84110
}
85111

86112
@ExportMessage
87-
protected boolean hasMembers() {
113+
boolean hasMembers() {
88114
return true;
89115
}
90116

91117
@ExportMessage
92-
protected boolean isMemberReadable(String member) {
118+
boolean isMemberReadable(String member) {
93119
switch (member) {
94-
case NAME:
95-
case DOC:
120+
case ML_NAME:
121+
case ML_METH:
122+
case ML_FLAGS:
123+
case ML_DOC:
96124
return true;
97125
default:
98126
return false;
@@ -101,7 +129,7 @@ protected boolean isMemberReadable(String member) {
101129

102130
@ExportMessage
103131
protected Object getMembers(@SuppressWarnings("unused") boolean includeInternal) {
104-
return new InteropArray(new Object[]{NAME, DOC});
132+
return new InteropArray(new Object[]{ML_NAME, ML_METH, ML_FLAGS, ML_DOC});
105133
}
106134

107135
@ExportMessage
@@ -112,18 +140,16 @@ protected Object readMember(String member,
112140
}
113141

114142
@GenerateUncached
115-
@ImportStatic({SpecialMethodNames.class})
143+
@ImportStatic(PyMethodDescrWrapper.class)
116144
abstract static class ReadFieldNode extends Node {
117-
public static final String NAME = PyMethodDescrWrapper.NAME;
118-
public static final String DOC = PyMethodDescrWrapper.DOC;
119145

120146
public abstract Object execute(Object delegate, String key);
121147

122148
protected static boolean eq(String expected, String actual) {
123149
return expected.equals(actual);
124150
}
125151

126-
@Specialization(guards = {"eq(NAME, key)"})
152+
@Specialization(guards = {"eq(ML_NAME, key)"})
127153
static Object getName(PythonObject object, @SuppressWarnings("unused") String key,
128154
@Cached PythonAbstractObject.PInteropGetAttributeNode getAttrNode,
129155
@Shared("toSulongNode") @Cached ToSulongNode toSulongNode,
@@ -137,24 +163,82 @@ static Object getName(PythonObject object, @SuppressWarnings("unused") String ke
137163
}
138164
}
139165

140-
@Specialization(guards = {"eq(DOC, key)"})
166+
@Specialization(guards = {"eq(ML_DOC, key)"})
141167
static Object getDoc(PythonObject object, @SuppressWarnings("unused") String key,
142168
@Cached ReadAttributeFromObjectNode getAttrNode,
143169
@Shared("toSulongNode") @Cached ToSulongNode toSulongNode,
144-
@Shared("asCharPointerNode") @Cached AsCharPointerNode asCharPointerNode,
170+
@Shared("castToJavaStringNode") @Cached CastToJavaStringNode castToJavaStringNode,
145171
@Shared("getNativeNullNode") @Cached GetNativeNullNode getNativeNullNode) {
146172
Object doc = getAttrNode.execute(object, __DOC__);
147-
if (PGuards.isPNone(doc)) {
148-
return toSulongNode.execute(getNativeNullNode.execute());
149-
} else {
150-
return asCharPointerNode.execute(doc);
173+
if (doc != PNone.NO_VALUE) {
174+
try {
175+
return new CStringWrapper(castToJavaStringNode.execute(doc));
176+
} catch (CannotCastException e) {
177+
// fall through
178+
}
179+
}
180+
return toSulongNode.execute(getNativeNullNode.execute());
181+
}
182+
183+
@Specialization(guards = {"eq(ML_METH, key)"})
184+
static Object getMeth(PythonObject object, @SuppressWarnings("unused") String key,
185+
@Shared("toSulongNode") @Cached ToSulongNode toSulongNode) {
186+
return toSulongNode.execute(object);
187+
}
188+
189+
@Specialization(guards = {"eq(ML_FLAGS, key)"})
190+
static Object getMeth(PythonObject object, @SuppressWarnings("unused") String key) {
191+
PBuiltinFunction fun = null;
192+
if (object instanceof PBuiltinFunction) {
193+
fun = (PBuiltinFunction) object;
194+
} else if (object instanceof PBuiltinMethod) {
195+
fun = ((PBuiltinMethod) object).getFunction();
196+
}
197+
if (fun != null) {
198+
return getFlags(fun);
199+
}
200+
return 0;
201+
}
202+
203+
@TruffleBoundary
204+
private static int getFlags(PBuiltinFunction object) {
205+
Builtin builtin = getBuiltin(object);
206+
int flags = 0;
207+
if (builtin.isClassmethod()) {
208+
flags |= CExtContext.METH_CLASS;
209+
}
210+
if (builtin.isStaticmethod()) {
211+
flags |= CExtContext.METH_STATIC;
212+
}
213+
Signature signature = object.getSignature();
214+
int params = signature.getParameterIds().length;
215+
if (params == 1) {
216+
// only 'self'
217+
flags |= CExtContext.METH_NOARGS;
218+
} else if (params == 2) {
219+
flags |= CExtContext.METH_O;
220+
} else if (signature.takesKeywordArgs()) {
221+
flags |= CExtContext.METH_VARARGS;
222+
} else if (signature.takesVarArgs()) {
223+
flags |= CExtContext.METH_VARARGS;
224+
}
225+
return flags | CExtContext.METH_FASTCALL;
226+
}
227+
228+
@TruffleBoundary
229+
private static Builtin getBuiltin(PBuiltinFunction delegate) {
230+
NodeFactory<? extends PythonBuiltinBaseNode> builtinNodeFactory = delegate.getBuiltinNodeFactory();
231+
if (builtinNodeFactory != null) {
232+
assert builtinNodeFactory.getNodeClass().getAnnotationsByType(Builtin.class).length > 0 : "PBuiltinFunction " + delegate + " is expected to have a Builtin annotated node.";
233+
return builtinNodeFactory.getNodeClass().getAnnotationsByType(Builtin.class)[0];
151234
}
235+
return null;
152236
}
153237
}
154238

155239
@ExportMessage
156240
protected boolean isMemberModifiable(String member) {
157-
return DOC.equals(member);
241+
return ML_DOC.equals(member);
158242
}
159243

160244
@ExportMessage

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ public abstract class CExtContext {
4747
public static CExtContext LAZY_CONTEXT = new CExtContext(null, null, null) {
4848
};
4949

50-
private static final int METH_VARARGS = 0x0001;
51-
private static final int METH_KEYWORDS = 0x0002;
52-
private static final int METH_NOARGS = 0x0004;
53-
private static final int METH_O = 0x0008;
54-
@SuppressWarnings("unused") private static final int METH_CLASS = 0x0010;
55-
@SuppressWarnings("unused") private static final int METH_STATIC = 0x0020;
56-
private static final int METH_FASTCALL = 0x0080;
50+
public static final int METH_VARARGS = 0x0001;
51+
public static final int METH_KEYWORDS = 0x0002;
52+
public static final int METH_NOARGS = 0x0004;
53+
public static final int METH_O = 0x0008;
54+
public static final int METH_CLASS = 0x0010;
55+
public static final int METH_STATIC = 0x0020;
56+
public static final int METH_FASTCALL = 0x0080;
5757

5858
private final PythonContext context;
5959

0 commit comments

Comments
 (0)