# HG changeset patch # User Paul Boddie # Date 1307909676 -7200 # Node ID ee5f5b872354bf2aeae1ee1c4b976a1692cba1c7 # Parent 0b8548d6ee4e64d3234df21566c771c1b82c5158 Changed the RSVP machine to have separate context and value registers for the current value, source value and result. diff -r 0b8548d6ee4e -r ee5f5b872354 TO_DO.txt --- a/TO_DO.txt Sun Jun 12 00:57:03 2011 +0200 +++ b/TO_DO.txt Sun Jun 12 22:14:36 2011 +0200 @@ -1,6 +1,9 @@ Low-Level Instructions and Macro Instructions ============================================= +Have contexts and values stored separately in memory. This involves eliminating DataValue +and storing attributes using two words. + Migrate macro instructions such as the *Index instructions to library code implemented using low-level instructions. diff -r 0b8548d6ee4e -r ee5f5b872354 micropython/rsvp.py --- a/micropython/rsvp.py Sun Jun 12 00:57:03 2011 +0200 +++ b/micropython/rsvp.py Sun Jun 12 22:14:36 2011 +0200 @@ -537,7 +537,7 @@ "Store the source value as an argument of the current value for the parameter with the given index." cost = 6 -class LoadContext(Instruction): +class LoadContextIntoValue(Instruction): "Load the context of an invocation." cost = 2 @@ -674,7 +674,7 @@ LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAddressContextCond, LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond, - LoadCallable, LoadContext, LoadResult, + LoadCallable, LoadContextIntoValue, LoadResult, LoadException, MakeInstance, MakeFragment, CopyExtra ) @@ -693,7 +693,7 @@ CheckException, CheckFrame, FillDefaults, MakeInstance, CheckContext, CheckClass, CheckType, - LoadContext # as the object providing the result + LoadContextIntoValue # as the object providing the result ) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 0b8548d6ee4e -r ee5f5b872354 micropython/trans.py --- a/micropython/trans.py Sun Jun 12 00:57:03 2011 +0200 +++ b/micropython/trans.py Sun Jun 12 22:14:36 2011 +0200 @@ -677,7 +677,7 @@ if target is None or isinstance(context, Instance): self.new_op(temp_target) - self.new_op(LoadContext()) + self.new_op(LoadContextIntoValue()) temp_context = self.optimiser.optimise_temp_storage() self.new_op(StoreFrame(0)) @@ -687,7 +687,7 @@ elif isinstance(context, Class): self.new_op(temp_target) - self.new_op(LoadContext()) + self.new_op(LoadContextIntoValue()) temp_context = self.optimiser.optimise_temp_storage() # Otherwise omit the context. diff -r 0b8548d6ee4e -r ee5f5b872354 rsvp.py --- a/rsvp.py Sun Jun 12 00:57:03 2011 +0200 +++ b/rsvp.py Sun Jun 12 22:14:36 2011 +0200 @@ -44,11 +44,11 @@ * Exception handler PC stack refers to the state of the PC stack - * Registers: current value, + * Registers: current context/value, + source context/value, + current result context/value, + current exception value, boolean status value, - source value, - current result, - current exception, current callable """ @@ -121,14 +121,21 @@ # Registers. + self.value = None + self.context = None + + self.source_value = None + self.source_context = None + + self.result_value = None + self.result_context = None + + self.exception = None + self.instruction = None self.operand = None - self.value = None self.status = None - self.source = None self.callable = None - self.result = None - self.exception = None # Constants. @@ -173,14 +180,21 @@ print "Handler frame stack", self.handler_local_sp_stack print "Handler PC stack", self.handler_pc_stack print + print "Value", self.value + print "Context", self.context + print + print "Source value", self.source_value + print "Source context", self.source_context + print + print "Result value", self.result_value + print "Result context", self.result_context + print + print "Exception", self.exception + print print "Instruction", self.instruction print "Operand", self.operand - print "Value", self.value print "Status", self.status - print "Source", self.source print "Callable", self.callable - print "Result", self.result - print "Exception", self.exception def show(self, start=None, end=None): self.show_memory(self.memory[start:end], self.coverage[start:end], start or 0) @@ -387,11 +401,11 @@ instructions would otherwise have. """ - value = self.value + value, context = self.value, self.context if self.instruction.source is not None: self.perform(self.instruction.source, 1) - self.source = self.value - self.value = value + self.source_value, self.source_context = self.value, self.context + self.value, self.context = value, context if self.instruction.input is not None: self.perform(self.instruction.input, 1) @@ -416,94 +430,111 @@ self.push_pc(self.pc + 1) return addr + # Low-level instructions. + + def LoadValue(self, operand): + self.value = operand + + def LoadContext(self, operand): + self.context = operand + # Instructions. def LoadConst(self): - self.value = DataValue(self.operand, self.operand) + self.LoadContext(self.operand) + self.LoadValue(self.operand) def LoadClass(self): - self.value = DataValue(PlaceholderContext, self.operand) + self.LoadContext(PlaceholderContext) + self.LoadValue(self.operand) def LoadFunction(self): - self.value = DataValue(ReplaceableContext, self.operand) + self.LoadContext(ReplaceableContext) + self.LoadValue(self.operand) def LoadName(self): frame = self.local_sp_stack[-1] - self.value = self.frame_stack[frame + self.operand] + data = self.frame_stack[frame + self.operand] + self.LoadContext(data.context) + self.LoadValue(data.ref) def StoreName(self): frame = self.local_sp_stack[-1] - self.frame_stack[frame + self.operand] = self.source # uses the source value + self.frame_stack[frame + self.operand] = DataValue(self.source_context, self.source_value) LoadTemp = LoadName def StoreTemp(self): frame = self.local_sp_stack[-1] - self.frame_stack[frame + self.operand] = self.value + self.frame_stack[frame + self.operand] = DataValue(self.context, self.value) def LoadAddress(self): # Preserve context (potentially null). - self.value = self.load(self.operand) + data = self.load(self.operand) + self.LoadContext(data.context) + self.LoadValue(data.ref) def LoadAddressContext(self): - value = self.load(self.operand) - inst_value = self.value - self.value = DataValue(inst_value.ref, value.ref) + # Value becomes context. + data = self.load(self.operand) + self.LoadContext(self.value) + self.LoadValue(data.ref) def LoadAddressContextCond(self): - value = self.load(self.operand) - inst_value = self.value - self.value = self._LoadAddressContextCond(value.context, value.ref, inst_value.ref) + data = self.load(self.operand) + data = self._LoadAddressContextCond(data.context, data.ref, self.value) + self.LoadContext(data.context) + self.LoadValue(data.ref) def StoreAddress(self): # Preserve context. - self.save(self.operand, self.source) + self.save(self.operand, DataValue(self.source_context, self.source_value)) def StoreAddressContext(self): # Overwrite context if null. - context_value = self.value - source_value = self.source - self._StoreAddressContext(self.operand, context_value, source_value) + self._StoreAddressContext(self.operand, self.context, self.value, self.source_context, self.source_value) def MakeInstance(self): size = self.operand - value = self.value # NOTE: Referencing the instance template. - addr = self._MakeObject(size, value.ref - Library.instance_template_size) + addr = self._MakeObject(size, self.value - Library.instance_template_size) # Introduce object as context for the new object. - self.value = DataValue(addr, addr) + self.LoadContext(addr) + self.LoadValue(addr) def MakeFragment(self): size = self.operand # Reserve twice the amount of space. addr = self._MakeFragment(size, size * 2) # NOTE: Context is not relevant for fragments. - self.value = DataValue(None, addr) + self.LoadContext(None) + self.LoadValue(addr) def LoadAttr(self): - value = self.value # Retrieved context should already be appropriate for the instance. # NOTE: Adding 1 to skip any header. - self.value = self.load(value.ref + self.operand + 1) + data = self.load(self.value + self.operand + 1) + self.LoadContext(data.context) + self.LoadValue(data.ref) def StoreAttr(self): - value = self.value # Target should already be an instance. # NOTE: Adding 1 to skip any header. - self.save(value.ref + self.operand + 1, self.source) + self.save(self.value + self.operand + 1, DataValue(self.source_context, self.source_value)) def LoadAttrIndex(self): - value = self.value - data = self.load(value.ref) + data = self.load(self.value) element = self.objlist[data.classcode + self.operand] if element is not None: attr_index, static_attr, offset = element if attr_index == self.operand: if static_attr: - self.value = self.load(offset) # offset is address of class/module attribute + data = self.load(offset) # offset is address of class/module attribute else: - self.value = self.load(value.ref + offset) + data = self.load(self.value + offset) + self.LoadContext(data.context) + self.LoadValue(data.ref) return self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance) @@ -512,39 +543,38 @@ # LoadAttrIndexContext not defined. def LoadAttrIndexContextCond(self): - inst_value = self.value - data = self.load(inst_value.ref) + data = self.load(self.value) element = self.objlist[data.classcode + self.operand] if element is not None: attr_index, static_attr, offset = element if attr_index == self.operand: if static_attr: - loaded_value = self.load(offset) # offset is address of class/module attribute - if data.attrcode is None: # absent attrcode == class/module - self.value = loaded_value - else: - self.value = self._LoadAddressContextCond(loaded_value.context, loaded_value.ref, inst_value.ref) + loaded_data = self.load(offset) # offset is address of class/module attribute + # Absent attrcode == class/module. + if data.attrcode is not None: + loaded_data = self._LoadAddressContextCond(loaded_data.context, loaded_data.ref, self.value) else: - self.value = self.load(inst_value.ref + offset) + loaded_data = self.load(self.value + offset) + self.LoadContext(loaded_data.context) + self.LoadValue(loaded_data.ref) return self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance) return self.RaiseException() def StoreAttrIndex(self): - value = self.value - data = self.load(value.ref) + data = self.load(self.value) element = self.objlist[data.classcode + self.operand] if element is not None: attr_index, static_attr, offset = element if attr_index == self.operand: if static_attr: - self._StoreAddressContext(offset, value, self.source) + self._StoreAddressContext(offset, self.context, self.value, self.source_context, self.source_value) return else: - self.save(value.ref + offset, self.source) + self.save(self.value + offset, DataValue(self.source_context, self.source_value)) return self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance) @@ -563,51 +593,46 @@ def StoreFrame(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame - self.frame_stack[frame + self.operand] = self.value + self.frame_stack[frame + self.operand] = DataValue(self.context, self.value) def StoreFrameIndex(self): - value = self.value frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame - data = self.load(value.ref) + data = self.load(self.value) element = self.paramlist[data.funccode + self.operand] if element is not None: # NOTE: Need to ensure correct positioning where a context has been generated. param_index, offset = element if param_index == self.operand: - self.frame_stack[frame + offset] = self.source + self.frame_stack[frame + offset] = DataValue(self.source_context, self.source_value) return self.exception = self._MakeObject(Library.instance_size, self.type_error_instance) return self.RaiseException() def LoadCallable(self): - value = self.value - data = self.load(value.ref) + data = self.load(self.value) self.callable = data.codeaddr def StoreCallable(self): - value = self.value # NOTE: Should improve the representation and permit direct saving. - data = self.load(value.ref) - self.save(value.ref, data.with_callable(self.callable)) + data = self.load(self.value) + self.save(self.value, data.with_callable(self.callable)) - def LoadContext(self): - value = self.value + def LoadContextIntoValue(self): # NOTE: Omission of the context of the context would make things like # NOTE: self() inside methods impossible. - self.value = DataValue(value.context, value.context) + self.LoadValue(self.context) def CheckContext(self): - self.status = self.value.ref is not ReplaceableContext + self.status = self.value is not ReplaceableContext def CheckClass(self): - value = self.value - if value.ref in (ReplaceableContext, PlaceholderContext): + if self.value in (ReplaceableContext, PlaceholderContext): self.status = 0 return - data = self.load(value.ref) + data = self.load(self.value) # Classes are not themselves usable as the self argument. # NOTE: This may change at some point. @@ -645,7 +670,6 @@ self.frame_stack.extend([None]) # ExtendFrame(1) def FillDefaults(self): - value = self.value (nargs, ndefaults) = self.operand # The frame is actually installed as the locals. @@ -661,7 +685,7 @@ pos = nlocals while pos < nargs: - self.frame_stack[frame + pos] = self.load(value.ref + default + 1) # skip header + self.frame_stack[frame + pos] = self.load(self.value + default + 1) # skip header default += 1 pos += 1 @@ -685,21 +709,13 @@ extra += 1 pos += 1 - self.value = DataValue(ref, ref) + self.LoadContext(ref) + self.LoadValue(ref) def CheckInstance(self): - value = self.value - target_value = self.source - # For the 'self' parameter in an invoked function, the proposed context # ('self') is checked against the target's context. - - self.status = self._CheckInstance(value.ref, target_value.ref) - - def CheckType(self): - value = self.value - target_value = self.operand - self.status = self._CheckType(value.ref, target_value.ref) + self.status = self._CheckInstance(self.value, self.source_value) def JumpInFrame(self): codeaddr = self.callable @@ -725,10 +741,12 @@ return self.pull_pc() def LoadResult(self): - self.value = self.result + self.LoadContext(self.result_context) + self.LoadValue(self.result_value) def StoreResult(self): - self.result = self.value + self.result_context = self.context + self.result_value = self.value def Jump(self): return self.operand @@ -742,10 +760,11 @@ return self.operand def LoadException(self): - self.value = DataValue(self.exception, self.exception) + self.LoadContext(self.exception) + self.LoadValue(self.exception) def StoreException(self): - self.exception = self.value.ref + self.exception = self.value def ClearException(self): self.exception = None @@ -783,13 +802,13 @@ del self.handler_stack[-nframes:] def CheckException(self): - self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref) + self.status = self.exception is not None and self._CheckInstance(self.exception, self.value) def TestIdentity(self): - self.status = self.value.ref == self.source.ref + self.status = self.value == self.source_value def TestIdentityAddress(self): - self.status = self.value.ref == self.operand + self.status = self.value == self.operand # LoadBoolean is implemented in the generated code. # StoreBoolean is implemented by testing against the True value. @@ -821,22 +840,6 @@ else: return 0 - def _CheckType(self, ref, cls): - data = self.load(ref) - target_data = self.load(cls) - - # Insist on instance vs. class. - - if data.attrcode is None: # absent attrcode == class/module - return 0 - - if target_data.attrcode is not None: # present attrcode == instance - return 0 - - # Return whether the types match. - - return data.classcode == target_data.classcode - def _MakeObject(self, size, ref): # Load the template. data = self.load(ref) @@ -851,21 +854,21 @@ self.save(addr, FragmentObject(occupied, size)) return addr - def _LoadAddressContextCond(self, context, ref, inst_ref): + def _LoadAddressContextCond(self, context, value, inst_value): # Check the instance context against the target's context. # This provides the context overriding for methods. - if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context): + if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_value, context): # Replace the context with the instance. - return DataValue(inst_ref, ref) + return DataValue(inst_value, value) else: - return DataValue(context, ref) + return DataValue(context, value) - def _StoreAddressContext(self, location, context_value, source_value): - if source_value.context is ReplaceableContext: - context = context_value.ref + def _StoreAddressContext(self, location, context, value, source_context, source_value): + if source_context is ReplaceableContext: + context = value else: - context = source_value.context - self.save(location, DataValue(context, source_value.ref)) + context = source_context + self.save(location, DataValue(context, source_value)) # Convenience functions. diff -r 0b8548d6ee4e -r ee5f5b872354 rsvplib.py --- a/rsvplib.py Sun Jun 12 00:57:03 2011 +0200 +++ b/rsvplib.py Sun Jun 12 22:14:36 2011 +0200 @@ -101,7 +101,8 @@ # Return the new object. # Introduce object as context for the new object. - self.machine.result = DataValue(addr, addr) + self.machine.result_context = addr + self.machine.result_value = addr def builtins_logical_op(self, operand_class, op): frame = self.local_sp_stack[-1] @@ -119,7 +120,8 @@ self.machine._CheckInstance(right_value.ref, operand_class)): notimpl = self.constants[NotImplemented] - self.machine.result = DataValue(notimpl, notimpl) + self.machine.result_context = notimpl + self.machine.result_value = notimpl return left_data = left_value.ref + self.instance_data_offset @@ -129,9 +131,11 @@ # NOTE: The data is considered ready to use. if op(self.machine.load(left_data), self.machine.load(right_data)): - self.machine.result = DataValue(self.constants[True], self.constants[True]) + self.machine.result_context = self.constants[True] + self.machine.result_value = self.constants[True] else: - self.machine.result = DataValue(self.constants[False], self.constants[False]) + self.machine.result_context = self.constants[False] + self.machine.result_value = self.constants[False] # Operators. # Although this takes a short-cut by using the operator module, testing is @@ -210,9 +214,11 @@ # NOTE: The data is considered ready to use. if self.machine.load(left_data) != 0: - self.machine.result = DataValue(self.constants[True], self.constants[True]) + self.machine.result_context = self.constants[True] + self.machine.result_value = self.constants[True] else: - self.machine.result = DataValue(self.constants[False], self.constants[False]) + self.machine.result_context = self.constants[False] + self.machine.result_value = self.constants[False] def builtins_int_neg(self): frame = self.local_sp_stack[-1] @@ -241,7 +247,8 @@ # Return the new object. # Introduce object as context for the new object. - self.machine.result = DataValue(addr, addr) + self.machine.result_context = addr + self.machine.result_value = addr # Various built-in methods. @@ -251,7 +258,8 @@ # Get operands addresses. left_value = self.frame_stack[frame] - self.machine.result = DataValue(left_value.ref, left_value.ref) + self.machine.result_context = left_value.ref + self.machine.result_value = left_value.ref def builtins_list_new(self): frame = self.local_sp_stack[-1] @@ -301,7 +309,9 @@ # Get the item itself. - self.machine.result = self.machine.load(fragment.ref + self.fragment_data_offset + item_pos) + data = self.machine.load(fragment.ref + self.fragment_data_offset + item_pos) + self.machine.result_context = data.context + self.machine.result_value = data.ref def builtins_list_len(self): frame = self.local_sp_stack[-1] @@ -331,7 +341,8 @@ # Return the new object. # Introduce object as context for the new object. - self.machine.result = DataValue(addr, addr) + self.machine.result_context = addr + self.machine.result_value = addr def builtins_list_append(self): frame = self.local_sp_stack[-1] @@ -399,7 +410,8 @@ def _builtins_tuple(self, obj_value): if self.machine._CheckInstance(obj_value.ref, self.tuple_class): - self.machine.result = obj_value + self.machine.result_context = obj_value.context + self.machine.result_value = obj_value.ref return # Reject non-list, non-tuple types. @@ -430,7 +442,8 @@ # Return the new object. # Introduce object as context for the new object. - self.machine.result = DataValue(addr, addr) + self.machine.result_context = addr + self.machine.result_value = addr def builtins_tuple_len(self): frame = self.local_sp_stack[-1] @@ -456,7 +469,8 @@ # Return the new object. # Introduce object as context for the new object. - self.machine.result = DataValue(addr, addr) + self.machine.result_context = addr + self.machine.result_value = addr def builtins_tuple_get_single_item(self): frame = self.local_sp_stack[-1] @@ -484,7 +498,9 @@ # Get the item. - self.machine.result = self.machine.load(obj_value.ref + self.instance_data_offset + item_pos) + data = self.machine.load(obj_value.ref + self.instance_data_offset + item_pos) + self.machine.result_context = data.context + self.machine.result_value = data.ref def builtins_object_init(self): pass @@ -514,13 +530,13 @@ attr_index, static_attr, offset = element if attr_index == index: if static_attr: - loaded_value = self.machine.load(offset) # offset is address of class/module attribute - if data.attrcode is None: # absent attrcode == class/module - self.machine.result = loaded_value - else: - self.machine.result = self.machine._LoadAddressContextCond(loaded_value.context, loaded_value.ref, obj_value.ref) + loaded_data = self.machine.load(offset) # offset is address of class/module attribute + if data.attrcode is not None: # absent attrcode == class/module + loaded_data = self.machine._LoadAddressContextCond(loaded_data.context, loaded_data.ref, obj_value.ref) else: - self.machine.result = self.machine.load(obj_value.ref + offset) + loaded_data = self.machine.load(obj_value.ref + offset) + self.machine.result_context = loaded_data.context + self.machine.result_value = loaded_data.ref return self.machine.exception = self.machine._MakeObject(self.instance_size, self.attr_error_instance) @@ -535,9 +551,11 @@ cls_value = self.frame_stack[frame + 1] if self.machine._CheckInstance(obj_value.ref, cls_value.ref): - self.machine.result = DataValue(self.constants[True], self.constants[True]) + self.machine.result_context = self.constants[True] + self.machine.result_value = self.constants[True] else: - self.machine.result = DataValue(self.constants[False], self.constants[False]) + self.machine.result_context = self.constants[False] + self.machine.result_value = self.constants[False] def builtins_print(self): # NOTE: Do nothing for now.