# HG changeset patch # User Paul Boddie # Date 1243708040 -7200 # Node ID 892b13f1cba4bcc97667c5ba78fbb797d8a70999 # Parent a179262ea7c4faa9e2ffd1b45c1db8fd9ca585aa Changed instantiator invocation reserving a frame slot regardless of whether the target is known in advance. In the instantiator, the first frame slot is then overwritten with the new instance, and the RecoverFrame instruction is no longer required. Instead, a new JumpInFrame instruction maintains the existing locals, jumping to the initialiser method for the class. Updated various tests, renaming and enhancing the classes test. diff -r a179262ea7c4 -r 892b13f1cba4 docs/invocation.txt --- a/docs/invocation.txt Fri May 29 00:18:40 2009 +0200 +++ b/docs/invocation.txt Sat May 30 20:27:20 2009 +0200 @@ -129,14 +129,18 @@ f(obj, 1, 2) # f not known at compile-time f -> C.__new__ (known and called at run-time) + -> load context for argument #1 + obj -> argument #2 + 1 -> argument #3 + 2 -> argument #4 Need to call C.__init__(, obj, 1, 2), preferably with the existing frame: - - obj -> argument #1 - 1 -> argument #2 - 2 -> argument #3 + *** -> instance overwrites argument #1 + obj -> argument #2 + 1 -> argument #3 + 2 -> argument #4 Then jump without switching frames. It should be possible to replace the old, tentative context information in the diff -r a179262ea7c4 -r 892b13f1cba4 micropython/ast.py --- a/micropython/ast.py Fri May 29 00:18:40 2009 +0200 +++ b/micropython/ast.py Sat May 30 20:27:20 2009 +0200 @@ -168,33 +168,21 @@ init_method = cls.get_init_method() - # Fix the current frame to include a new storage slot at the beginning. - - self.new_op(AdjustFrame(-1)) - - # Convert this frame back to being an invocation frame. - - self.new_op(RecoverFrame()) - - # Make an object. + # Make an object and store it in the unused first slot. self.make_object(cls, len(cls.instance_attributes())) - self.new_op(StoreFrame(0)) + self.new_op(StoreTemp(0)) # Invoke the appropriate initialiser. self.new_op(LoadFunction(init_method)) self.new_op(LoadCallable()) - self.new_op(JumpWithFrame()) + self.new_op(JumpInFrame()) # Store the object as the result. - self.new_op(LoadName(init_method.all_locals()["self"])) # load the context in the invocation frame + self.new_op(LoadTemp(0)) # load the context from the locals self.new_op(StoreResult()) - - # Fix the current frame to release the storage slot at the beginning. - - self.new_op(AdjustFrame(1)) self.new_op(Return()) self.unit.blocks = self.blocks diff -r a179262ea7c4 -r 892b13f1cba4 micropython/data.py --- a/micropython/data.py Fri May 29 00:18:40 2009 +0200 +++ b/micropython/data.py Sat May 30 20:27:20 2009 +0200 @@ -1081,9 +1081,9 @@ def as_instantiator(self): - "Make an instantiator function from a method." + "Make an instantiator function from a method, keeping all arguments." - function = Function(self.parent.name, self.parent.parent, self.argnames[1:], self.defaults, + function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.module, self.astnode) function.default_attrs = self.default_attrs return function diff -r a179262ea7c4 -r 892b13f1cba4 micropython/rsvp.py --- a/micropython/rsvp.py Fri May 29 00:18:40 2009 +0200 +++ b/micropython/rsvp.py Sat May 30 20:27:20 2009 +0200 @@ -195,7 +195,6 @@ class MakeFrame(Immediate): "Make a new invocation frame." class DropFrame(Instruction): "Drop an invocation frame." -class RecoverFrame(Instruction): "Recover the current frame as an invocation frame." class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position." class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index." class LoadContext(Instruction): "Load the context of an invocation." @@ -211,6 +210,7 @@ # Invocation-related instructions, using a special result "register". +class JumpInFrame(Instruction): "Jump, using the current locals, to the current callable." class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable." class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame." class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." diff -r a179262ea7c4 -r 892b13f1cba4 micropython/trans.py --- a/micropython/trans.py Fri May 29 00:18:40 2009 +0200 +++ b/micropython/trans.py Sat May 30 20:27:20 2009 +0200 @@ -557,9 +557,12 @@ # Handle calls to classes. # The resulting target must match that used in the actual invocation. + # A context is reserved for the new instance, but this is not provided + # in the invocation (since the instantiator will fill the locals slot + # concerned). elif isinstance(target, Class): - ncontext = 0 + ncontext = 1 expect_context = 0 target = target.get_instantiator() diff -r a179262ea7c4 -r 892b13f1cba4 rsvp.py --- a/rsvp.py Fri May 29 00:18:40 2009 +0200 +++ b/rsvp.py Sat May 30 20:27:20 2009 +0200 @@ -395,7 +395,7 @@ def StoreName(self): frame = self.local_sp_stack[-1] - self.frame_stack[frame + self.operand] = self.source + self.frame_stack[frame + self.operand] = self.source # uses the source value LoadTemp = LoadName @@ -511,9 +511,6 @@ frame = self.invocation_sp_stack.pop() self.frame_stack = self.frame_stack[:frame] # reset stack before call - def RecoverFrame(self): - self.invocation_sp_stack[-1] = self.local_sp_stack.pop() - def StoreFrame(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame self.frame_stack[frame + self.operand] = self.value @@ -607,6 +604,10 @@ self.status = self._CheckInstance(ref, target_context) + def JumpInFrame(self): + codeaddr = self.callable + return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one + def JumpWithFrame(self): codeaddr = self.callable self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame @@ -714,10 +715,9 @@ return addr def _LoadAddressContextCond(self, context, ref, inst_ref): - # Check the instance context against the target's context. - - if self._CheckInstance(inst_ref, context): + # This provides the context overriding for methods. + if context is not None and self._CheckInstance(inst_ref, context): # Replace the context with the instance. return inst_ref, ref else: diff -r a179262ea7c4 -r 892b13f1cba4 tests/attributes_instance_bind_method.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/attributes_instance_bind_method.py Sat May 30 20:27:20 2009 +0200 @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +class B: + def __init__(self, y): + self.y = y + def m(self, x): + return x + +class A: + c1 = B + m1 = B.m + def __init__(self, b): + self.c2 = B + self.m2 = B.m + self.c3 = b + self.m3 = b.m + +b = B(789) +a = A(b) +result_123 = A.m1(b, 123) # A.m1 is unbound +result_234 = a.m1(b, 234) # a.m1 is unbound +result_345 = a.m2(b, 345) # a.m2 is unbound +result_456 = a.m3(456) # a.m3 is bound to b + +b1 = A.c1(678) # A.c1 is just a reference to B +result_678 = b1.y +b2 = a.c1(567) # a.c1 is just a reference to B +result_567 = b2.y +b3 = a.c2(765) # a.c2 is just a reference to B +result_765 = b3.y + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method.py --- a/tests/call_method.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method.py Sat May 30 20:27:20 2009 +0200 @@ -5,5 +5,6 @@ self.x = x c = C(123) +result_123 = c.x # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method_ref.py --- a/tests/call_method_ref.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method_ref.py Sat May 30 20:27:20 2009 +0200 @@ -10,5 +10,8 @@ f = c.f f(1, 2, 3) +result_1 = c.a +result_2 = c.b +result_3 = c.c # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method_ref_internal.py --- a/tests/call_method_ref_internal.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method_ref_internal.py Sat May 30 20:27:20 2009 +0200 @@ -12,5 +12,8 @@ c = C() c.f(1, 2, 3) +result_1 = c.a +result_2 = c.b +result_3 = c.c # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method_self.py --- a/tests/call_method_self.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method_self.py Sat May 30 20:27:20 2009 +0200 @@ -11,5 +11,8 @@ c = C() c.f(1, 2, 3) +result_1 = c.a +result_2 = c.b +result_3 = c.c # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method_via_class.py --- a/tests/call_method_via_class.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method_via_class.py Sat May 30 20:27:20 2009 +0200 @@ -10,5 +10,8 @@ f = C.f f(c, 1, 2, 3) # test self argument +result_1 = c.a +result_2 = c.b +result_3 = c.c # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/call_method_via_class_internal.py --- a/tests/call_method_via_class_internal.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/call_method_via_class_internal.py Sat May 30 20:27:20 2009 +0200 @@ -11,5 +11,8 @@ c = C() c.f(1, 2, 3) +result_1 = c.a +result_2 = c.b +result_3 = c.c # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/class_init_defaults.py --- a/tests/class_init_defaults.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/class_init_defaults.py Sat May 30 20:27:20 2009 +0200 @@ -7,5 +7,8 @@ self.z = z c = C() +result_1 = c.x +result_2 = c.y +result_3 = c.z # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/class_init_keywords.py --- a/tests/class_init_keywords.py Fri May 29 00:18:40 2009 +0200 +++ b/tests/class_init_keywords.py Sat May 30 20:27:20 2009 +0200 @@ -7,5 +7,8 @@ self.z = z c = C(1, 2, z=3) +result_1 = c.x +result_2 = c.y +result_3 = c.z # vim: tabstop=4 expandtab shiftwidth=4 diff -r a179262ea7c4 -r 892b13f1cba4 tests/classes.py --- a/tests/classes.py Fri May 29 00:18:40 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -#!/usr/bin/env python - -class B: - pass - -class A: - c0 = B - def __init__(self): - self.c2 = B - -a = A() - - # context on A attribute context on a attribute -A.c0 # none none -a.c2 # N/A none - -# vim: tabstop=4 expandtab shiftwidth=4