1.1 --- a/docs/structures.txt Sun Aug 24 19:20:45 2008 +0200
1.2 +++ b/docs/structures.txt Mon Aug 25 02:04:10 2008 +0200
1.3 @@ -161,12 +161,12 @@
1.4
1.5 A suitable structure layout might be something like this:
1.6
1.7 - Identifier Address Details Type Object ...
1.8 + Identifier Identifier Address Details Type Object ...
1.9
1.10 - 0 1 2 3 4 5
1.11 - classcode invocation invocation __class__ attribute ...
1.12 - reference #args, reference reference
1.13 - #defaults
1.14 + 0 1 2 3 4 5 6
1.15 + classcode attrcode invocation invocation __class__ attribute ...
1.16 + reference #args, reference reference
1.17 + #defaults
1.18
1.19 Here, the classcode refers to the attribute lookup table for the object. Since
1.20 classes and instances share the same classcode, they might resemble the
1.21 @@ -174,17 +174,17 @@
1.22
1.23 Class C:
1.24
1.25 - 0 1 2 3 4 5
1.26 - code for C __new__ __new__ class type attribute ...
1.27 - reference #args, reference reference
1.28 - #defaults
1.29 + 0 1 2 3 4 5 6
1.30 + code for C attrcode __new__ __new__ class type attribute ...
1.31 + for C reference #args, reference reference
1.32 + #defaults
1.33
1.34 Instance of C:
1.35
1.36 - 0 1 2 3 4 5
1.37 - code for C C.__call__ C.__call__ class C attribute ...
1.38 - reference #args, reference reference
1.39 - (if exists) #defaults
1.40 + 0 1 2 3 4 5 6
1.41 + code for C attrcode C.__call__ C.__call__ class C attribute ...
1.42 + for C reference #args, reference reference
1.43 + (if exists) #defaults
1.44
1.45 The __new__ reference would lead to code consisting of the following
1.46 instructions:
1.47 @@ -200,10 +200,10 @@
1.48
1.49 Function f:
1.50
1.51 - 0 1 2 3 4 5
1.52 - code for code code class attribute ...
1.53 - function reference #args, function (default)
1.54 - #defaults reference reference
1.55 + 0 1 2 3 4 5 6
1.56 + code for attrcode code code class attribute ...
1.57 + function for reference #args, function (default)
1.58 + function #defaults reference reference
1.59
1.60 Here, the code reference would lead to code for the function. Note that the
1.61 function locals are completely distinct from this structure and are not
1.62 @@ -214,10 +214,10 @@
1.63
1.64 Module m:
1.65
1.66 - 0 1 2 3 4 5
1.67 - code for m (unused) (unused) module type attribute ...
1.68 - reference (global)
1.69 - reference
1.70 + 0 1 2 3 4 5 6
1.71 + code for m attrcode (unused) (unused) module type attribute ...
1.72 + for m reference (global)
1.73 + reference
1.74
1.75 Both classes and modules have code in their definitions, but this would be
1.76 generated in order and not referenced externally.
1.77 @@ -257,3 +257,18 @@
1.78 Where accesses can be determined ahead of time (as discussed in the
1.79 optimisations section), the above algorithm may not necessarily be employed in
1.80 the generated code for some accesses.
1.81 +
1.82 +Instance/Class Compatibility
1.83 +----------------------------
1.84 +
1.85 +Although it would be possible to have a data structure mapping classes to
1.86 +compatible classes, which in the case of context (or self argument)
1.87 +suitability in invocations would involve a mapping from a class to itself plus
1.88 +its descendants, the need to retain the key to such a data structure for each
1.89 +class might introduce a noticeable overhead. Such a structure would
1.90 +effectively be a matrix with each dimension indexed using the same sequence of
1.91 +codes for each of the classes in a program.
1.92 +
1.93 +An alternative might be to insert descendants as special attributes into the
1.94 +object/attribute lookup table. This would also require an extra key to be
1.95 +retained, since each class would have its own attribute code.
2.1 --- a/micropython/__init__.py Sun Aug 24 19:20:45 2008 +0200
2.2 +++ b/micropython/__init__.py Mon Aug 25 02:04:10 2008 +0200
2.3 @@ -115,7 +115,6 @@
2.4
2.5 objtable = self.get_object_table()
2.6 paramtable = self.get_parameter_table()
2.7 - clstable = self.get_class_table()
2.8
2.9 image = []
2.10
2.11 @@ -239,21 +238,6 @@
2.12
2.13 return self.objtable
2.14
2.15 - def get_class_table(self):
2.16 -
2.17 - "Return a table with details of class compatibility."
2.18 -
2.19 - if self.clstable is None:
2.20 - t = self.clstable = micropython.table.ClassTable()
2.21 - for module in self.get_modules():
2.22 - for obj in module.all_objects:
2.23 - if isinstance(obj, micropython.inspect.Class):
2.24 - compatible = [obj] + list(obj.descendants)
2.25 - compatible_dict = dict([(cls.full_name(), cls) for cls in compatible])
2.26 - t.add(obj.full_name(), compatible_dict)
2.27 -
2.28 - return self.clstable
2.29 -
2.30 def get_parameter_table(self):
2.31
2.32 "Return a table with details of parameters for functions and methods."
3.1 --- a/micropython/ast.py Sun Aug 24 19:20:45 2008 +0200
3.2 +++ b/micropython/ast.py Mon Aug 25 02:04:10 2008 +0200
3.3 @@ -68,7 +68,6 @@
3.4 self.importer = importer
3.5 self.objtable = self.importer.get_object_table()
3.6 self.paramtable = self.importer.get_parameter_table()
3.7 - self.clstable = self.importer.get_class_table()
3.8 self.builtins = self.importer.modules.get("__builtins__")
3.9
3.10 # Desired optimisations.
3.11 @@ -388,6 +387,7 @@
3.12 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
3.13 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
3.14 StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
3.15 + LoadCallable,
3.16 TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
3.17 CheckFrame,
3.18 LoadContext, # as the object providing the result
3.19 @@ -953,6 +953,7 @@
3.20
3.21 continue_label = self.new_label()
3.22 self.new_op(CheckSelf())
3.23 + self.active.source = temp
3.24 self.new_op(JumpIfTrue(continue_label))
3.25
3.26 # Where the context is inappropriate, drop the incomplete frame and
3.27 @@ -1786,11 +1787,9 @@
3.28 # Populate the new object required for the function.
3.29
3.30 if temp is not None:
3.31 - self.record_value()
3.32 + self.new_op(LoadCallable())
3.33 self.new_op(temp)
3.34 self.new_op(StoreCallable())
3.35 - self.set_source()
3.36 - self.discard_value()
3.37
3.38 self.new_op(temp)
3.39 #self.discard_temp(temp)
4.1 --- a/micropython/table.py Sun Aug 24 19:20:45 2008 +0200
4.2 +++ b/micropython/table.py Mon Aug 25 02:04:10 2008 +0200
4.3 @@ -167,14 +167,6 @@
4.4
4.5 return (offset, attr.is_class_attribute(), attr.defined_within_hierarchy(), position)
4.6
4.7 -class ClassList(List):
4.8 -
4.9 - "A class list."
4.10 -
4.11 - def entry_as_raw(self, entry):
4.12 - offset, attr = entry
4.13 - return offset
4.14 -
4.15 class ParameterList(List):
4.16
4.17 "A parameter list."
4.18 @@ -314,12 +306,6 @@
4.19
4.20 list_class = ObjectList
4.21
4.22 -class ClassTable(Table):
4.23 -
4.24 - "A class table."
4.25 -
4.26 - list_class = ClassList
4.27 -
4.28 class ParameterTable(Table):
4.29
4.30 "A parameter table."
5.1 --- a/rsvp.py Sun Aug 24 19:20:45 2008 +0200
5.2 +++ b/rsvp.py Mon Aug 25 02:04:10 2008 +0200
5.3 @@ -58,7 +58,7 @@
5.4
5.5 "A really simple virtual processor."
5.6
5.7 - def __init__(self, memory, objtable, paramtable, clstable, pc=None, debug=0):
5.8 + def __init__(self, memory, objtable, paramtable, pc=None, debug=0):
5.9
5.10 """
5.11 Initialise the processor with a 'memory' (a list of values containing
5.12 @@ -68,7 +68,6 @@
5.13 self.memory = memory
5.14 self.objtable = objtable
5.15 self.paramtable = paramtable
5.16 - self.clstable = clstable
5.17 self.pc = pc or 0
5.18 self.debug = debug
5.19
5.20 @@ -252,10 +251,10 @@
5.21
5.22 def LoadAttrIndex(self):
5.23 context, ref = self.value
5.24 - code = self.load(ref) # + 0 (the classcode)
5.25 - element = self.objtable[code + self.operand]
5.26 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.27 + element = self.objtable[classcode + self.operand]
5.28 found_code, class_attr, replace_context, offset = element
5.29 - if found_code == code:
5.30 + if found_code == classcode:
5.31 if class_attr:
5.32 loaded_context, loaded_ref = self.load(offset) # offset is address of class attribute
5.33 if replace_context:
5.34 @@ -270,10 +269,10 @@
5.35
5.36 def StoreAttrIndex(self):
5.37 context, ref = self.value
5.38 - code = self.load(ref) # + 0 (the classcode)
5.39 - element = self.objtable[code + self.operand]
5.40 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.41 + element = self.objtable[classcode + self.operand]
5.42 found_code, class_attr, replace_context, offset = element
5.43 - if found_code == code:
5.44 + if found_code == classcode:
5.45 if class_attr:
5.46 # NOTE: This should cause an attribute or type error.
5.47 # Class attributes cannot be changed at run-time.
5.48 @@ -301,10 +300,10 @@
5.49
5.50 def StoreFrameIndex(self):
5.51 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
5.52 - code = self.load(ref) # + 0 (the functioncode)
5.53 - element = self.objtable[code + self.operand]
5.54 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.55 + element = self.objtable[classcode + self.operand]
5.56 found_code, offset = element
5.57 - if found_code == code:
5.58 + if found_code == classcode:
5.59 self.frame_stack[frame + offset] = self.value
5.60 else:
5.61 # NOTE: This should cause an argument error.
5.62 @@ -312,25 +311,52 @@
5.63
5.64 def LoadCallable(self):
5.65 context, ref = self.value
5.66 - self.callable = self.load(ref + 1)
5.67 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.68 + self.callable = codeaddr, codedetails
5.69
5.70 def StoreCallable(self):
5.71 context, ref = self.value
5.72 - self.save(ref + 1, self.callable)
5.73 + # NOTE: Should improve the representation and permit direct saving.
5.74 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.75 + self.save(ref, (classcode, attrcode) + self.callable)
5.76
5.77 def LoadContext(self):
5.78 context, ref = self.value
5.79 self.value = None, context
5.80
5.81 def CheckFrame(self):
5.82 + operand = self.operand
5.83 + frame = self.invocation_sp_stack[-1]
5.84 context, ref = self.value
5.85 - nargs, ndefaults = self.load(ref + 2)
5.86 - if not (nargs - ndefaults <= self.operand <= nargs):
5.87 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.88 +
5.89 + # Support sliding of the frame to exclude any inappropriate context.
5.90 +
5.91 + if context is None:
5.92 + frame = frame[1:]
5.93 + operand -= 1
5.94 + else:
5.95 + if contexttype == self.typetype:
5.96 + frame = frame[1:]
5.97 + operand -= 1
5.98 +
5.99 + nargs, ndefaults = codedetails
5.100 + if not (nargs - ndefaults <= operand <= nargs):
5.101 raise Exception, "CheckFrame %r" % (nargs - ndefaults, self.operand, nargs)
5.102 +
5.103 # NOTE: Support population of defaults.
5.104 - # NOTE: Support sliding of the frame to exclude any inappropriate context.
5.105
5.106 - def CheckSelf(self): pass
5.107 + def CheckSelf(self):
5.108 + context, ref = self.value
5.109 + target_context, target_ref = self.source
5.110 + classcode, attrcode, codeaddr, codedetails = self.load(ref)
5.111 + target_classcode, target_attrcode, target_codeaddr, target_codedetails = self.load(target_context)
5.112 + element = self.objtable[target_classcode + attrcode]
5.113 + found_code, class_attr, replace_context, offset = element
5.114 + if found_code == target_classcode:
5.115 + self.status = 1
5.116 + else:
5.117 + self.status = 0
5.118
5.119 def JumpWithFrame(self):
5.120 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
6.1 --- a/test.py Sun Aug 24 19:20:45 2008 +0200
6.2 +++ b/test.py Mon Aug 25 02:04:10 2008 +0200
6.3 @@ -68,6 +68,5 @@
6.4 i.vacuum()
6.5 ot = i.get_object_table()
6.6 pt = i.get_parameter_table()
6.7 - ct = i.get_class_table()
6.8
6.9 # vim: tabstop=4 expandtab shiftwidth=4
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/tests/call_method2.py Mon Aug 25 02:04:10 2008 +0200
7.3 @@ -0,0 +1,15 @@
7.4 +#!/usr/bin/env python
7.5 +
7.6 +class C:
7.7 + def f(self, a, b, c):
7.8 + pass
7.9 +
7.10 +c = C()
7.11 +
7.12 +f = c.f
7.13 +f(1, 2, 3)
7.14 +
7.15 +f = C.f
7.16 +f(c, 1, 2, 3)
7.17 +
7.18 +# vim: tabstop=4 expandtab shiftwidth=4