42
42
43
43
import static com .oracle .graal .python .nodes .SpecialAttributeNames .__DOC__ ;
44
44
45
+ import com .oracle .graal .python .builtins .Builtin ;
46
+ import com .oracle .graal .python .builtins .objects .PNone ;
45
47
import com .oracle .graal .python .builtins .objects .PythonAbstractObject ;
48
+ import com .oracle .graal .python .builtins .objects .cext .capi .CArrayWrappers .CStringWrapper ;
46
49
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .AsCharPointerNode ;
47
50
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .FromCharPointerNode ;
48
51
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .GetNativeNullNode ;
49
52
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 ;
50
57
import com .oracle .graal .python .builtins .objects .object .PythonBuiltinObject ;
51
58
import com .oracle .graal .python .builtins .objects .object .PythonObject ;
52
59
import com .oracle .graal .python .nodes .PGuards ;
53
60
import com .oracle .graal .python .nodes .SpecialAttributeNames ;
54
61
import com .oracle .graal .python .nodes .SpecialMethodNames ;
55
62
import com .oracle .graal .python .nodes .attributes .ReadAttributeFromObjectNode ;
56
63
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 ;
57
67
import com .oracle .graal .python .runtime .interop .InteropArray ;
68
+ import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
58
69
import com .oracle .truffle .api .dsl .Cached ;
59
70
import com .oracle .truffle .api .dsl .Cached .Exclusive ;
60
71
import com .oracle .truffle .api .dsl .Cached .Shared ;
61
72
import com .oracle .truffle .api .dsl .GenerateUncached ;
62
73
import com .oracle .truffle .api .dsl .ImportStatic ;
74
+ import com .oracle .truffle .api .dsl .NodeFactory ;
63
75
import com .oracle .truffle .api .dsl .Specialization ;
64
76
import com .oracle .truffle .api .interop .InteropLibrary ;
65
77
import com .oracle .truffle .api .interop .UnknownIdentifierException ;
73
85
/**
74
86
* Wraps a PythonObject to provide a native view with a shape like {@code PyMethodDescr}.
75
87
*/
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
+ */
76
100
@ ExportLibrary (InteropLibrary .class )
77
101
@ ExportLibrary (NativeTypeLibrary .class )
78
102
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" ;
81
107
82
108
public PyMethodDescrWrapper (PythonObject delegate ) {
83
109
super (delegate );
84
110
}
85
111
86
112
@ ExportMessage
87
- protected boolean hasMembers () {
113
+ boolean hasMembers () {
88
114
return true ;
89
115
}
90
116
91
117
@ ExportMessage
92
- protected boolean isMemberReadable (String member ) {
118
+ boolean isMemberReadable (String member ) {
93
119
switch (member ) {
94
- case NAME :
95
- case DOC :
120
+ case ML_NAME :
121
+ case ML_METH :
122
+ case ML_FLAGS :
123
+ case ML_DOC :
96
124
return true ;
97
125
default :
98
126
return false ;
@@ -101,7 +129,7 @@ protected boolean isMemberReadable(String member) {
101
129
102
130
@ ExportMessage
103
131
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 });
105
133
}
106
134
107
135
@ ExportMessage
@@ -112,18 +140,16 @@ protected Object readMember(String member,
112
140
}
113
141
114
142
@ GenerateUncached
115
- @ ImportStatic ({ SpecialMethodNames .class } )
143
+ @ ImportStatic (PyMethodDescrWrapper .class )
116
144
abstract static class ReadFieldNode extends Node {
117
- public static final String NAME = PyMethodDescrWrapper .NAME ;
118
- public static final String DOC = PyMethodDescrWrapper .DOC ;
119
145
120
146
public abstract Object execute (Object delegate , String key );
121
147
122
148
protected static boolean eq (String expected , String actual ) {
123
149
return expected .equals (actual );
124
150
}
125
151
126
- @ Specialization (guards = {"eq(NAME , key)" })
152
+ @ Specialization (guards = {"eq(ML_NAME , key)" })
127
153
static Object getName (PythonObject object , @ SuppressWarnings ("unused" ) String key ,
128
154
@ Cached PythonAbstractObject .PInteropGetAttributeNode getAttrNode ,
129
155
@ Shared ("toSulongNode" ) @ Cached ToSulongNode toSulongNode ,
@@ -137,24 +163,82 @@ static Object getName(PythonObject object, @SuppressWarnings("unused") String ke
137
163
}
138
164
}
139
165
140
- @ Specialization (guards = {"eq(DOC , key)" })
166
+ @ Specialization (guards = {"eq(ML_DOC , key)" })
141
167
static Object getDoc (PythonObject object , @ SuppressWarnings ("unused" ) String key ,
142
168
@ Cached ReadAttributeFromObjectNode getAttrNode ,
143
169
@ Shared ("toSulongNode" ) @ Cached ToSulongNode toSulongNode ,
144
- @ Shared ("asCharPointerNode " ) @ Cached AsCharPointerNode asCharPointerNode ,
170
+ @ Shared ("castToJavaStringNode " ) @ Cached CastToJavaStringNode castToJavaStringNode ,
145
171
@ Shared ("getNativeNullNode" ) @ Cached GetNativeNullNode getNativeNullNode ) {
146
172
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 ];
151
234
}
235
+ return null ;
152
236
}
153
237
}
154
238
155
239
@ ExportMessage
156
240
protected boolean isMemberModifiable (String member ) {
157
- return DOC .equals (member );
241
+ return ML_DOC .equals (member );
158
242
}
159
243
160
244
@ ExportMessage
0 commit comments