4848import com .oracle .graal .python .builtins .objects .method .PBuiltinMethod ;
4949import com .oracle .graal .python .builtins .objects .type .TpSlots ;
5050import com .oracle .graal .python .builtins .objects .type .TpSlots .GetCachedTpSlotsNode ;
51+ import com .oracle .graal .python .builtins .objects .type .TypeBuiltins ;
5152import com .oracle .graal .python .builtins .objects .type .slots .TpSlotVarargs .CallSlotTpCallNode ;
5253import com .oracle .graal .python .nodes .ErrorMessages ;
5354import com .oracle .graal .python .nodes .PGuards ;
@@ -185,7 +186,8 @@ static Object builtinMethodCall(VirtualFrame frame, PBuiltinMethod callable, Obj
185186 }
186187
187188 @ Fallback
188- static Object doGeneric (VirtualFrame frame , Object callableObject , Object [] arguments , PKeyword [] keywords ,
189+ @ SuppressWarnings ("truffle-static-method" )
190+ Object doGeneric (VirtualFrame frame , Object callableObject , Object [] arguments , PKeyword [] keywords ,
189191 @ Bind Node inliningTarget ,
190192 @ Cached PRaiseNode raise ,
191193 @ Cached GetClassNode getClassNode ,
@@ -194,6 +196,22 @@ static Object doGeneric(VirtualFrame frame, Object callableObject, Object[] argu
194196 Object type = getClassNode .execute (inliningTarget , callableObject );
195197 TpSlots slots = getSlots .execute (inliningTarget , type );
196198 if (slots .tp_call () != null ) {
199+ /*
200+ * Uncached fast-path for type.__call__. This is not just for performance, but has
201+ * "side-channel" effects. Without it, type.__call__'s needsCallerFrame assumption tends
202+ * to get invalidated, which then causes frame sync at every subsequent uncached
203+ * type.__call__ call. Frame syncs create new strong references to local variables (in
204+ * CPython as well) and these spurious frame syncs cause failures in weakref-using
205+ * tests.
206+ */
207+ if (CompilerDirectives .inInterpreter () && !isAdoptable () && slots .tp_call () == TypeBuiltins .SLOTS .tp_call ()) {
208+ /*
209+ * This node is often called from first-uncached bytecode execution, so it has the
210+ * frame despite being uncached. Passing it avoids stack walk when calling
211+ * super.__init__
212+ */
213+ return TypeBuiltins .CallNode .executeUncached (frame , callableObject , arguments , keywords );
214+ }
197215 return callSlot .execute (frame , inliningTarget , slots .tp_call (), callableObject , arguments , keywords );
198216 }
199217 throw raise .raise (inliningTarget , TypeError , ErrorMessages .OBJ_ISNT_CALLABLE , callableObject );
0 commit comments