Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -59,6 +59,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObject.GetNode;
import com.oracle.truffle.api.object.DynamicObject.GetShapeFlagsNode;
import com.oracle.truffle.api.object.Property;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.strings.TruffleString;
Expand Down Expand Up @@ -94,16 +95,17 @@ public static MroShape createRoot() {
public static MroShape create(MroSequenceStorage mro, PythonLanguage lang) {
CompilerAsserts.neverPartOfCompilation();
MroShape mroShape = lang.getMroShapeRoot();
GetShapeFlagsNode getShapeFlagsUncached = GetShapeFlagsNode.getUncached();
for (int i = mro.length() - 1; i >= 0; i--) {
PythonAbstractClass element = mro.getPythonClassItemNormalized(i);
if (PythonManagedClass.isInstance(element)) {
PythonManagedClass managedClass = PythonManagedClass.cast(element);
if (GetDictIfExistsNode.getUncached().execute(managedClass) != null) {
if (GetDictIfExistsNode.getDictUncached(managedClass) != null) {
// On top of not having a shape, the dictionary may also contain items with side
// effecting __eq__ and/or __hash__
return null;
}
if ((DynamicObject.GetShapeFlagsNode.getUncached().execute(managedClass) & HAS_NO_VALUE_PROPERTIES) != 0) {
if ((getShapeFlagsUncached.execute(managedClass) & HAS_NO_VALUE_PROPERTIES) != 0) {
return null;
}
assert hasNoNoValueProperties(managedClass);
Expand Down Expand Up @@ -232,12 +234,12 @@ public static boolean validate(Object obj, PythonLanguage language) {
// We ignore difference for special attributes that should not influence the MRO
// lookup results
diff.remove(T___SLOTNAMES__);
if (diff.size() > 0) {
if (!diff.isEmpty()) {
HashSet<String> sDiff = new HashSet<>(diff.size());
for (Object o : diff) {
sDiff.add(o.toString());
}
assert diff.isEmpty() : message + ",diff:" + String.join(",", sDiff);
assert false : message + ",diff:" + String.join(",", sDiff);
}
}
currMroShape = currMroShape.parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode;
import com.oracle.graal.python.nodes.call.special.MaybeBindDescriptorNode;
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
import com.oracle.graal.python.nodes.exception.EncapsulateExceptionGroupNode;
import com.oracle.graal.python.nodes.exception.ExceptMatchNode;
Expand Down Expand Up @@ -1926,8 +1927,66 @@ public static boolean doIterator(VirtualFrame frame, LocalAccessor output, Objec

@Operation(storeBytecodeIndex = true)
@ConstantOperand(type = TruffleString.class)
@ImportStatic({PythonUtils.class, PGuards.class, GetAttribute.class})
public static final class GetMethod {
@Specialization
/** NO_VALUE result indicates that we should bail out to the full lookup */
@NeverDefault
static Object findStringMethod(Node n, TruffleString name) {
Object descr = LookupAttributeInMRONode.findAttr(PythonContext.get(n), PythonBuiltinClassType.PString, name, ReadAttributeFromPythonObjectNode.getUncached());
// NO_VALUE would mean we need to lookup on the instance, non-method descriptor means that it's going to be something non-callable.
// This is certainly going to lead to some error, so not interesting for fast-path
return MaybeBindDescriptorNode.isMethodDescriptor(descr) ? descr : PNone.NO_VALUE;
}

// Strings are by far the most common builtin objects on which we look up methods
@ForceQuickening
@Specialization(guards = "!isNoValue(result)", excludeForUncached = false)
public static Object doStringFastPath(VirtualFrame frame, TruffleString name, TruffleString obj,
@Cached(value = "findStringMethod($node, name)", allowUncached = true, weak = true) Object result) {
return result;
}

@ForceQuickening
@Specialization(guards = {
"!hasMaterializedDict(cachedShape)", "managedClass != null || isBuiltinWithObjectOrModuleGetattro(cachedShape)", //
"cachedShape.check(obj)", "result != null"}, limit = "2", excludeForUncached = true)
public static Object doFastPath(VirtualFrame frame,
TruffleString name, PythonObject obj,
@Bind Node inliningTarget,
@Cached("obj.getShape()") Shape cachedShape,
@Cached(value = "getManagedClassOrNull(cachedShape)", weak = true) PythonManagedClass managedClass,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, name)") PropertyGetter cachedPropertyGetter,
@Cached InlineWeakValueProfile slotsValueProfile,
@Cached InlinedBranchProfile hasInstanceValueBranchProfile,
@Cached LookupAttributeInMRONode.CachedKeyFastPath getMethod,
@Bind("getMethodFastPath(obj, name, inliningTarget, managedClass, cachedShape, cachedPropertyGetter, slotsValueProfile, hasInstanceValueBranchProfile, getMethod)") Object result) {
assert obj.checkDictFlags();
return result;
}

static Object getMethodFastPath(PythonObject obj, TruffleString name, Node inliningTarget, PythonManagedClass managedClass, Shape cachedShape, PropertyGetter cachedPropertyGetter,
InlineWeakValueProfile slotsValueProfile, InlinedBranchProfile hasInstanceValueBranchProfile, LookupAttributeInMRONode.CachedKeyFastPath getMethod) {
if (managedClass != null) {
if (!GetAttribute.hasObjectOrModuleGetattro(inliningTarget, managedClass, slotsValueProfile)) {
return null;
}
}
Object descr = getMethod.execute(inliningTarget, cachedShape.getDynamicType(), name);
if (descr == null || (descr != PNone.NO_VALUE && !MaybeBindDescriptorNode.isMethodDescriptor(descr))) {
return null;
}
if (cachedPropertyGetter != null) {
assert obj.checkDictFlags();
Object instanceValue = cachedPropertyGetter.get(obj);
if (instanceValue != PNone.NO_VALUE) {
hasInstanceValueBranchProfile.enter(inliningTarget);
return new BoundDescriptor(instanceValue);
}
}
return descr != PNone.NO_VALUE ? descr : null;
}

@Specialization(replaces = {"doStringFastPath", "doFastPath"})
public static Object doIt(VirtualFrame frame,
TruffleString name, Object obj,
@Bind Node inliningTarget,
Expand Down
Loading