1.1 --- a/rsvp.py Sun Sep 07 18:43:40 2008 +0200
1.2 +++ b/rsvp.py Sun Sep 07 20:23:10 2008 +0200
1.3 @@ -24,22 +24,32 @@
1.4
1.5 The execution model of the virtual processor involves the following things:
1.6
1.7 - * Memory
1.8 - * PC (program counter) stack
1.9 - * Frame stack (containing invocation frames in use and in preparation plus
1.10 - temporary storage)
1.11 - * Local frame pointer stack
1.12 + * Memory contains constants, global variable
1.13 + references and program code
1.14 +
1.15 + * PC (program counter) stack contains the return address associated
1.16 + with each function invocation
1.17 +
1.18 + * Frame stack contains invocation frames in use and in
1.19 + preparation plus temporary storage
1.20 +
1.21 + * Local frame pointer stack refers to the frames in the frame stack
1.22 +
1.23 * Invocation frame pointer stack
1.24 +
1.25 * Exception handler stack
1.26 - * Registers: current value, boolean status value, source value, result,
1.27 - current exception, current callable
1.28
1.29 -The memory contains constants, global variable references and program code.
1.30 + * Exception handler locals stack refers to the state of the local frame
1.31 + pointer stack
1.32 +
1.33 + * Exception handler PC stack refers to the state of the PC stack
1.34
1.35 -The PC stack contains the return address associated with each function
1.36 -invocation.
1.37 -
1.38 -The frame pointer stack tracks the position of frames within the frame stack.
1.39 + * Registers: current value,
1.40 + boolean status value,
1.41 + source value,
1.42 + current result,
1.43 + current exception,
1.44 + current callable
1.45 """
1.46
1.47 class IllegalInstruction(Exception):
1.48 @@ -77,7 +87,9 @@
1.49 self.frame_stack = []
1.50 self.local_sp_stack = [0]
1.51 self.invocation_sp_stack = []
1.52 - self.handler_stack = []
1.53 + self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code
1.54 + self.handler_local_sp_stack = []
1.55 + self.handler_pc_stack = []
1.56
1.57 # Registers.
1.58
1.59 @@ -97,6 +109,8 @@
1.60 print "Local stack pointers", self.local_sp_stack
1.61 print "Invocation stack pointers", self.invocation_sp_stack
1.62 print "Handler stack", self.handler_stack
1.63 + print "Handler frame stack", self.handler_local_sp_stack
1.64 + print "Handler PC stack", self.handler_pc_stack
1.65 print
1.66 print "Instruction", self.instruction
1.67 print "Operand", self.operand
1.68 @@ -265,10 +279,10 @@
1.69 def MakeObject(self):
1.70 size = self.operand
1.71 context, ref = self.value
1.72 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.73 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.74 addr = self.new(size)
1.75 # Set the header to resemble the class.
1.76 - self.save(addr, (classcode, attrcode, None, None)) # NOTE: __call__ method not yet provided.
1.77 + self.save(addr, (classcode, attrcode, None, None, 1)) # NOTE: __call__ method not yet provided.
1.78 # Introduce null context for new object.
1.79 self.value = None, addr
1.80
1.81 @@ -284,7 +298,7 @@
1.82
1.83 def LoadAttrIndex(self):
1.84 context, ref = self.value
1.85 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.86 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.87 element = self.objlist[classcode + self.operand]
1.88 attr_index, class_attr, replace_context, offset = element
1.89 if attr_index == self.operand:
1.90 @@ -302,7 +316,7 @@
1.91
1.92 def StoreAttrIndex(self):
1.93 context, ref = self.value
1.94 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.95 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.96 element = self.objlist[classcode + self.operand]
1.97 attr_index, class_attr, replace_context, offset = element
1.98 if attr_index == self.operand:
1.99 @@ -336,7 +350,7 @@
1.100
1.101 def StoreFrameIndex(self):
1.102 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
1.103 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.104 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.105 element = self.objlist[classcode + self.operand]
1.106 attr_index, offset = element
1.107 if attr_index == self.operand:
1.108 @@ -347,14 +361,14 @@
1.109
1.110 def LoadCallable(self):
1.111 context, ref = self.value
1.112 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.113 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.114 self.callable = codeaddr, codedetails
1.115
1.116 def StoreCallable(self):
1.117 context, ref = self.value
1.118 # NOTE: Should improve the representation and permit direct saving.
1.119 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.120 - self.save(ref, (classcode, attrcode) + self.callable)
1.121 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.122 + self.save(ref, (classcode, attrcode) + self.callable + (instance,))
1.123
1.124 def LoadContext(self):
1.125 context, ref = self.value
1.126 @@ -364,7 +378,7 @@
1.127 operand = self.operand
1.128 frame = self.invocation_sp_stack[-1]
1.129 context, ref = self.value
1.130 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.131 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.132
1.133 # Support sliding of the frame to exclude any inappropriate context.
1.134
1.135 @@ -372,7 +386,8 @@
1.136 self.invocation_sp_stack[-1] += 1
1.137 operand -= 1
1.138 else:
1.139 - if contexttype == self.typetype:
1.140 + context_classcode, context_attrcode, context_codeaddr, context_codedetails, context_instance = self.load(context)
1.141 + if not context_instance:
1.142 self.invocation_sp_stack[-1] += 1
1.143 operand -= 1
1.144
1.145 @@ -386,19 +401,9 @@
1.146 context, ref = self.value
1.147 target_context, target_ref = self.source
1.148
1.149 - # Load the details of the proposed context and the target's context.
1.150 -
1.151 - classcode, attrcode, codeaddr, codedetails = self.load(ref)
1.152 - target_classcode, target_attrcode, target_codeaddr, target_codedetails = self.load(target_context)
1.153 -
1.154 - # Find the table entry for the descendant.
1.155 + # Check the details of the proposed context and the target's context.
1.156
1.157 - element = self.objlist[target_classcode + attrcode]
1.158 - attr_index, class_attr, replace_context, offset = element
1.159 - if attr_index == attrcode:
1.160 - self.status = 1
1.161 - else:
1.162 - self.status = 0
1.163 + self._CheckInstance(ref, target_context)
1.164
1.165 def JumpWithFrame(self):
1.166 codeaddr, codedetails = self.callable
1.167 @@ -437,25 +442,31 @@
1.168 return self.operand
1.169
1.170 def LoadException(self):
1.171 - self.value = self.exception
1.172 + self.value = None, self.exception
1.173
1.174 def StoreException(self):
1.175 - self.exception = self.value
1.176 + self.exception = self.value[1]
1.177
1.178 def RaiseException(self):
1.179 - return self.handler_stack.pop()
1.180 + return self.handler_stack[-1]
1.181
1.182 def PushHandler(self):
1.183 self.handler_stack.append(self.operand)
1.184 + self.handler_local_sp_stack.append(len(self.local_sp_stack))
1.185 + self.handler_pc_stack.append(len(self.pc_stack))
1.186
1.187 def PopHandler(self):
1.188 + # Reduce the local frame pointer stack to refer to the handler's frame.
1.189 + self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()]
1.190 + # Reduce the PC stack to discard all superfluous return addresses.
1.191 + self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()]
1.192 self.handler_stack.pop()
1.193
1.194 def CheckException(self):
1.195 - self.status = self.value[1] == self.exception
1.196 + self._CheckInstance(self.exception, self.value[1])
1.197
1.198 def TestIdentity(self):
1.199 - self.status = self.value[1] == self.source
1.200 + self.status = self.value[1] == self.source[1]
1.201
1.202 def TestIdentityAddress(self):
1.203 self.status = self.value[1] == self.operand
1.204 @@ -466,4 +477,19 @@
1.205 def InvertBoolean(self):
1.206 self.status = not self.status
1.207
1.208 + # Common implementation details.
1.209 +
1.210 + def _CheckInstance(self, ref, cls):
1.211 + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref)
1.212 + target_classcode, target_attrcode, target_codeaddr, target_codedetails, target_instance = self.load(cls)
1.213 +
1.214 + # Find the table entry for the descendant.
1.215 +
1.216 + element = self.objlist[target_classcode + attrcode]
1.217 + attr_index, class_attr, replace_context, offset = element
1.218 + if attr_index == attrcode:
1.219 + self.status = 1
1.220 + else:
1.221 + self.status = 0
1.222 +
1.223 # vim: tabstop=4 expandtab shiftwidth=4