39
39
import com .oracle .graal .python .nodes .attributes .GetAttributeNode ;
40
40
import com .oracle .graal .python .nodes .attributes .GetAttributeNode .GetAnyAttributeNode ;
41
41
import com .oracle .graal .python .nodes .call .PythonCallNodeGen .GetCallAttributeNodeGen ;
42
+ import com .oracle .graal .python .nodes .call .PythonCallNodeGen .InvokeForeignNodeGen ;
42
43
import com .oracle .graal .python .nodes .call .special .CallBinaryMethodNode ;
43
44
import com .oracle .graal .python .nodes .call .special .CallQuaternaryMethodNode ;
44
45
import com .oracle .graal .python .nodes .call .special .CallTernaryMethodNode ;
52
53
import com .oracle .graal .python .nodes .object .GetClassNode ;
53
54
import com .oracle .graal .python .nodes .subscript .GetItemNode ;
54
55
import com .oracle .graal .python .nodes .util .ExceptionStateNodes .GetCaughtExceptionNode ;
56
+ import com .oracle .graal .python .runtime .PythonOptions ;
55
57
import com .oracle .graal .python .runtime .exception .PythonErrorType ;
56
58
import com .oracle .graal .python .runtime .object .PythonObjectFactory ;
57
59
import com .oracle .truffle .api .CompilerAsserts ;
60
+ import com .oracle .truffle .api .CompilerDirectives ;
58
61
import com .oracle .truffle .api .debug .DebuggerTags ;
59
62
import com .oracle .truffle .api .dsl .Cached ;
63
+ import com .oracle .truffle .api .dsl .ImportStatic ;
60
64
import com .oracle .truffle .api .dsl .NodeChild ;
61
65
import com .oracle .truffle .api .dsl .Specialization ;
62
66
import com .oracle .truffle .api .frame .VirtualFrame ;
69
73
import com .oracle .truffle .api .interop .UnsupportedMessageException ;
70
74
import com .oracle .truffle .api .interop .UnsupportedTypeException ;
71
75
import com .oracle .truffle .api .library .CachedLibrary ;
76
+ import com .oracle .truffle .api .nodes .Node ;
72
77
import com .oracle .truffle .api .profiles .BranchProfile ;
73
78
74
79
@ NodeChild ("calleeNode" )
@@ -95,7 +100,7 @@ public abstract class PythonCallNode extends ExpressionNode {
95
100
this .keywordArguments = keywordArguments ;
96
101
}
97
102
98
- public static PythonCallNode create (ExpressionNode calleeNode , ExpressionNode [] argumentNodes , ExpressionNode [] keywords , ExpressionNode starArgs , ExpressionNode kwArgs ) {
103
+ public static ExpressionNode create (ExpressionNode calleeNode , ExpressionNode [] argumentNodes , ExpressionNode [] keywords , ExpressionNode starArgs , ExpressionNode kwArgs ) {
99
104
assert !(starArgs instanceof EmptyNode ) : "pass null instead" ;
100
105
assert !(kwArgs instanceof EmptyNode ) : "pass null instead" ;
101
106
@@ -110,6 +115,22 @@ public static PythonCallNode create(ExpressionNode calleeNode, ExpressionNode[]
110
115
getCallableNode = GetCallAttributeNodeGen .create (((GetAttributeNode ) calleeNode ).getKey (), ((GetAttributeNode ) calleeNode ).getObject ());
111
116
}
112
117
KeywordArgumentsNode keywordArgumentsNode = kwArgs == null && keywords .length == 0 ? null : KeywordArgumentsNode .create (keywords , kwArgs );
118
+
119
+ if (argumentNodes != null && keywordArgumentsNode == null && starArgs == null ) {
120
+ switch (argumentNodes .length ) {
121
+ case 1 :
122
+ return new PythonCallUnary (getCallableNode , argumentNodes [0 ]);
123
+ case 2 :
124
+ return new PythonCallBinary (getCallableNode , argumentNodes );
125
+ case 3 :
126
+ return new PythonCallTernary (getCallableNode , argumentNodes );
127
+ case 4 :
128
+ return new PythonCallQuaternary (getCallableNode , argumentNodes );
129
+ default :
130
+ // otherwise: fall through
131
+ }
132
+ }
133
+
113
134
if (starArgs == null ) {
114
135
return PythonCallNodeGen .create (calleeName , argumentNodes , null , keywordArgumentsNode , getCallableNode );
115
136
} else {
@@ -126,14 +147,25 @@ private static class PythonCallUnary extends ExpressionNode {
126
147
@ Child ExpressionNode getCallable ;
127
148
@ Child ExpressionNode argumentNode ;
128
149
150
+ @ Child InvokeForeign invokeForeign ;
151
+
129
152
PythonCallUnary (ExpressionNode getCallable , ExpressionNode argumentNode ) {
130
153
this .getCallable = getCallable ;
131
154
this .argumentNode = argumentNode ;
132
155
}
133
156
134
157
@ Override
135
158
public Object execute (VirtualFrame frame ) {
136
- return callUnary .executeObject (frame , getCallable .execute (frame ), argumentNode .execute (frame ));
159
+ Object callable = getCallable .execute (frame );
160
+ Object argument = argumentNode .execute (frame );
161
+ if (callable instanceof ForeignInvoke ) {
162
+ if (invokeForeign == null ) {
163
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
164
+ invokeForeign = insert (InvokeForeignNodeGen .create ());
165
+ }
166
+ return invokeForeign .execute (frame , (ForeignInvoke ) callable , new Object []{argument }, PKeyword .EMPTY_KEYWORDS );
167
+ }
168
+ return callUnary .executeObject (frame , callable , argument );
137
169
}
138
170
}
139
171
@@ -142,15 +174,26 @@ private static class PythonCallBinary extends ExpressionNode {
142
174
@ Child ExpressionNode getCallable ;
143
175
@ Children final ExpressionNode [] argumentNodes ;
144
176
177
+ @ Child InvokeForeign invokeForeign ;
178
+
145
179
PythonCallBinary (ExpressionNode getCallable , ExpressionNode [] argumentNodes ) {
146
180
this .getCallable = getCallable ;
147
181
this .argumentNodes = argumentNodes ;
148
182
}
149
183
150
184
@ Override
151
185
public Object execute (VirtualFrame frame ) {
152
- Object [] evaluatedArguments = PositionalArgumentsNode .evaluateArguments (frame , argumentNodes );
153
- return callBinary .executeObject (frame , getCallable .execute (frame ), evaluatedArguments [0 ], evaluatedArguments [1 ]);
186
+ Object callable = getCallable .execute (frame );
187
+ Object argument1 = argumentNodes [0 ].execute (frame );
188
+ Object argument2 = argumentNodes [1 ].execute (frame );
189
+ if (callable instanceof ForeignInvoke ) {
190
+ if (invokeForeign == null ) {
191
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
192
+ invokeForeign = insert (InvokeForeignNodeGen .create ());
193
+ }
194
+ return invokeForeign .execute (frame , (ForeignInvoke ) callable , new Object []{argument1 , argument2 }, PKeyword .EMPTY_KEYWORDS );
195
+ }
196
+ return callBinary .executeObject (frame , callable , argument1 , argument2 );
154
197
}
155
198
}
156
199
@@ -159,14 +202,27 @@ private static class PythonCallTernary extends ExpressionNode {
159
202
@ Child ExpressionNode getCallable ;
160
203
@ Children final ExpressionNode [] argumentNodes ;
161
204
205
+ @ Child InvokeForeign invokeForeign ;
206
+
162
207
PythonCallTernary (ExpressionNode getCallable , ExpressionNode [] argumentNodes ) {
163
208
this .getCallable = getCallable ;
164
209
this .argumentNodes = argumentNodes ;
165
210
}
166
211
167
212
@ Override
168
213
public Object execute (VirtualFrame frame ) {
169
- return callTernary .execute (frame , getCallable .execute (frame ), argumentNodes [0 ].execute (frame ), argumentNodes [1 ].execute (frame ), argumentNodes [2 ].execute (frame ));
214
+ Object callable = getCallable .execute (frame );
215
+ Object argument1 = argumentNodes [0 ].execute (frame );
216
+ Object argument2 = argumentNodes [1 ].execute (frame );
217
+ Object argument3 = argumentNodes [2 ].execute (frame );
218
+ if (callable instanceof ForeignInvoke ) {
219
+ if (invokeForeign == null ) {
220
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
221
+ invokeForeign = insert (InvokeForeignNodeGen .create ());
222
+ }
223
+ return invokeForeign .execute (frame , (ForeignInvoke ) callable , new Object []{argument1 , argument2 , argument3 }, PKeyword .EMPTY_KEYWORDS );
224
+ }
225
+ return callTernary .execute (frame , callable , argument1 , argument2 , argument3 );
170
226
}
171
227
}
172
228
@@ -175,15 +231,28 @@ private static class PythonCallQuaternary extends ExpressionNode {
175
231
@ Child ExpressionNode getCallable ;
176
232
@ Children final ExpressionNode [] argumentNodes ;
177
233
234
+ @ Child InvokeForeign invokeForeign ;
235
+
178
236
PythonCallQuaternary (ExpressionNode getCallable , ExpressionNode [] argumentNodes ) {
179
237
this .getCallable = getCallable ;
180
238
this .argumentNodes = argumentNodes ;
181
239
}
182
240
183
241
@ Override
184
242
public Object execute (VirtualFrame frame ) {
185
- return callQuaternary .execute (frame , getCallable .execute (frame ), argumentNodes [0 ].execute (frame ), argumentNodes [1 ].execute (frame ), argumentNodes [2 ].execute (frame ),
186
- argumentNodes [3 ].execute (frame ));
243
+ Object callable = getCallable .execute (frame );
244
+ Object argument1 = argumentNodes [0 ].execute (frame );
245
+ Object argument2 = argumentNodes [1 ].execute (frame );
246
+ Object argument3 = argumentNodes [2 ].execute (frame );
247
+ Object argument4 = argumentNodes [3 ].execute (frame );
248
+ if (callable instanceof ForeignInvoke ) {
249
+ if (invokeForeign == null ) {
250
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
251
+ invokeForeign = insert (InvokeForeignNodeGen .create ());
252
+ }
253
+ return invokeForeign .execute (frame , (ForeignInvoke ) callable , new Object []{argument1 , argument2 , argument3 , argument4 }, PKeyword .EMPTY_KEYWORDS );
254
+ }
255
+ return callQuaternary .execute (frame , callable , argument1 , argument2 , argument3 , argument4 );
187
256
}
188
257
}
189
258
@@ -261,32 +330,47 @@ private PKeyword[] evaluateKeywords(VirtualFrame frame) {
261
330
return keywordArguments == null ? PKeyword .EMPTY_KEYWORDS : keywordArguments .execute (frame );
262
331
}
263
332
333
+ @ ImportStatic ({PythonOptions .class })
334
+ abstract static class InvokeForeign extends Node {
335
+
336
+ @ Child private CallNode callNode = CallNode .create ();
337
+
338
+ public abstract Object execute (VirtualFrame frame , ForeignInvoke callable , Object [] arguments , PKeyword [] keywords );
339
+
340
+ @ Specialization
341
+ Object call (VirtualFrame frame , ForeignInvoke callable , Object [] arguments , PKeyword [] keywords ,
342
+ @ Cached PRaiseNode raise ,
343
+ @ Cached ("create()" ) PForeignToPTypeNode fromForeign ,
344
+ @ Cached ("create()" ) BranchProfile typeError ,
345
+ @ Cached ("create()" ) BranchProfile invokeError ,
346
+ @ Cached ("create()" ) GetAnyAttributeNode getAttrNode ,
347
+ @ CachedLibrary (limit = "getCallSiteInlineCacheMaxDepth()" ) InteropLibrary interop ) {
348
+ try {
349
+ return fromForeign .executeConvert (interop .invokeMember (callable .receiver , callable .identifier , arguments ));
350
+ } catch (ArityException | UnsupportedTypeException e ) {
351
+ typeError .enter ();
352
+ throw raise .raise (PythonErrorType .TypeError , e );
353
+ } catch (UnknownIdentifierException | UnsupportedMessageException e ) {
354
+ invokeError .enter ();
355
+ // the interop contract is to revert to readMember and then execute
356
+ Object member = getAttrNode .executeObject (frame , callable .receiver , callable .identifier );
357
+ return callNode .execute (frame , member , arguments , keywords );
358
+ }
359
+ }
360
+ }
361
+
264
362
@ Specialization
265
363
Object call (VirtualFrame frame , ForeignInvoke callable ,
266
364
@ Cached PRaiseNode raise ,
267
- @ Cached ("create()" ) PForeignToPTypeNode fromForeign ,
268
365
@ Cached ("create()" ) BranchProfile keywordsError ,
269
- @ Cached ("create()" ) BranchProfile typeError ,
270
- @ Cached ("create()" ) BranchProfile invokeError ,
271
- @ Cached ("create()" ) GetAnyAttributeNode getAttrNode ,
272
- @ CachedLibrary (limit = "getCallSiteInlineCacheMaxDepth()" ) InteropLibrary interop ) {
366
+ @ Cached InvokeForeign invoke ) {
273
367
Object [] arguments = evaluateArguments (frame );
274
368
PKeyword [] keywords = evaluateKeywords (frame );
275
369
if (keywords .length != 0 ) {
276
370
keywordsError .enter ();
277
371
throw raise .raise (PythonErrorType .TypeError , ErrorMessages .FOREIGN_INVOCATION_DOESNT_SUPPORT_KEYWORD_ARG );
278
372
}
279
- try {
280
- return fromForeign .executeConvert (interop .invokeMember (callable .receiver , callable .identifier , arguments ));
281
- } catch (ArityException | UnsupportedTypeException e ) {
282
- typeError .enter ();
283
- throw raise .raise (PythonErrorType .TypeError , e );
284
- } catch (UnknownIdentifierException | UnsupportedMessageException e ) {
285
- invokeError .enter ();
286
- // the interop contract is to revert to readMember and then execute
287
- Object member = getAttrNode .executeObject (frame , callable .receiver , callable .identifier );
288
- return callNode .execute (frame , member , arguments , keywords );
289
- }
373
+ return invoke .execute (frame , callable , arguments , keywords );
290
374
}
291
375
292
376
protected static boolean isSysExcInfo (Class <? extends PythonBuiltinBaseNode > nodeClass ) {
0 commit comments