1 Namespace Definition
2 ====================
3
4 Module attributes are defined either at the module level or by global
5 statements.
6
7 Class attributes are defined only within class statements.
8
9 Instance attributes are defined only by assignments to attributes of self
10 within __init__ methods.
11
12 Data Structures
13 ===============
14
15 Since classes, functions and instances are all "objects", each must support
16 certain features and operations in the same way.
17
18 The __class__ Attribute
19 -----------------------
20
21 All objects support the __class__ attribute:
22
23 Class: refers to the type class (type.__class__ also refers to the type class)
24 Function: refers to the function class
25 Instance: refers to the class instantiated to make the object
26
27 Invocation
28 ----------
29
30 The following actions need to be supported:
31
32 Class: create instance, call __init__ with instance, return object
33 Function: call function body, return result
34 Instance: call __call__ method, return result
35
36 Structure Layout
37 ----------------
38
39 A suitable structure layout might be something like this:
40
41 0 1 2 3 4
42 classcode invocation __class__ attribute ...
43 reference reference reference
44
45 Here, the classcode refers to the attribute lookup table for the object. Since
46 classes and instances share the same classcode, they might resemble the
47 following:
48
49 Class C:
50
51 0 1 2 3 4
52 code for C __new__ class type attribute ...
53 reference reference reference
54
55 Instance of C:
56
57 0 1 2 3 4
58 code for C C.__call__ class C attribute ...
59 reference reference reference
60 (if exists)
61
62 The __new__ reference would lead to code consisting of the following
63 instructions:
64
65 create instance for C
66 call C.__init__(instance, ...)
67 return instance
68
69 If C has a __call__ attribute, the invocation "slot" of C instances would
70 refer to the same thing as C.__call__.
71
72 For functions, the same general layout applies:
73
74 Function f:
75
76 0 1 2 3 4
77 code for code class attribute ...
78 function reference function reference
79 reference
80
81 Here, the code reference would lead to code for the function.
82
83 Invocation Operation
84 --------------------
85
86 Consequently, regardless of the object an invocation is always done as
87 follows:
88
89 get invocation reference (at object+1)
90 jump to reference
91
92 Additional preparation is necessary before the above code: positional
93 arguments must be saved to the parameter stack, and keyword arguments must be
94 resolved and saved to the appropriate position in the parameter stack.
95
96 Attribute Operations
97 --------------------
98
99 Attribute access needs to go through the attribute lookup table.
100
101 Instruction Evaluation Model
102 ============================
103
104 Programs use a value stack where evaluated instructions may save their
105 results. A value stack pointer indicates the top of this stack. In addition, a
106 separate stack is used to record the invocation frames. All stack pointers
107 refer to the next address to be used by the stack, not the address of the
108 uppermost element.
109
110 Frame Stack Value Stack
111 ----------- ----------- Address of Callable
112 -------------------
113 previous ...
114 current ------> callable -----> identifier
115 arg1 reference to code
116 arg2
117 arg3
118 local4
119 local5
120 ...
121
122 Loading local names is a matter of performing frame-relative accesses to the
123 value stack.
124
125 Invocations and Argument Evaluation
126 -----------------------------------
127
128 When preparing for an invocation, the caller first sets the invocation frame
129 pointer. Then, positional arguments are added to the stack such that the first
130 argument positions are filled. A number of stack locations for the remaining
131 arguments specified in the program are then reserved. The names of keyword
132 arguments are used (in the form of table index values) to consult the
133 parameter table and to find the location in which such arguments are to be
134 stored.
135
136 fn(a, b, d=1, e=2, c=3) -> fn(a, b, c, d, e)
137
138 Value Stack
139 -----------
140
141 ... ... ... ...
142 fn fn fn fn
143 a a a a
144 b b b b
145 ___ ___ ___ --> 3
146 ___ --> 1 1 | 1
147 ___ | ___ --> 2 | 2
148 1 ----------- 2 ----------- 3 -----------
149
150 Conceptually, the frame can be considered as a collection of attributes, as
151 seen in other kinds of structures:
152
153 Frame for invocation of fn:
154
155 0 1 2 3 4 5
156 code a b c d e
157 reference
158
159 However, where arguments are specified positionally, such "attributes" are not
160 set using a comparable approach to that employed with other structures.
161 Keyword arguments are set using an attribute-like mechanism, though, where the
162 position of each argument discovered using the parameter table.
163
164 Tuples, Frames and Allocation
165 -----------------------------
166
167 Using the approach where arguments are treated like attributes in some kind of
168 structure, we could choose to allocate frames in places other than a stack.
169 This would produce something somewhat similar to a plain tuple object.
170
171 Optimisations
172 =============
173
174 Some optimisations around constant objects might be possible; these depend on
175 the following:
176
177 * Reliable tracking of assignments: where assignment operations occur, the
178 target of the assignment should be determined if any hope of optimisation
179 is to be maintained. Where no guarantees can be made about the target of
180 an assignment, no assignment-related information should be written to
181 potential targets.
182
183 * Objects acting as "containers" of attributes must be regarded as "safe":
184 where assignments are recorded as occurring on an attribute, it must be
185 guaranteed that no other unforeseen ways exist to assign to such
186 attributes.
187
188 The discussion below presents certain rules which must be imposed to uphold
189 the above requirements.
190
191 Constant Attributes
192 -------------------
193
194 Where attributes of modules, classes and instances are only set once and are
195 effectively constant, it should be possible to circumvent the attribute lookup
196 mechanism and to directly reference the attribute value. This technique may
197 only be considered applicable in the following cases for "container" objects:
198
199 1. For modules, provided that assignments to module attributes are only
200 permitted within the module itself either at the top-level or via names
201 declared as globals. Thus, the following would not be permitted:
202
203 another_module.this_module.attr = value
204
205 In the above, this_module is a reference to the current module.
206
207 2. For classes, provided that assignments to class attributes are only
208 permitted within the class definition, outside methods. This would mean
209 that classes would be "sealed" at definition time (like functions).
210
211 Unlike the property of function locals that they may only sensibly be accessed
212 within the function in which they reside, these cases demand additional
213 controls or assumptions on or about access to the stored data. Meanwhile, it
214 would be difficult to detect eligible attributes on arbitrary instances due to
215 the need for some kind of type inference or abstract execution.
216
217 Where (1) and (2) apply, any attribute with only one recorded assignment on it
218 can be considered a constant attribute and this eligible for this
219 optimisation, the consequence of which would be the replacement of a
220 LoadAttrIndex instruction (which needs to look up an attribute using the
221 run-time details of the "container" and the compile-time details of the
222 attribute) with a LoadAttr instruction.
223
224 Additional Controls
225 -------------------
226
227 For the above cases for "container" objects, the following controls would need
228 to apply:
229
230 1. Modules would need to be immutable after initialisation. However, during
231 initialisation, there remains a possibility of another module attempting
232 to access the original module. For example, if ppp/__init__.py contained
233 the following...
234
235 x = 1
236 import ppp.qqq
237 print x
238
239 ...and if ppp/qqq.py contained the following...
240
241 import ppp
242 ppp.x = 2
243
244 ...then the value 2 would be printed. Since modules are objects which are
245 registered globally in a program, it would be possible to set attributes
246 in the above way.
247
248 2. Classes would need to be immutable after initialisation. However, since
249 classes are objects, any reference to a class after initialisation could
250 be used to set attributes on the class.
251
252 Solutions:
253
254 1. Insist on global scope for module attribute assignments.
255
256 2. Insist on local scope within classes.
257
258 Both of the above measures need to be enforced at run-time, since an arbitrary
259 attribute assignment could be attempted on any kind of object, yet to uphold
260 the properties of "safe containers", attempts to change attributes of such
261 objects should be denied. Since foreseen attribute assignment operations have
262 certain properties detectable at compile-time, it could be appropriate to
263 generate special instructions (or modified instructions) during the
264 initialisation of modules and classes for such foreseen assignments, whilst
265 employing normal attribute assignment operations in all other cases. Indeed,
266 the StoreAttr instruction, which is used to set attributes in "safe
267 containers" would be used exclusively for this purpose; the StoreAttrIndex
268 instruction would be used exclusively for all other attribute assignments.
269
270 Constant Attribute Values
271 -------------------------
272
273 Where an attribute value is itself regarded as constant, is a "safe container"
274 and is used in an operation accessing its own attributes, the value can be
275 directly inspected for optimisations or employed in the generated code. For
276 the attribute values themselves, only objects of a constant nature may be
277 considered suitable for this particular optimisation:
278
279 * Classes
280 * Modules
281 * Instances defined as constant literals
282
283 This is because arbitrary objects (such as most instances) have no
284 well-defined form before run-time and cannot be investigated further at
285 compile-time or have a representation inserted into the generated code.
286
287 Class Attributes and Access via Instances
288 -----------------------------------------
289
290 Unlike module attributes, class attributes can be accessed in a number of
291 different ways:
292
293 * Using the class itself:
294
295 C.x = 123
296 cls = C; cls.x = 234
297
298 * Using a subclass of the class (for reading attributes):
299
300 class D(C):
301 pass
302 D.x # setting D.x would populate D, not C
303
304 * Using instances of the class or a subclass of the class (for reading
305 attributes):
306
307 c = C()
308 c.x # setting c.x would populate c, not C
309
310 Since assignments are only achieved using direct references to the class, and
311 since class attributes should be defined only within the class initialisation
312 process, the properties of class attributes should be consistent with those
313 desired.
314
315 Method Access via Instances
316 ---------------------------
317
318 It is desirable to optimise method access, even though most method calls are
319 likely to occur via instances. It is possible, given the properties of methods
320 as class attributes to investigate the kind of instance that the self
321 parameter/local refers to within each method: it should be an instance either
322 of the class in which the method is defined or a compatible class, although
323 situations exist where this might not be the case:
324
325 * Explicit invocation of a method:
326
327 d = D() # D is not related to C
328 C.f(d) # calling f(self) in C
329
330 Optimising Function Invocations
331 -------------------------------
332
333 Where an attribute value is itself regarded as constant and is a function,
334 knowledge about the parameters of the function can be employed to optimise the
335 preparation of the invocation frame.