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 ;
56
69
import com .oracle .truffle .api .frame .Frame ;
57
70
import com .oracle .truffle .api .frame .VirtualFrame ;
58
71
import com .oracle .truffle .api .nodes .Node ;
72
+ import com .oracle .truffle .api .profiles .ConditionProfile ;
59
73
60
74
/**
61
75
* Equivalent to use for the various PyObject_LookupAttr* functions available in CPython. Note that
66
80
* doesn't exist.
67
81
*/
68
82
@ GenerateUncached
69
- @ ImportStatic (SpecialMethodSlot .class )
83
+ @ ImportStatic ({SpecialMethodSlot .class , SpecialMethodNames .class , PGuards .class })
84
+
70
85
public abstract class PyObjectLookupAttr extends Node {
86
+ private static final BuiltinMethodDescriptor OBJ_GET_ATTRIBUTE = BuiltinMethodDescriptor .get (ObjectBuiltinsFactory .GetAttributeNodeFactory .getInstance (), PythonBuiltinClassType .PythonObject );
87
+ private static final BuiltinMethodDescriptor MODULE_GET_ATTRIBUTE = BuiltinMethodDescriptor .get (ModuleBuiltinsFactory .ModuleGetattritbuteNodeFactory .getInstance (),
88
+ PythonBuiltinClassType .PythonModule );
89
+ private static final BuiltinMethodDescriptor TYPE_GET_ATTRIBUTE = BuiltinMethodDescriptor .get (TypeBuiltinsFactory .GetattributeNodeFactory .getInstance (), PythonBuiltinClassType .PythonClass );
90
+
71
91
public abstract Object execute (Frame frame , Object receiver , Object name );
72
92
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 ;
93
+ protected static boolean hasNoGetattr (Object lazyClass ) {
94
+ Object slotValue = null ;
95
+ if (lazyClass instanceof PythonBuiltinClassType ) {
96
+ slotValue = SpecialMethodSlot .GetAttr .getValue ((PythonBuiltinClassType ) lazyClass );
97
+ } else if (lazyClass instanceof PythonManagedClass ) {
98
+ slotValue = SpecialMethodSlot .GetAttr .getValue ((PythonManagedClass ) lazyClass );
99
+ }
100
+ return slotValue == PNone .NO_VALUE ;
101
+ }
102
+
103
+ protected static boolean getAttributeIs (Object lazyClass , BuiltinMethodDescriptor expected ) {
104
+ Object slotValue = null ;
105
+ if (lazyClass instanceof PythonBuiltinClassType ) {
106
+ slotValue = SpecialMethodSlot .GetAttribute .getValue ((PythonBuiltinClassType ) lazyClass );
107
+ } else if (lazyClass instanceof PythonManagedClass ) {
108
+ slotValue = SpecialMethodSlot .GetAttribute .getValue ((PythonManagedClass ) lazyClass );
109
+ }
110
+ return slotValue == expected ;
111
+ }
112
+
113
+ protected static boolean isObjectGetAttribute (Object lazyClass ) {
114
+ return getAttributeIs (lazyClass , OBJ_GET_ATTRIBUTE );
115
+ }
116
+
117
+ protected static boolean isModuleGetAttribute (Object lazyClass ) {
118
+ return getAttributeIs (lazyClass , MODULE_GET_ATTRIBUTE );
119
+ }
120
+
121
+ protected static boolean isTypeGetAttribute (Object lazyClass ) {
122
+ return getAttributeIs (lazyClass , TYPE_GET_ATTRIBUTE );
123
+ }
124
+
125
+ // simple version that needs no calls and only reads from the object directly
126
+ @ SuppressWarnings ("unused" )
127
+ @ Specialization (guards = {"isObjectGetAttribute(type)" , "hasNoGetattr(type)" , "name == cachedName" , "isNoValue(descr)" })
128
+ static final Object doBuiltinObject (VirtualFrame frame , Object object , String name ,
129
+ @ Cached ("name" ) String cachedName ,
130
+ @ Cached GetClassNode getClass ,
131
+ @ Bind ("getClass.execute(object)" ) Object type ,
132
+ @ Cached ("create(name)" ) LookupAttributeInMRONode lookupName ,
133
+ @ Bind ("lookupName.execute(type)" ) Object descr ,
134
+ @ Cached ReadAttributeFromObjectNode readNode ) {
135
+ return readNode .execute (object , cachedName );
136
+ }
137
+
138
+ // simple version that needs no calls and only reads from the object directly. the only
139
+ // difference for module.__getattribute__ over object.__getattribute__ is that it looks for a
140
+ // module-level __getattr__ as well
141
+ @ SuppressWarnings ("unused" )
142
+ @ Specialization (guards = {"isModuleGetAttribute(type)" , "hasNoGetattr(type)" , "name == cachedName" , "isNoValue(descr)" }, limit = "1" )
143
+ static final Object doBuiltinModule (VirtualFrame frame , Object object , String name ,
144
+ @ Cached ("name" ) String cachedName ,
145
+ @ Cached GetClassNode getClass ,
146
+ @ Bind ("getClass.execute(object)" ) Object type ,
147
+ @ Cached ("create(name)" ) LookupAttributeInMRONode lookupName ,
148
+ @ Bind ("lookupName.execute(type)" ) Object descr ,
149
+ @ Cached ReadAttributeFromObjectNode readNode ,
150
+ @ Cached ReadAttributeFromObjectNode readGetattr ,
151
+ @ Shared ("errorProfile" ) @ Cached IsBuiltinClassProfile errorProfile ,
152
+ @ Cached ConditionProfile noValueFound ,
153
+ @ Cached CallNode callGetattr ) {
154
+ Object value = readNode .execute (object , cachedName );
155
+ if (noValueFound .profile (value == PNone .NO_VALUE )) {
156
+ Object getAttr = readGetattr .execute (object , SpecialMethodNames .__GETATTR__ );
157
+ if (getAttr != PNone .NO_VALUE ) {
158
+ // (tfel): I'm not profiling this, since modules with __getattr__ are kind of rare
159
+ try {
160
+ return callGetattr .execute (frame , getAttr , name );
161
+ } catch (PException e ) {
162
+ e .expect (PythonBuiltinClassType .AttributeError , errorProfile );
163
+ return PNone .NO_VALUE ;
164
+ }
165
+ } else {
166
+ return PNone .NO_VALUE ;
167
+ }
168
+ } else {
169
+ return value ;
83
170
}
84
171
}
85
172
86
- @ Specialization (replaces = "getFixedAttr" )
173
+ // simple version that needs no calls and only reads from the object directly. the only
174
+ // difference for type.__getattribute__ over object.__getattribute__ is that it looks for a
175
+ // __get__ method on the value and invokes it if it is callable.
176
+ @ SuppressWarnings ("unused" )
177
+ @ Specialization (guards = {"isTypeGetAttribute(type)" , "hasNoGetattr(type)" , "name == cachedName" , "isNoValue(descr)" }, limit = "1" )
178
+ static final Object doBuiltinType (VirtualFrame frame , Object object , String name ,
179
+ @ Cached ("name" ) String cachedName ,
180
+ @ Cached GetClassNode getClass ,
181
+ @ Bind ("getClass.execute(object)" ) Object type ,
182
+ @ Cached ("create(name)" ) LookupAttributeInMRONode lookupName ,
183
+ @ Bind ("lookupName.execute(type)" ) Object descr ,
184
+ @ Cached ReadAttributeFromObjectNode readNode ,
185
+ @ Cached ConditionProfile valueFound ,
186
+ @ Cached ("create(__GET__)" ) LookupInheritedAttributeNode lookupValueGet ,
187
+ @ Cached ConditionProfile noGetMethod ,
188
+ @ Cached CallTernaryMethodNode invokeValueGet ,
189
+ @ Shared ("errorProfile" ) @ Cached IsBuiltinClassProfile errorProfile ) {
190
+ Object value = readNode .execute (object , cachedName );
191
+ if (valueFound .profile (value != PNone .NO_VALUE )) {
192
+ Object valueGet = lookupValueGet .execute (value );
193
+ if (noGetMethod .profile (valueGet == PNone .NO_VALUE )) {
194
+ return value ;
195
+ } else if (PGuards .isCallable (valueGet )) {
196
+ try {
197
+ return invokeValueGet .execute (frame , valueGet , value , PNone .NONE , object );
198
+ } catch (PException e ) {
199
+ e .expect (PythonBuiltinClassType .AttributeError , errorProfile );
200
+ return PNone .NO_VALUE ;
201
+ }
202
+ }
203
+ }
204
+ return PNone .NO_VALUE ;
205
+ }
206
+
207
+ @ Specialization (replaces = {"doBuiltinObject" , "doBuiltinModule" , "doBuiltinType" })
87
208
static Object getDynamicAttr (Frame frame , Object receiver , Object name ,
88
209
@ Cached GetClassNode getClass ,
89
210
@ Cached (parameters = "GetAttribute" ) LookupSpecialMethodSlotNode lookupGetattribute ,
90
211
@ Cached (parameters = "GetAttr" ) LookupSpecialMethodSlotNode lookupGetattr ,
91
212
@ Cached CallBinaryMethodNode callGetattribute ,
92
213
@ Cached CallBinaryMethodNode callGetattr ,
93
- @ Cached IsBuiltinClassProfile errorProfile ) {
214
+ @ Shared ( "errorProfile" ) @ Cached IsBuiltinClassProfile errorProfile ) {
94
215
Object type = getClass .execute (receiver );
95
216
Object getattribute = lookupGetattribute .execute (frame , type , receiver );
96
217
try {
@@ -101,7 +222,7 @@ static Object getDynamicAttr(Frame frame, Object receiver, Object name,
101
222
Object getattr = lookupGetattr .execute (frame , type , receiver );
102
223
if (getattr != PNone .NO_VALUE ) {
103
224
try {
104
- return callGetattr .executeObject (frame , getattr , name );
225
+ return callGetattr .executeObject (frame , getattr , receiver , name );
105
226
} catch (PException e ) {
106
227
e .expect (PythonBuiltinClassType .AttributeError , errorProfile );
107
228
}
0 commit comments