Skip to content

Commit 972bc6c

Browse files
committed
Use CallBinaryMethodNode for dispatching __getattribute__ callable
It is a common pattern that Python class defines only __getattr__, in which case the TpSlotGetAttrPython will wrap the inherited builtin __getattribute__ and the user defined __getattr__ callable. Normally, slots wrapping Python callables do not wrap builtins. This is impossible for slots wrapping one callable, because we unwrap them in fixupSlotDispatchers (like CPython). For other slots wrapping 2 callables it is probably not as common as for tp_getattro. Therefore the dispatching code for those nodes, does not have a fast-path for builtin callables. This PR adds such fast-path to CallManagedSlotGetAttrNode.
1 parent 15e4a1e commit 972bc6c

File tree

1 file changed

+11
-1
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots

1 file changed

+11
-1
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotGetAttr.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPython;
6464
import com.oracle.graal.python.nodes.PGuards;
6565
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode.Dynamic;
66+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
67+
import com.oracle.graal.python.nodes.call.special.MaybeBindDescriptorNode;
6668
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
6769
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
6870
import com.oracle.graal.python.runtime.ExecutionContext.CallContext;
@@ -297,6 +299,8 @@ static Object callPythonSimple(VirtualFrame frame, Node inliningTarget, TpSlotGe
297299

298300
@Specialization(guards = "slot.hasGetattr()")
299301
static Object callPythonSimple(VirtualFrame frame, Node inliningTarget, TpSlotGetAttrPython slot, Object self, Object name,
302+
@Cached MaybeBindDescriptorNode bindDescriptorNode,
303+
@Cached CallBinaryMethodNode callGetAttributeNode,
300304
@Exclusive @Cached BinaryPythonSlotDispatcherNode callPythonFun,
301305
@Cached IsBuiltinObjectProfile errorProfile) {
302306
// equivalent of slot_tp_getattr_hook
@@ -309,7 +313,13 @@ static Object callPythonSimple(VirtualFrame frame, Node inliningTarget, TpSlotGe
309313
// TODO: CPython calls PyObject_GenericGetAttr if there is no __getattribute__. Can
310314
// we create a type that does not inherit tp_getattro and so no __getattribute__ is
311315
// created for it in add_operators?
312-
return callPythonFun.execute(frame, inliningTarget, slot.getGetattribute(), type, self, name);
316+
317+
// NOTE: we use CallBinaryMethodNode, because it is common that the __getattribute__
318+
// callable is PBuiltinFunction wrapper is wrapping raw tp_getattro slot. This
319+
// happens if a Python class declares __getattr__ and inherits __getattribute__
320+
// wrapping some builtin slot.
321+
Object bound = bindDescriptorNode.execute(frame, inliningTarget, slot.getGetattribute(), self, type);
322+
return callGetAttributeNode.executeObject(frame, bound, self, name);
313323
} catch (PException pe) {
314324
pe.expect(inliningTarget, AttributeError, errorProfile);
315325
if (getattr == null) {

0 commit comments

Comments
 (0)