|
42 | 42 |
|
43 | 43 | import com.oracle.graal.python.builtins.PythonBuiltinClassType;
|
44 | 44 | import com.oracle.graal.python.builtins.objects.PNone;
|
| 45 | +import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor; |
| 46 | +import com.oracle.graal.python.builtins.objects.module.ModuleBuiltinsFactory; |
| 47 | +import com.oracle.graal.python.builtins.objects.object.ObjectBuiltinsFactory; |
| 48 | +import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; |
45 | 49 | import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
|
46 |
| -import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetFixedAttributeNode; |
| 50 | +import com.oracle.graal.python.builtins.objects.type.TypeBuiltinsFactory; |
| 51 | +import com.oracle.graal.python.nodes.PGuards; |
| 52 | +import com.oracle.graal.python.nodes.SpecialMethodNames; |
| 53 | +import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode; |
| 54 | +import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode; |
| 55 | +import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode; |
| 56 | +import com.oracle.graal.python.nodes.call.CallNode; |
47 | 57 | import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
|
| 58 | +import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode; |
48 | 59 | import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodSlotNode;
|
49 | 60 | import com.oracle.graal.python.nodes.object.GetClassNode;
|
50 | 61 | import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
|
51 | 62 | import com.oracle.graal.python.runtime.exception.PException;
|
| 63 | +import com.oracle.truffle.api.dsl.Bind; |
52 | 64 | import com.oracle.truffle.api.dsl.Cached;
|
| 65 | +import com.oracle.truffle.api.dsl.Cached.Shared; |
53 | 66 | import com.oracle.truffle.api.dsl.GenerateUncached;
|
54 | 67 | import com.oracle.truffle.api.dsl.ImportStatic;
|
55 | 68 | import com.oracle.truffle.api.dsl.Specialization;
|
|
66 | 79 | * doesn't exist.
|
67 | 80 | */
|
68 | 81 | @GenerateUncached
|
69 |
| -@ImportStatic(SpecialMethodSlot.class) |
| 82 | +@ImportStatic({SpecialMethodSlot.class, SpecialMethodNames.class, PGuards.class}) |
| 83 | + |
70 | 84 | public abstract class PyObjectLookupAttr extends Node {
|
| 85 | + private static final BuiltinMethodDescriptor OBJ_GET_ATTRIBUTE = BuiltinMethodDescriptor.get(ObjectBuiltinsFactory.GetAttributeNodeFactory.getInstance(), PythonBuiltinClassType.PythonObject); |
| 86 | + private static final BuiltinMethodDescriptor MODULE_GET_ATTRIBUTE = BuiltinMethodDescriptor.get(ModuleBuiltinsFactory.ModuleGetattritbuteNodeFactory.getInstance(), PythonBuiltinClassType.PythonModule); |
| 87 | + private static final BuiltinMethodDescriptor TYPE_GET_ATTRIBUTE = BuiltinMethodDescriptor.get(TypeBuiltinsFactory.GetattributeNodeFactory.getInstance(), PythonBuiltinClassType.PythonClass); |
| 88 | + |
71 | 89 | public abstract Object execute(Frame frame, Object receiver, Object name);
|
72 | 90 |
|
73 |
| - @Specialization(guards = "name == cachedName", limit = "1") |
74 |
| - static Object getFixedAttr(VirtualFrame frame, Object receiver, @SuppressWarnings("unused") String name, |
75 |
| - @SuppressWarnings("unused") @Cached("name") String cachedName, |
76 |
| - @Cached("create(name)") GetFixedAttributeNode getAttrNode, |
77 |
| - @Cached IsBuiltinClassProfile errorProfile) { |
78 |
| - try { |
79 |
| - return getAttrNode.execute(frame, receiver); |
80 |
| - } catch (PException e) { |
81 |
| - e.expect(PythonBuiltinClassType.AttributeError, errorProfile); |
82 |
| - return PNone.NO_VALUE; |
| 91 | + protected static boolean hasNoGetattr(Object lazyClass) { |
| 92 | + Object slotValue = null; |
| 93 | + if (lazyClass instanceof PythonBuiltinClassType) { |
| 94 | + slotValue = SpecialMethodSlot.GetAttr.getValue((PythonBuiltinClassType) lazyClass); |
| 95 | + } else if (lazyClass instanceof PythonManagedClass) { |
| 96 | + slotValue = SpecialMethodSlot.GetAttr.getValue((PythonManagedClass) lazyClass); |
| 97 | + } |
| 98 | + return slotValue == PNone.NO_VALUE; |
| 99 | + } |
| 100 | + |
| 101 | + protected static boolean getAttributeIs(Object lazyClass, BuiltinMethodDescriptor expected) { |
| 102 | + Object slotValue = null; |
| 103 | + if (lazyClass instanceof PythonBuiltinClassType) { |
| 104 | + slotValue = SpecialMethodSlot.GetAttribute.getValue((PythonBuiltinClassType) lazyClass); |
| 105 | + } else if (lazyClass instanceof PythonManagedClass) { |
| 106 | + slotValue = SpecialMethodSlot.GetAttribute.getValue((PythonManagedClass) lazyClass); |
| 107 | + } |
| 108 | + return slotValue == expected; |
| 109 | + } |
| 110 | + |
| 111 | + protected static boolean isObjectGetAttribute(Object lazyClass) { |
| 112 | + return getAttributeIs(lazyClass, OBJ_GET_ATTRIBUTE); |
| 113 | + } |
| 114 | + |
| 115 | + protected static boolean isModuleGetAttribute(Object lazyClass) { |
| 116 | + return getAttributeIs(lazyClass, MODULE_GET_ATTRIBUTE); |
| 117 | + } |
| 118 | + |
| 119 | + protected static boolean isTypeGetAttribute(Object lazyClass) { |
| 120 | + return getAttributeIs(lazyClass, TYPE_GET_ATTRIBUTE); |
| 121 | + } |
| 122 | + |
| 123 | + // simple version that needs no calls and only reads from the object directly |
| 124 | + @SuppressWarnings("unused") |
| 125 | + @Specialization(guards = {"isObjectGetAttribute(type)", "hasNoGetattr(type)", "name == cachedName", "isNoValue(descr)"}) |
| 126 | + static final Object doBuiltinObject(VirtualFrame frame, Object object, String name, |
| 127 | + @Cached("name") String cachedName, |
| 128 | + @Cached GetClassNode getClass, |
| 129 | + @Bind("getClass.execute(object)") Object type, |
| 130 | + @Cached("create(name)") LookupAttributeInMRONode lookupName, |
| 131 | + @Bind("lookupName.execute(type)") Object descr, |
| 132 | + @Cached ReadAttributeFromObjectNode readNode) { |
| 133 | + return readNode.execute(object, cachedName); |
| 134 | + } |
| 135 | + |
| 136 | + // simple version that needs no calls and only reads from the object directly. the only |
| 137 | + // difference for module.__getattribute__ over object.__getattribute__ is that it looks for a |
| 138 | + // module-level __getattr__ as well |
| 139 | + @SuppressWarnings("unused") |
| 140 | + @Specialization(guards = {"isModuleGetAttribute(type)", "hasNoGetattr(type)", "name == cachedName", "isNoValue(descr)"}, limit = "1") |
| 141 | + static final Object doBuiltinModule(VirtualFrame frame, Object object, String name, |
| 142 | + @Cached("name") String cachedName, |
| 143 | + @Cached GetClassNode getClass, |
| 144 | + @Bind("getClass.execute(object)") Object type, |
| 145 | + @Cached("create(name)") LookupAttributeInMRONode lookupName, |
| 146 | + @Bind("lookupName.execute(type)") Object descr, |
| 147 | + @Cached ReadAttributeFromObjectNode readNode, |
| 148 | + @Cached ReadAttributeFromObjectNode readGetattr, |
| 149 | + @Shared("errorProfile") @Cached IsBuiltinClassProfile errorProfile, |
| 150 | + @Cached CallNode callGetattr) { |
| 151 | + Object value = readNode.execute(object, cachedName); |
| 152 | + if (value == PNone.NO_VALUE) { |
| 153 | + Object getAttr = readGetattr.execute(object, SpecialMethodNames.__GETATTR__); |
| 154 | + if (getAttr != PNone.NO_VALUE) { |
| 155 | + try { |
| 156 | + return callGetattr.execute(frame, getAttr, name); |
| 157 | + } catch (PException e) { |
| 158 | + e.expect(PythonBuiltinClassType.AttributeError, errorProfile); |
| 159 | + return PNone.NO_VALUE; |
| 160 | + } |
| 161 | + } else { |
| 162 | + return PNone.NO_VALUE; |
| 163 | + } |
| 164 | + } else { |
| 165 | + return value; |
83 | 166 | }
|
84 | 167 | }
|
85 | 168 |
|
86 |
| - @Specialization(replaces = "getFixedAttr") |
| 169 | + // simple version that needs no calls and only reads from the object directly. the only |
| 170 | + // difference for type.__getattribute__ over object.__getattribute__ is that it looks for a |
| 171 | + // __get__ method on the value and invokes it if it is callable. |
| 172 | + @SuppressWarnings("unused") |
| 173 | + @Specialization(guards = {"isTypeGetAttribute(type)", "hasNoGetattr(type)", "name == cachedName", "isNoValue(descr)"}, limit = "1") |
| 174 | + static final Object doBuiltinType(VirtualFrame frame, Object object, String name, |
| 175 | + @Cached("name") String cachedName, |
| 176 | + @Cached GetClassNode getClass, |
| 177 | + @Bind("getClass.execute(object)") Object type, |
| 178 | + @Cached("create(name)") LookupAttributeInMRONode lookupName, |
| 179 | + @Bind("lookupName.execute(type)") Object descr, |
| 180 | + @Cached ReadAttributeFromObjectNode readNode, |
| 181 | + @Cached ReadAttributeFromObjectNode readGetattr, |
| 182 | + @Cached("create(__GET__)") LookupInheritedAttributeNode lookupValueGet, |
| 183 | + @Cached CallTernaryMethodNode invokeValueGet, |
| 184 | + @Shared("errorProfile") @Cached IsBuiltinClassProfile errorProfile, |
| 185 | + @Cached CallNode callGetattr) { |
| 186 | + Object value = readNode.execute(object, cachedName); |
| 187 | + if (value != PNone.NO_VALUE) { |
| 188 | + Object valueGet = lookupValueGet.execute(value); |
| 189 | + if (valueGet == PNone.NO_VALUE) { |
| 190 | + return value; |
| 191 | + } else if (PGuards.isCallable(valueGet)) { |
| 192 | + try { |
| 193 | + return invokeValueGet.execute(frame, valueGet, value, PNone.NONE, object); |
| 194 | + } catch (PException e) { |
| 195 | + e.expect(PythonBuiltinClassType.AttributeError, errorProfile); |
| 196 | + return PNone.NO_VALUE; |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + return PNone.NO_VALUE; |
| 201 | + } |
| 202 | + |
| 203 | + @Specialization(replaces = {"doBuiltinObject", "doBuiltinModule", "doBuiltinType"}) |
87 | 204 | static Object getDynamicAttr(Frame frame, Object receiver, Object name,
|
88 | 205 | @Cached GetClassNode getClass,
|
89 | 206 | @Cached(parameters = "GetAttribute") LookupSpecialMethodSlotNode lookupGetattribute,
|
90 | 207 | @Cached(parameters = "GetAttr") LookupSpecialMethodSlotNode lookupGetattr,
|
91 | 208 | @Cached CallBinaryMethodNode callGetattribute,
|
92 | 209 | @Cached CallBinaryMethodNode callGetattr,
|
93 |
| - @Cached IsBuiltinClassProfile errorProfile) { |
| 210 | + @Shared("errorProfile") @Cached IsBuiltinClassProfile errorProfile) { |
94 | 211 | Object type = getClass.execute(receiver);
|
95 | 212 | Object getattribute = lookupGetattribute.execute(frame, type, receiver);
|
96 | 213 | try {
|
|
0 commit comments