micropython

Annotated README.txt

231:b8fea0931697
2009-05-30 Paul Boddie Split the descendant of the old classes test into two more specific tests of attribute binding and methods/callables.
paul@23 1
Optimisations
paul@23 2
=============
paul@23 3
paul@29 4
Some optimisations around constant objects might be possible; these depend on
paul@29 5
the following:
paul@29 6
paul@29 7
  * Reliable tracking of assignments: where assignment operations occur, the
paul@29 8
    target of the assignment should be determined if any hope of optimisation
paul@29 9
    is to be maintained. Where no guarantees can be made about the target of
paul@29 10
    an assignment, no assignment-related information should be written to
paul@29 11
    potential targets.
paul@29 12
paul@29 13
  * Objects acting as "containers" of attributes must be regarded as "safe":
paul@29 14
    where assignments are recorded as occurring on an attribute, it must be
paul@29 15
    guaranteed that no other unforeseen ways exist to assign to such
paul@29 16
    attributes.
paul@29 17
paul@29 18
The discussion below presents certain rules which must be imposed to uphold
paul@29 19
the above requirements.
paul@29 20
paul@30 21
Safe Containers
paul@30 22
---------------
paul@28 23
paul@23 24
Where attributes of modules, classes and instances are only set once and are
paul@23 25
effectively constant, it should be possible to circumvent the attribute lookup
paul@28 26
mechanism and to directly reference the attribute value. This technique may
paul@30 27
only be considered applicable for the following "container" objects, subject
paul@30 28
to the noted constraints:
paul@28 29
paul@30 30
 1. For modules, "safety" is enforced by ensuring that assignments to module
paul@30 31
    attributes are only permitted within the module itself either at the
paul@30 32
    top-level or via names declared as globals. Thus, the following would not
paul@30 33
    be permitted:
paul@28 34
paul@28 35
    another_module.this_module.attr = value
paul@28 36
paul@29 37
    In the above, this_module is a reference to the current module.
paul@28 38
paul@30 39
 2. For classes, "safety" is enforced by ensuring that assignments to class
paul@30 40
    attributes are only permitted within the class definition, outside
paul@30 41
    methods. This would mean that classes would be "sealed" at definition time
paul@30 42
    (like functions).
paul@28 43
paul@28 44
Unlike the property of function locals that they may only sensibly be accessed
paul@28 45
within the function in which they reside, these cases demand additional
paul@28 46
controls or assumptions on or about access to the stored data. Meanwhile, it
paul@28 47
would be difficult to detect eligible attributes on arbitrary instances due to
paul@28 48
the need for some kind of type inference or abstract execution.
paul@28 49
paul@30 50
Constant Attributes
paul@30 51
-------------------
paul@30 52
paul@30 53
When accessed via "safe containers", as described above, any attribute with
paul@30 54
only one recorded assignment on it can be considered a constant attribute and
paul@30 55
this eligible for optimisation, the consequence of which would be the
paul@30 56
replacement of a LoadAttrIndex instruction (which needs to look up an
paul@30 57
attribute using the run-time details of the "container" and the compile-time
paul@30 58
details of the attribute) with a LoadAttr instruction.
paul@30 59
paul@30 60
However, some restrictions exist on assignment operations which may be
paul@30 61
regarded to cause only one assignment in the lifetime of a program:
paul@30 62
paul@30 63
 1. For module attributes, only assignments at the top-level outside loop
paul@30 64
    statements can be reliably assumed to cause only a single assignment.
paul@30 65
paul@30 66
 2. For class attributes, only assignments at the top-level within class
paul@30 67
    definitions and outside loop statements can be reliably assumed to cause
paul@30 68
    only a single assignment.
paul@30 69
paul@30 70
All assignments satisfying the "safe container" requirements, but not the
paul@30 71
requirements immediately above, should each be recorded as causing at least
paul@30 72
one assignment.
paul@28 73
paul@29 74
Additional Controls
paul@29 75
-------------------
paul@29 76
paul@29 77
For the above cases for "container" objects, the following controls would need
paul@29 78
to apply:
paul@29 79
paul@29 80
 1. Modules would need to be immutable after initialisation. However, during
paul@29 81
    initialisation, there remains a possibility of another module attempting
paul@29 82
    to access the original module. For example, if ppp/__init__.py contained
paul@29 83
    the following...
paul@29 84
paul@29 85
    x = 1
paul@29 86
    import ppp.qqq
paul@29 87
    print x
paul@29 88
paul@29 89
    ...and if ppp/qqq.py contained the following...
paul@29 90
paul@29 91
    import ppp
paul@29 92
    ppp.x = 2
paul@29 93
paul@29 94
    ...then the value 2 would be printed. Since modules are objects which are
paul@29 95
    registered globally in a program, it would be possible to set attributes
paul@29 96
    in the above way.
paul@29 97
paul@29 98
 2. Classes would need to be immutable after initialisation. However, since
paul@29 99
    classes are objects, any reference to a class after initialisation could
paul@29 100
    be used to set attributes on the class.
paul@29 101
paul@29 102
Solutions:
paul@29 103
paul@29 104
 1. Insist on global scope for module attribute assignments.
paul@29 105
paul@29 106
 2. Insist on local scope within classes.
paul@29 107
paul@29 108
Both of the above measures need to be enforced at run-time, since an arbitrary
paul@29 109
attribute assignment could be attempted on any kind of object, yet to uphold
paul@29 110
the properties of "safe containers", attempts to change attributes of such
paul@29 111
objects should be denied. Since foreseen attribute assignment operations have
paul@29 112
certain properties detectable at compile-time, it could be appropriate to
paul@29 113
generate special instructions (or modified instructions) during the
paul@29 114
initialisation of modules and classes for such foreseen assignments, whilst
paul@29 115
employing normal attribute assignment operations in all other cases. Indeed,
paul@29 116
the StoreAttr instruction, which is used to set attributes in "safe
paul@29 117
containers" would be used exclusively for this purpose; the StoreAttrIndex
paul@29 118
instruction would be used exclusively for all other attribute assignments.
paul@29 119
paul@43 120
To ensure the "sealing" of modules and classes, entries in the attribute
paul@43 121
lookup table would encode whether a class or module is being accessed, so
paul@43 122
that the StoreAttrIndex instruction could reject such accesses.
paul@43 123
paul@28 124
Constant Attribute Values
paul@28 125
-------------------------
paul@28 126
paul@29 127
Where an attribute value is itself regarded as constant, is a "safe container"
paul@29 128
and is used in an operation accessing its own attributes, the value can be
paul@29 129
directly inspected for optimisations or employed in the generated code. For
paul@29 130
the attribute values themselves, only objects of a constant nature may be
paul@28 131
considered suitable for this particular optimisation:
paul@28 132
paul@28 133
  * Classes
paul@28 134
  * Modules
paul@28 135
  * Instances defined as constant literals
paul@28 136
paul@28 137
This is because arbitrary objects (such as most instances) have no
paul@28 138
well-defined form before run-time and cannot be investigated further at
paul@28 139
compile-time or have a representation inserted into the generated code.
paul@29 140
paul@29 141
Class Attributes and Access via Instances
paul@29 142
-----------------------------------------
paul@29 143
paul@29 144
Unlike module attributes, class attributes can be accessed in a number of
paul@29 145
different ways:
paul@29 146
paul@29 147
  * Using the class itself:
paul@29 148
paul@29 149
    C.x = 123
paul@29 150
    cls = C; cls.x = 234
paul@29 151
paul@29 152
  * Using a subclass of the class (for reading attributes):
paul@29 153
paul@29 154
    class D(C):
paul@29 155
        pass
paul@29 156
    D.x # setting D.x would populate D, not C
paul@29 157
paul@29 158
  * Using instances of the class or a subclass of the class (for reading
paul@29 159
    attributes):
paul@29 160
paul@29 161
    c = C()
paul@29 162
    c.x # setting c.x would populate c, not C
paul@29 163
paul@29 164
Since assignments are only achieved using direct references to the class, and
paul@29 165
since class attributes should be defined only within the class initialisation
paul@29 166
process, the properties of class attributes should be consistent with those
paul@29 167
desired.
paul@29 168
paul@29 169
Method Access via Instances
paul@29 170
---------------------------
paul@29 171
paul@29 172
It is desirable to optimise method access, even though most method calls are
paul@29 173
likely to occur via instances. It is possible, given the properties of methods
paul@29 174
as class attributes to investigate the kind of instance that the self
paul@29 175
parameter/local refers to within each method: it should be an instance either
paul@29 176
of the class in which the method is defined or a compatible class, although
paul@29 177
situations exist where this might not be the case:
paul@29 178
paul@29 179
  * Explicit invocation of a method:
paul@29 180
paul@29 181
    d = D() # D is not related to C
paul@29 182
    C.f(d) # calling f(self) in C
paul@29 183
paul@30 184
If blatant usage of incompatible instances were somehow disallowed, it would
paul@30 185
still be necessary to investigate the properties of an instance's class and
paul@30 186
its relationship with other classes. Consider the following example:
paul@30 187
paul@30 188
    class A:
paul@30 189
        def f(self): ...
paul@30 190
paul@30 191
    class B:
paul@30 192
        def f(self): ...
paul@30 193
        def g(self):
paul@30 194
            self.f()
paul@30 195
paul@30 196
    class C(A, B):
paul@30 197
        pass
paul@30 198
paul@30 199
Here, instances of B passed into the method B.g could be assumed to provide
paul@30 200
access to B.f when self.f is resolved at compile-time. However, instances of C
paul@30 201
passed into B.g would instead provide access to A.f when self.f is resolved at
paul@30 202
compile-time (since the method resolution order is C, A, B instead of just B).
paul@30 203
paul@30 204
One solution might be to specialise methods for each instance type, but this
paul@30 205
could be costly. Another less ambitious solution might only involve the
paul@30 206
optimisation of such internal method calls if an unambiguous target can be
paul@30 207
resolved.