paul@199 | 1 | Concepts
|
paul@199 | 2 | ========
|
paul@199 | 3 |
|
paul@201 | 4 | This document describes the underlying concepts employed in micropython.
|
paul@201 | 5 |
|
paul@201 | 6 | * Namespaces and attribute definition
|
paul@570 | 7 | * Attribute usage observations
|
paul@199 | 8 | * Contexts and values
|
paul@200 | 9 | * Tables, attributes and lookups
|
paul@199 | 10 | * Objects and structures
|
paul@200 | 11 | * Parameters and lookups
|
paul@200 | 12 | * Instantiation
|
paul@222 | 13 | * Register usage
|
paul@245 | 14 | * List and tuple representations
|
paul@199 | 15 |
|
paul@201 | 16 | Namespaces and Attribute Definition
|
paul@201 | 17 | ===================================
|
paul@201 | 18 |
|
paul@201 | 19 | Namespaces are any objects which can retain attributes.
|
paul@201 | 20 |
|
paul@201 | 21 | * Module attributes are defined either at the module level or by global
|
paul@201 | 22 | statements.
|
paul@201 | 23 | * Class attributes are defined only within class statements.
|
paul@534 | 24 | * Instance attributes are defined only by assignments to attributes of self
|
paul@534 | 25 | or tentatively as references to attributes of self.
|
paul@201 | 26 |
|
paul@201 | 27 | These restrictions apply because such attributes are thus explicitly declared,
|
paul@201 | 28 | permitting the use of tables (described below). Module and class attributes
|
paul@201 | 29 | can also be finalised in this way in order to permit certain optimisations.
|
paul@201 | 30 |
|
paul@243 | 31 | An additional restriction required for the current implementation of tables
|
paul@243 | 32 | (as described below) applies to class definitions: each class must be defined
|
paul@243 | 33 | using a unique name; repeated definition of classes having the same name is
|
paul@243 | 34 | thus not permitted. This restriction arises from the use of the "full name" of
|
paul@243 | 35 | a class as a key to the object table, where the full name is a qualified path
|
paul@243 | 36 | via the module hierarchy ending with the name of the class.
|
paul@243 | 37 |
|
paul@519 | 38 | Rebinding of attributes outside classes and modules can be allowed if
|
paul@519 | 39 | attribute usage observations are being used to detect such external
|
paul@519 | 40 | modifications to such objects. Without such observations, such rebinding
|
paul@519 | 41 | should be forbidden since apparently constant attributes might be modified in
|
paul@519 | 42 | a running program, but code may have been generated that provides specific
|
paul@519 | 43 | objects for those attributes under the assumption that they will not be
|
paul@519 | 44 | changed.
|
paul@519 | 45 |
|
paul@201 | 46 | See rejected.txt for complicating mechanisms which could be applied to
|
paul@201 | 47 | mitigate the effects of these restrictions on optimisations.
|
paul@201 | 48 |
|
paul@550 | 49 | Attribute Usage Observations
|
paul@550 | 50 | ============================
|
paul@550 | 51 |
|
paul@550 | 52 | Within a scope, a name may be used in conjunction with attribute names in
|
paul@550 | 53 | order to access attributes on objects referenced by the name. However, such
|
paul@550 | 54 | observations can only be regarded as reliable if the object referenced is not
|
paul@550 | 55 | changed independently by some other mechanism or activity.
|
paul@550 | 56 |
|
paul@550 | 57 | With conventional functions and methods, any locally defined names can be
|
paul@550 | 58 | considered private to that scope and thus immune to independent modification,
|
paul@550 | 59 | at least within reasonable features of the language. Although stack
|
paul@550 | 60 | modification may be possible, it seems appropriate to reject such features,
|
paul@550 | 61 | especially since they lend themselves to unmaintainable programs.
|
paul@550 | 62 |
|
paul@550 | 63 | For names defined during the initialisation of a class, since the class itself
|
paul@550 | 64 | cannot be referenced by name until its declaration has been completely
|
paul@550 | 65 | evaluated, no independent modification can occur from outside the class scope.
|
paul@550 | 66 |
|
paul@550 | 67 | For names defined during the initialisation of a module, global declarations
|
paul@550 | 68 | in functions permit the rebinding of global variables and since functions may
|
paul@550 | 69 | be invoked during module initialisation, independent modification can
|
paul@550 | 70 | potentially occur if any functions are called.
|
paul@550 | 71 |
|
paul@550 | 72 | Module globals can be accessed from other modules that can refer to a module
|
paul@550 | 73 | by its name. Initially, an import is required to make a module available for
|
paul@550 | 74 | modification, but there is no restriction on whether a module has been
|
paul@550 | 75 | completely imported (and thus defined) before an import statement can make it
|
paul@550 | 76 | available to other modules. Consider the following package root definition:
|
paul@550 | 77 |
|
paul@557 | 78 | # Module changed:
|
paul@550 | 79 | def f():
|
paul@557 | 80 | import changed.modifier
|
paul@550 | 81 | x = 123
|
paul@550 | 82 | f()
|
paul@550 | 83 |
|
paul@557 | 84 | # Module changed.modifier:
|
paul@557 | 85 | import changed
|
paul@557 | 86 | changed.x = 456
|
paul@550 | 87 |
|
paul@557 | 88 | Here, an import of changed will initially set x to 123, but then the function
|
paul@557 | 89 | f will be invoked and cause the changed.modifier module to be imported. Since
|
paul@557 | 90 | the changed module is already being imported, the import statement will not
|
paul@557 | 91 | try to perform the import operation again, but it will make the partially
|
paul@557 | 92 | defined module available for access. Thus, the changed.modifier module will
|
paul@557 | 93 | then set x to 456, and independent modification of the changed namespace will
|
paul@557 | 94 | have been performed.
|
paul@550 | 95 |
|
paul@550 | 96 | In conclusion, module globals cannot therefore be regarded as immune to
|
paul@550 | 97 | operations that would disrupt usage observations. Consequently, only locals
|
paul@550 | 98 | and class definition "locals" can be reliably employed in attribute usage
|
paul@550 | 99 | observations.
|
paul@550 | 100 |
|
paul@199 | 101 | Contexts and Values
|
paul@199 | 102 | ===================
|
paul@199 | 103 |
|
paul@199 | 104 | Values are used as the common reference representation in micropython: as
|
paul@199 | 105 | stored representations of attributes (of classes, instances, modules, and
|
paul@199 | 106 | other objects supporting attribute-like entities) as well as the stored values
|
paul@199 | 107 | associated with names in functions and methods.
|
paul@199 | 108 |
|
paul@199 | 109 | Unlike other implementations, micropython does not create things like bound
|
paul@199 | 110 | method objects for individual instances. Instead, all objects are referenced
|
paul@199 | 111 | using a context, reference pair:
|
paul@199 | 112 |
|
paul@199 | 113 | Value Layout
|
paul@199 | 114 | ------------
|
paul@199 | 115 |
|
paul@199 | 116 | 0 1
|
paul@199 | 117 | context object
|
paul@199 | 118 | reference reference
|
paul@199 | 119 |
|
paul@199 | 120 | Specific implementations might reverse this ordering for optimisation
|
paul@199 | 121 | purposes.
|
paul@199 | 122 |
|
paul@199 | 123 | Rationale
|
paul@199 | 124 | ---------
|
paul@199 | 125 |
|
paul@199 | 126 | To reduce the number of created objects whilst retaining the ability to
|
paul@199 | 127 | support bound method invocations. The context indicates the context in which
|
paul@199 | 128 | an invocation is performed, typically the owner of the method.
|
paul@199 | 129 |
|
paul@199 | 130 | Usage
|
paul@199 | 131 | -----
|
paul@199 | 132 |
|
paul@199 | 133 | The context may be inserted as the first argument when a value is involved in
|
paul@199 | 134 | an invocation. This argument may then be omitted from the invocation if its
|
paul@199 | 135 | usage is not appropriate.
|
paul@199 | 136 |
|
paul@199 | 137 | See invocation.txt for details.
|
paul@199 | 138 |
|
paul@237 | 139 | Context Value Types
|
paul@237 | 140 | -------------------
|
paul@237 | 141 |
|
paul@237 | 142 | The following types of context value exist:
|
paul@237 | 143 |
|
paul@237 | 144 | Type Usage Transformations
|
paul@237 | 145 | ---- ----- ---------------
|
paul@237 | 146 |
|
paul@237 | 147 | Replaceable With functions (not methods) May be replaced with an
|
paul@237 | 148 | instance or a class when a
|
paul@237 | 149 | value is stored on an
|
paul@237 | 150 | instance or class
|
paul@237 | 151 |
|
paul@237 | 152 | Placeholder With classes May not be replaced
|
paul@237 | 153 |
|
paul@237 | 154 | Instance With instances (and constants) May not be replaced
|
paul@237 | 155 | or functions as methods
|
paul@237 | 156 |
|
paul@237 | 157 | Class With functions as methods May be replaced when a
|
paul@237 | 158 | value is loaded from a
|
paul@237 | 159 | class attribute via an
|
paul@237 | 160 | instance
|
paul@237 | 161 |
|
paul@199 | 162 | Contexts in Acquired Values
|
paul@199 | 163 | ---------------------------
|
paul@199 | 164 |
|
paul@237 | 165 | There are four classes of instructions which provide values:
|
paul@199 | 166 |
|
paul@199 | 167 | Instruction Purpose Context Operations
|
paul@199 | 168 | ----------- ------- ------------------
|
paul@199 | 169 |
|
paul@237 | 170 | 1) LoadConst Load module, constant Use loaded object with itself
|
paul@237 | 171 | as context
|
paul@199 | 172 |
|
paul@237 | 173 | 2) LoadFunction Load function Combine replaceable context
|
paul@237 | 174 | with loaded object
|
paul@223 | 175 |
|
paul@237 | 176 | 3) LoadClass Load class Combine placeholder context
|
paul@237 | 177 | with loaded object
|
paul@237 | 178 |
|
paul@237 | 179 | 4) LoadAddress* Load attribute from Preserve or override stored
|
paul@201 | 180 | LoadAttr* class, module, context (as described in
|
paul@201 | 181 | instance assignment.txt)
|
paul@199 | 182 |
|
paul@199 | 183 | In order to comply with traditional Python behaviour, contexts may or may not
|
paul@199 | 184 | represent the object from which an attribute has been acquired.
|
paul@199 | 185 |
|
paul@199 | 186 | See assignment.txt for details.
|
paul@199 | 187 |
|
paul@199 | 188 | Contexts in Stored Values
|
paul@199 | 189 | -------------------------
|
paul@199 | 190 |
|
paul@223 | 191 | There are two classes of instruction for storing values:
|
paul@199 | 192 |
|
paul@223 | 193 | Instruction Purpose Context Operations
|
paul@223 | 194 | ----------- ------- ------------------
|
paul@199 | 195 |
|
paul@223 | 196 | 1) StoreAddress Store attribute in a Preserve context; note that no
|
paul@223 | 197 | known object test for class attribute
|
paul@223 | 198 | assignment should be necessary
|
paul@223 | 199 | since this instruction should only
|
paul@223 | 200 | be generated for module globals
|
paul@199 | 201 |
|
paul@223 | 202 | StoreAttr Store attribute in an Preserve context; note that no
|
paul@223 | 203 | instance test for class attribute
|
paul@223 | 204 | assignment should be necessary
|
paul@223 | 205 | since this instruction should only
|
paul@223 | 206 | be generated for self accesses
|
paul@199 | 207 |
|
paul@223 | 208 | StoreAttrIndex Store attribute in an Preserve context; since the index
|
paul@223 | 209 | unknown object lookup could yield a class
|
paul@223 | 210 | attribute, a test of the nature of
|
paul@223 | 211 | the nature of the structure is
|
paul@223 | 212 | necessary in order to prevent
|
paul@223 | 213 | assignments to classes
|
paul@199 | 214 |
|
paul@223 | 215 | 2) StoreAddressContext Store attribute in a Override context if appropriate;
|
paul@237 | 216 | known object if the value has a replaceable
|
paul@237 | 217 | context, permit the target to
|
paul@237 | 218 | take ownership of the value
|
paul@199 | 219 |
|
paul@199 | 220 | See assignment.txt for details.
|
paul@199 | 221 |
|
paul@200 | 222 | Tables, Attributes and Lookups
|
paul@200 | 223 | ==============================
|
paul@199 | 224 |
|
paul@199 | 225 | Attribute lookups, where the exact location of an object attribute is deduced,
|
paul@199 | 226 | are performed differently in micropython than in other implementations.
|
paul@199 | 227 | Instead of providing attribute dictionaries, in which attributes are found,
|
paul@199 | 228 | attributes are located at fixed places in object structures (described below)
|
paul@199 | 229 | and their locations are stored using a special representation known as a
|
paul@199 | 230 | table.
|
paul@199 | 231 |
|
paul@199 | 232 | For a given program, a table can be considered as being like a matrix mapping
|
paul@199 | 233 | classes to attribute names. For example:
|
paul@199 | 234 |
|
paul@199 | 235 | class A:
|
paul@200 | 236 | # instances have attributes x, y
|
paul@199 | 237 |
|
paul@199 | 238 | class B(A):
|
paul@200 | 239 | # introduces attribute z for instances
|
paul@199 | 240 |
|
paul@199 | 241 | class C:
|
paul@200 | 242 | # instances have attributes a, b, z
|
paul@199 | 243 |
|
paul@200 | 244 | This would provide the following table, referred to as an object table in the
|
paul@200 | 245 | context of classes and instances:
|
paul@199 | 246 |
|
paul@199 | 247 | Class/attr a b x y z
|
paul@199 | 248 |
|
paul@199 | 249 | A 1 2
|
paul@199 | 250 | B 1 2 3
|
paul@199 | 251 | C 1 2 3
|
paul@199 | 252 |
|
paul@199 | 253 | A limitation of this representation is that instance attributes may not shadow
|
paul@199 | 254 | class attributes: if an attribute with a given name is not defined on an
|
paul@199 | 255 | instance, an attribute with the same name cannot be provided by the class of
|
paul@401 | 256 | the instance or any superclass of the instance's class. This impacts the
|
paul@401 | 257 | provision of the __class__ attribute, as described below.
|
paul@199 | 258 |
|
paul@199 | 259 | The table can be compacted using a representation known as a displacement
|
paul@200 | 260 | list (referred to as an object list in this context):
|
paul@199 | 261 |
|
paul@199 | 262 | Classes with attribute offsets
|
paul@199 | 263 |
|
paul@199 | 264 | classcode A
|
paul@199 | 265 | attrcode a b x y z
|
paul@199 | 266 |
|
paul@199 | 267 | B
|
paul@199 | 268 | a b x y z
|
paul@199 | 269 |
|
paul@199 | 270 | C
|
paul@199 | 271 | a b x y z
|
paul@199 | 272 |
|
paul@199 | 273 | List . . 1 2 1 2 3 1 2 . . 3
|
paul@199 | 274 |
|
paul@199 | 275 | Here, the classcode refers to the offset in the list at which a class's
|
paul@199 | 276 | attributes are defined, whereas the attrcode defines the offset within a
|
paul@199 | 277 | region of attributes corresponding to a single attribute of a given name.
|
paul@199 | 278 |
|
paul@200 | 279 | Attribute Locations
|
paul@200 | 280 | -------------------
|
paul@200 | 281 |
|
paul@394 | 282 | The locations stored in table/list elements are generally for instance
|
paul@394 | 283 | attributes relative to the location of the instance, whereas those for class
|
paul@394 | 284 | attributes and module attributes are generally absolute addresses. Thus, each
|
paul@394 | 285 | occupied table cell has the following structure:
|
paul@242 | 286 |
|
paul@242 | 287 | attrcode, uses-absolute-address, address (or location)
|
paul@200 | 288 |
|
paul@247 | 289 | This could be given instead as follows:
|
paul@247 | 290 |
|
paul@247 | 291 | attrcode, is-class-or-module, location
|
paul@247 | 292 |
|
paul@247 | 293 | Since uses-absolute-address corresponds to is-class-or-module, and since there
|
paul@247 | 294 | is a need to test for classes and modules to prevent assignment to attributes
|
paul@247 | 295 | of such objects, this particular information is always required.
|
paul@247 | 296 |
|
paul@394 | 297 | The __class__ Attribute
|
paul@394 | 298 | -----------------------
|
paul@394 | 299 |
|
paul@401 | 300 | In Python 2.x, at least with new-style classes, instances have __class__
|
paul@401 | 301 | attributes which indicate the class from which they have been instantiated,
|
paul@401 | 302 | whereas classes have __class__ attributes which reference the type class.
|
paul@401 | 303 | With the object table, it is not possible to provide absolute addresses which
|
paul@401 | 304 | can be used for both classes and instances, since this would result in classes
|
paul@401 | 305 | and instances having the same class, and thus the class of a class would be
|
paul@401 | 306 | the class itself.
|
paul@397 | 307 |
|
paul@401 | 308 | One solution is to use object-relative values in the table so that referencing
|
paul@401 | 309 | the __class__ attribute of an instance produces a value which can be combined
|
paul@401 | 310 | with an instance's address to yield the address of the attribute, which itself
|
paul@401 | 311 | refers to the instance's class, whereas referencing the __class__ attribute of
|
paul@401 | 312 | a class produces a similar object-relative value that is combined with the
|
paul@401 | 313 | class's address to yield the address of the attribute, which itself refers to
|
paul@401 | 314 | the special type class.
|
paul@401 | 315 |
|
paul@401 | 316 | Obviously, the above solution requires both classes and instances to retain an
|
paul@401 | 317 | attribute location specifically to hold the value appropriate for each object
|
paul@401 | 318 | type, whereas a scheme which omits the __class__ attribute on classes would be
|
paul@401 | 319 | able to employ an absolute address in the table and maintain only a single
|
paul@401 | 320 | address to refer to the class for all instances. The only problem with not
|
paul@401 | 321 | providing a sensible __class__ attribute entry for classes would be the need
|
paul@401 | 322 | for special treatment of __class__ to prevent inappropriate consultation of
|
paul@401 | 323 | the table for classes.
|
paul@394 | 324 |
|
paul@247 | 325 | Comparing Tables as Matrices with Displacement Lists
|
paul@247 | 326 | ----------------------------------------------------
|
paul@247 | 327 |
|
paul@247 | 328 | Although displacement lists can provide reasonable levels of compaction for
|
paul@247 | 329 | attribute data, the element size is larger than that required for a simple
|
paul@247 | 330 | matrix: the attribute code (attrcode) need not be stored since each element
|
paul@247 | 331 | unambiguously refers to the availability of an attribute for a particular
|
paul@247 | 332 | class or instance of that class, and so the data at a given element need not
|
paul@247 | 333 | be tested for relevance to a given attribute access operation.
|
paul@247 | 334 |
|
paul@247 | 335 | Given a program with 20 object types and 100 attribute types, a matrix would
|
paul@247 | 336 | occupy the following amount of space:
|
paul@247 | 337 |
|
paul@247 | 338 | number of object types * number of attribute types * element size
|
paul@247 | 339 | = 20 * 100 * 1 (assuming that a single location is sufficient for an element)
|
paul@247 | 340 | = 2000
|
paul@247 | 341 |
|
paul@247 | 342 | In contrast, given a compaction to 40% of the matrix size (without considering
|
paul@247 | 343 | element size) in a displacement list, the amount of space would be as follows:
|
paul@247 | 344 |
|
paul@247 | 345 | number of elements * element size
|
paul@247 | 346 | = 40% * (20 * 100) * 2 (assuming that one additional location is required)
|
paul@247 | 347 | = 1600
|
paul@247 | 348 |
|
paul@247 | 349 | Consequently, the principal overhead of using a displacement list is likely to
|
paul@247 | 350 | be in the need to check element relevance when retrieving values from such a
|
paul@247 | 351 | list.
|
paul@247 | 352 |
|
paul@199 | 353 | Objects and Structures
|
paul@199 | 354 | ======================
|
paul@199 | 355 |
|
paul@199 | 356 | As well as references, micropython needs to have actual objects to refer to.
|
paul@199 | 357 | Since classes, functions and instances are all objects, it is desirable that
|
paul@199 | 358 | certain common features and operations are supported in the same way for all
|
paul@199 | 359 | of these things. To permit this, a common data structure format is used.
|
paul@199 | 360 |
|
paul@215 | 361 | Header.................................................... Attributes.................
|
paul@200 | 362 |
|
paul@401 | 363 | Identifier Identifier Address Identifier Size Object ...
|
paul@199 | 364 |
|
paul@401 | 365 | 0 1 2 3 4 5 6
|
paul@401 | 366 | classcode attrcode/ invocation funccode size attribute ...
|
paul@401 | 367 | instance reference reference
|
paul@215 | 368 | status
|
paul@199 | 369 |
|
paul@206 | 370 | Classcode
|
paul@206 | 371 | ---------
|
paul@206 | 372 |
|
paul@206 | 373 | Used in attribute lookup.
|
paul@206 | 374 |
|
paul@199 | 375 | Here, the classcode refers to the attribute lookup table for the object (as
|
paul@200 | 376 | described above). Classes and instances share the same classcode, and their
|
paul@200 | 377 | structures reflect this. Functions all belong to the same type and thus employ
|
paul@200 | 378 | the classcode for the function built-in type, whereas modules have distinct
|
paul@200 | 379 | types since they must support different sets of attributes.
|
paul@199 | 380 |
|
paul@206 | 381 | Attrcode
|
paul@206 | 382 | --------
|
paul@206 | 383 |
|
paul@206 | 384 | Used to test instances for membership of classes (or descendants of classes).
|
paul@206 | 385 |
|
paul@242 | 386 | Since, in traditional Python, classes are only ever instances of some generic
|
paul@242 | 387 | built-in type, support for testing such a relationship directly has been
|
paul@207 | 388 | removed and the attrcode is not specified for classes: the presence of an
|
paul@242 | 389 | attrcode indicates that a given object is an instance. In addition, support
|
paul@242 | 390 | has also been removed for testing modules in the same way, meaning that the
|
paul@242 | 391 | attrcode is also not specified for modules.
|
paul@206 | 392 |
|
paul@215 | 393 | See the "Testing Instance Compatibility with Classes (Attrcode)" section below
|
paul@215 | 394 | for details of attrcodes.
|
paul@214 | 395 |
|
paul@213 | 396 | Invocation Reference
|
paul@213 | 397 | --------------------
|
paul@213 | 398 |
|
paul@213 | 399 | Used when an object is called.
|
paul@213 | 400 |
|
paul@213 | 401 | This is the address of the code to be executed when an invocation is performed
|
paul@213 | 402 | on the object.
|
paul@213 | 403 |
|
paul@215 | 404 | Funccode
|
paul@215 | 405 | --------
|
paul@213 | 406 |
|
paul@215 | 407 | Used to look up argument positions by name.
|
paul@213 | 408 |
|
paul@215 | 409 | The strategy with keyword arguments in micropython is to attempt to position
|
paul@215 | 410 | such arguments in the invocation frame as it is being constructed.
|
paul@215 | 411 |
|
paul@215 | 412 | See the "Parameters and Lookups" section for more information.
|
paul@215 | 413 |
|
paul@215 | 414 | Size
|
paul@215 | 415 | ----
|
paul@215 | 416 |
|
paul@219 | 417 | Used to indicate the size of an object including attributes.
|
paul@213 | 418 |
|
paul@209 | 419 | Attributes
|
paul@209 | 420 | ----------
|
paul@209 | 421 |
|
paul@209 | 422 | For classes, modules and instances, the attributes in the structure correspond
|
paul@209 | 423 | to the attributes of each kind of object. For functions, however, the
|
paul@209 | 424 | attributes in the structure correspond to the default arguments for each
|
paul@209 | 425 | function, if any.
|
paul@209 | 426 |
|
paul@206 | 427 | Structure Types
|
paul@206 | 428 | ---------------
|
paul@206 | 429 |
|
paul@199 | 430 | Class C:
|
paul@199 | 431 |
|
paul@401 | 432 | 0 1 2 3 4 5 6
|
paul@401 | 433 | classcode (unused) __new__ funccode size attribute ...
|
paul@401 | 434 | for C reference for reference
|
paul@215 | 435 | instantiator
|
paul@199 | 436 |
|
paul@199 | 437 | Instance of C:
|
paul@199 | 438 |
|
paul@401 | 439 | 0 1 2 3 4 5 6
|
paul@401 | 440 | classcode attrcode C.__call__ funccode size attribute ...
|
paul@401 | 441 | for C for C reference for reference
|
paul@215 | 442 | (if exists) C.__call__
|
paul@199 | 443 |
|
paul@200 | 444 | Function f:
|
paul@199 | 445 |
|
paul@401 | 446 | 0 1 2 3 4 5 6
|
paul@401 | 447 | classcode attrcode code funccode size attribute ...
|
paul@401 | 448 | for for reference (default)
|
paul@401 | 449 | function function reference
|
paul@200 | 450 |
|
paul@200 | 451 | Module m:
|
paul@200 | 452 |
|
paul@401 | 453 | 0 1 2 3 4 5 6
|
paul@401 | 454 | classcode attrcode (unused) (unused) (unused) attribute ...
|
paul@401 | 455 | for m for m (global)
|
paul@401 | 456 | reference
|
paul@200 | 457 |
|
paul@200 | 458 | The __class__ Attribute
|
paul@200 | 459 | -----------------------
|
paul@200 | 460 |
|
paul@401 | 461 | All objects should support the __class__ attribute, and in most cases this is
|
paul@401 | 462 | done using the object table, yielding a common address for all instances of a
|
paul@401 | 463 | given class.
|
paul@401 | 464 |
|
paul@401 | 465 | Function: refers to the function class
|
paul@401 | 466 | Instance: refers to the class instantiated to make the object
|
paul@401 | 467 |
|
paul@401 | 468 | The object table cannot support two definitions simultaneously for both
|
paul@401 | 469 | instances and their classes. Consequently, __class__ access on classes must be
|
paul@401 | 470 | tested for and a special result returned.
|
paul@200 | 471 |
|
paul@200 | 472 | Class: refers to the type class (type.__class__ also refers to the type class)
|
paul@401 | 473 |
|
paul@401 | 474 | For convenience, the first attribute of a class will be the common __class__
|
paul@401 | 475 | attribute for all its instances. As noted above, direct access to this
|
paul@401 | 476 | attribute will not be possible for classes, and a constant result will be
|
paul@401 | 477 | returned instead.
|
paul@200 | 478 |
|
paul@203 | 479 | Lists and Tuples
|
paul@203 | 480 | ----------------
|
paul@203 | 481 |
|
paul@203 | 482 | The built-in list and tuple sequences employ variable length structures using
|
paul@203 | 483 | the attribute locations to store their elements, where each element is a
|
paul@203 | 484 | reference to a separately stored object.
|
paul@203 | 485 |
|
paul@214 | 486 | Testing Instance Compatibility with Classes (Attrcode)
|
paul@200 | 487 | ------------------------------------------------------
|
paul@200 | 488 |
|
paul@200 | 489 | Although it would be possible to have a data structure mapping classes to
|
paul@200 | 490 | compatible classes, such as a matrix indicating the subclasses (or
|
paul@200 | 491 | superclasses) of each class, the need to retain the key to such a data
|
paul@200 | 492 | structure for each class might introduce a noticeable overhead.
|
paul@200 | 493 |
|
paul@200 | 494 | Instead of having a separate structure, descendant classes of each class are
|
paul@200 | 495 | inserted as special attributes into the object table. This requires an extra
|
paul@200 | 496 | key to be retained, since each class must provide its own attribute code such
|
paul@200 | 497 | that upon an instance/class compatibility test, the code may be obtained and
|
paul@200 | 498 | used in the object table.
|
paul@200 | 499 |
|
paul@200 | 500 | Invocation and Code References
|
paul@200 | 501 | ------------------------------
|
paul@200 | 502 |
|
paul@200 | 503 | Modules: there is no meaningful invocation reference since modules cannot be
|
paul@200 | 504 | explicitly called.
|
paul@200 | 505 |
|
paul@200 | 506 | Functions: a simple code reference is employed pointing to code implementing
|
paul@200 | 507 | the function. Note that the function locals are completely distinct from this
|
paul@200 | 508 | structure and are not comparable to attributes. Instead, attributes are
|
paul@200 | 509 | reserved for default parameter values, although they do not appear in the
|
paul@200 | 510 | object table described above, appearing instead in a separate parameter table
|
paul@200 | 511 | described below.
|
paul@200 | 512 |
|
paul@200 | 513 | Classes: given that classes must be invoked in order to create instances, a
|
paul@200 | 514 | reference must be provided in class structures. However, this reference does
|
paul@200 | 515 | not point directly at the __init__ method of the class. Instead, the
|
paul@200 | 516 | referenced code belongs to a special initialiser function, __new__, consisting
|
paul@200 | 517 | of the following instructions:
|
paul@200 | 518 |
|
paul@200 | 519 | create instance for C
|
paul@200 | 520 | call C.__init__(instance, ...)
|
paul@200 | 521 | return instance
|
paul@200 | 522 |
|
paul@200 | 523 | Instances: each instance employs a reference to any __call__ method defined in
|
paul@200 | 524 | the class hierarchy for the instance, thus maintaining its callable nature.
|
paul@200 | 525 |
|
paul@200 | 526 | Both classes and modules may contain code in their definitions - the former in
|
paul@200 | 527 | the "body" of the class, potentially defining attributes, and the latter as
|
paul@200 | 528 | the "top-level" code in the module, potentially defining attributes/globals -
|
paul@200 | 529 | but this code is not associated with any invocation target. It is thus
|
paul@200 | 530 | generated in order of appearance and is not referenced externally.
|
paul@200 | 531 |
|
paul@200 | 532 | Invocation Operation
|
paul@200 | 533 | --------------------
|
paul@200 | 534 |
|
paul@200 | 535 | Consequently, regardless of the object an invocation is always done as
|
paul@200 | 536 | follows:
|
paul@200 | 537 |
|
paul@200 | 538 | get invocation reference from the header
|
paul@200 | 539 | jump to reference
|
paul@200 | 540 |
|
paul@200 | 541 | Additional preparation is necessary before the above code: positional
|
paul@200 | 542 | arguments must be saved in the invocation frame, and keyword arguments must be
|
paul@200 | 543 | resolved and saved to the appropriate position in the invocation frame.
|
paul@200 | 544 |
|
paul@200 | 545 | See invocation.txt for details.
|
paul@200 | 546 |
|
paul@200 | 547 | Parameters and Lookups
|
paul@200 | 548 | ======================
|
paul@200 | 549 |
|
paul@200 | 550 | Since Python supports keyword arguments when making invocations, it becomes
|
paul@200 | 551 | necessary to record the parameter names associated with each function or
|
paul@200 | 552 | method. Just as object tables record attributes positions on classes and
|
paul@200 | 553 | instances, parameter tables record parameter positions in function or method
|
paul@200 | 554 | parameter lists.
|
paul@200 | 555 |
|
paul@200 | 556 | For a given program, a parameter table can be considered as being like a
|
paul@200 | 557 | matrix mapping functions/methods to parameter names. For example:
|
paul@200 | 558 |
|
paul@200 | 559 | def f(x, y, z):
|
paul@200 | 560 | pass
|
paul@200 | 561 |
|
paul@200 | 562 | def g(a, b, c):
|
paul@200 | 563 | pass
|
paul@200 | 564 |
|
paul@200 | 565 | def h(a, x):
|
paul@200 | 566 | pass
|
paul@200 | 567 |
|
paul@200 | 568 | This would provide the following table, referred to as a parameter table in
|
paul@200 | 569 | the context of functions and methods:
|
paul@200 | 570 |
|
paul@200 | 571 | Function/param a b c x y z
|
paul@200 | 572 |
|
paul@200 | 573 | f 1 2 3
|
paul@200 | 574 | g 1 2 3
|
paul@200 | 575 | h 1 2
|
paul@200 | 576 |
|
paul@233 | 577 | Confusion can occur when functions are adopted as methods, since the context
|
paul@233 | 578 | then occupies the first slot in the invocation frame:
|
paul@233 | 579 |
|
paul@233 | 580 | def f(x, y, z):
|
paul@233 | 581 | pass
|
paul@233 | 582 |
|
paul@233 | 583 | f(x=1, y=2, z=3) -> f(<context>, 1, 2, 3)
|
paul@233 | 584 | -> f(1, 2, 3)
|
paul@233 | 585 |
|
paul@233 | 586 | class C:
|
paul@233 | 587 | f = f
|
paul@233 | 588 |
|
paul@233 | 589 | def g(x, y, z):
|
paul@233 | 590 | pass
|
paul@233 | 591 |
|
paul@233 | 592 | c = C()
|
paul@233 | 593 |
|
paul@233 | 594 | c.f(y=2, z=3) -> f(<context>, 2, 3)
|
paul@233 | 595 | c.g(y=2, z=3) -> C.g(<context>, 2, 3)
|
paul@233 | 596 |
|
paul@200 | 597 | Just as with parameter tables, a displacement list can be prepared from a
|
paul@200 | 598 | parameter table:
|
paul@200 | 599 |
|
paul@200 | 600 | Functions with parameter (attribute) offsets
|
paul@200 | 601 |
|
paul@200 | 602 | funccode f
|
paul@200 | 603 | attrcode a b c x y z
|
paul@200 | 604 |
|
paul@200 | 605 | g
|
paul@200 | 606 | a b c x y z
|
paul@200 | 607 |
|
paul@200 | 608 | h
|
paul@200 | 609 | a b c x y z
|
paul@200 | 610 |
|
paul@200 | 611 | List . . . 1 2 3 1 2 3 1 . . 2 . .
|
paul@200 | 612 |
|
paul@200 | 613 | Here, the funccode refers to the offset in the list at which a function's
|
paul@200 | 614 | parameters are defined, whereas the attrcode defines the offset within a
|
paul@200 | 615 | region of attributes corresponding to a single parameter of a given name.
|
paul@200 | 616 |
|
paul@200 | 617 | Instantiation
|
paul@200 | 618 | =============
|
paul@200 | 619 |
|
paul@200 | 620 | When instantiating classes, memory must be reserved for the header of the
|
paul@200 | 621 | resulting instance, along with locations for the attributes of the instance.
|
paul@200 | 622 | Since the instance header contains data common to all instances of a class, a
|
paul@200 | 623 | template header is copied to the start of the newly reserved memory region.
|
paul@222 | 624 |
|
paul@222 | 625 | Register Usage
|
paul@222 | 626 | ==============
|
paul@222 | 627 |
|
paul@222 | 628 | During code generation, much of the evaluation produces results which are
|
paul@450 | 629 | implicitly recorded in the "active value" or "working" register, and various
|
paul@450 | 630 | instructions will consume this active value. In addition, some instructions
|
paul@450 | 631 | will consume a separate "active source value" from a register, typically those
|
paul@450 | 632 | which are assigning the result of an expression to an assignment target.
|
paul@222 | 633 |
|
paul@222 | 634 | Since values often need to be retained for later use, a set of temporary
|
paul@222 | 635 | storage locations are typically employed. However, optimisations may reduce
|
paul@222 | 636 | the need to use such temporary storage where instructions which provide the
|
paul@450 | 637 | "active value" can be re-executed and will produce the same result. Whether
|
paul@450 | 638 | re-use of instructions is possible or not, values still need to be loaded into
|
paul@450 | 639 | a "source" register to be accessed by an assignment instruction.
|
paul@450 | 640 |
|
paul@450 | 641 | RSVP instructions generally have the notion of working, target and source
|
paul@450 | 642 | registers (see registers.txt). These register "roles" are independent from the
|
paul@450 | 643 | actual registers defined for the RSVP machine itself, even though the naming
|
paul@450 | 644 | is similar. Generally, instructions do regard the RSVP "working" registers as
|
paul@450 | 645 | the class of register in the "working" role, although some occurrences of
|
paul@450 | 646 | instruction usage may employ other registers (such as the "result" registers)
|
paul@450 | 647 | and thus take advantage of the generality of the RSVP implementation of such
|
paul@450 | 648 | instructions.
|
paul@245 | 649 |
|
paul@245 | 650 | List and Tuple Representations
|
paul@245 | 651 | ==============================
|
paul@245 | 652 |
|
paul@245 | 653 | Since tuples have a fixed size, the representation of a tuple instance is
|
paul@245 | 654 | merely a header describing the size of the entire object, together with a
|
paul@245 | 655 | sequence of references to the object "stored" at each position in the
|
paul@245 | 656 | structure. Such references consist of the usual context and reference pair.
|
paul@245 | 657 |
|
paul@245 | 658 | Lists, however, have a variable size and must be accessible via an unchanging
|
paul@245 | 659 | location even as more memory is allocated elsewhere to accommodate the
|
paul@245 | 660 | contents of the list. Consequently, the representation must resemble the
|
paul@245 | 661 | following:
|
paul@245 | 662 |
|
paul@245 | 663 | Structure header for list (size == header plus special attribute)
|
paul@245 | 664 | Special attribute referencing the underlying sequence
|
paul@245 | 665 |
|
paul@245 | 666 | The underlying sequence has a fixed size, like a tuple, but may contain fewer
|
paul@245 | 667 | elements than the size of the sequence permits:
|
paul@245 | 668 |
|
paul@245 | 669 | Special header indicating the current size and allocated size
|
paul@245 | 670 | Element
|
paul@245 | 671 | ... <-- current size
|
paul@245 | 672 | (Unused space)
|
paul@245 | 673 | ... <-- allocated size
|
paul@245 | 674 |
|
paul@245 | 675 | This representation permits the allocation of a new sequence when space is
|
paul@245 | 676 | exhausted in an existing sequence, with the new sequence address stored in the
|
paul@245 | 677 | main list structure. Since access to the contents of the list must go through
|
paul@245 | 678 | the main list structure, underlying allocation activities may take place
|
paul@245 | 679 | without the users of a list having to be aware of such activities.
|