micropython

Annotated README.txt

236:6ba10a65eddd
2009-06-02 Paul Boddie Introduced a separate globals processing phase, recording all declared global names before attempting to resolve other names. Removed the Global class and warning about globals not being declared at the module level. Added tests of globals.
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.