micropython

rsvp.py

402:c87bdb84d9d3
2011-02-27 Paul Boddie Introduced placeholder functions for print in order to let all tests pass. Added TestIdentity and status-related optimisation suggestions.
     1 #!/usr/bin/env python     2      3 """     4 A really simple virtual processor employing a simple set of instructions which     5 ignore low-level operations and merely concentrate on variable access, structure     6 access, structure allocation and function invocations.     7      8 Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>     9     10 This program is free software; you can redistribute it and/or modify it under    11 the terms of the GNU General Public License as published by the Free Software    12 Foundation; either version 3 of the License, or (at your option) any later    13 version.    14     15 This program is distributed in the hope that it will be useful, but WITHOUT    16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    17 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    18 details.    19     20 You should have received a copy of the GNU General Public License along with    21 this program.  If not, see <http://www.gnu.org/licenses/>.    22     23 --------    24     25 The execution model of the virtual processor involves the following things:    26     27   * Memory                          contains constants, global variable    28                                     references and program code    29     30   * PC (program counter) stack      contains the return address associated    31                                     with each function invocation    32     33   * Frame stack                     contains invocation frames in use and in    34                                     preparation plus temporary storage    35     36   * Local frame pointer stack       refers to the frames in the frame stack    37     38   * Invocation frame pointer stack    39     40   * Exception handler stack    41     42   * Exception handler locals stack  refers to the state of the local frame    43                                     pointer stack    44     45   * Exception handler PC stack      refers to the state of the PC stack    46     47   * Registers: current value,    48                boolean status value,    49                source value,    50                current result,    51                current exception,    52                current callable    53 """    54     55 from micropython.program import DataValue, ReplaceableContext, PlaceholderContext, FragmentObject    56 from rsvplib import Library    57     58 class IllegalInstruction(Exception):    59     pass    60     61 class IllegalAddress(Exception):    62     def __init__(self, address):    63         self.address = address    64     def __repr__(self):    65         return "IllegalAddress(%r)" % self.address    66     def __str__(self):    67         return repr(self)    68     69 class EmptyPCStack(Exception):    70     pass    71     72 class EmptyFrameStack(Exception):    73     pass    74     75 class BreakpointReached(Exception):    76     pass    77     78 class RSVPMachine:    79     80     "A really simple virtual processor."    81     82     def __init__(self, memory, objlist, paramlist, pc=None, debug=0, abort_upon_exception=0):    83     84         """    85         Initialise the processor with a 'memory' (a list of values containing    86         instructions and data), the object and parameter lists 'objlist' and    87         'paramlist', and the optional program counter 'pc'.    88         """    89     90         self.memory = memory    91         self._objlist = objlist    92         self._paramlist = paramlist    93         self.objlist = objlist.as_raw()    94         self.paramlist = paramlist.as_raw()    95         self.library = None    96     97         self.pc = pc or 0    98         self.debug = debug    99         self.abort_upon_exception = abort_upon_exception   100    101         # Profiling.   102    103         self.coverage = [0] * len(self.memory)   104         self.counter = 0   105         self.cost = 0   106    107         # Stacks.   108    109         self.pc_stack = []   110         self.frame_stack = []   111         self.local_sp_stack = [0]   112         self.invocation_sp_stack = []   113    114         # Exception handler stacks are used to reset the state of the main   115         # stacks.   116    117         self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code   118         self.handler_local_sp_stack = []   119         self.handler_invocation_sp_stack = []   120         self.handler_pc_stack = []   121    122         # Registers.   123    124         self.instruction = None   125         self.operand = None   126         self.value = None   127         self.status = None   128         self.source = None   129         self.callable = None   130         self.result = None   131         self.exception = None   132    133         # Constants.   134    135         cls = self._get_class("__builtins__", "AttributeError")   136         self.attr_error = cls.location   137         self.attr_error_instance = cls.instance_template_location   138         cls = self._get_class("__builtins__", "TypeError")   139         self.type_error = cls.location   140         self.type_error_instance = cls.instance_template_location   141         cls = self._get_class("__builtins__", "tuple")   142         self.tuple_class = cls.location   143         self.tuple_instance = cls.instance_template_location   144    145         # Debugging attributes.   146    147         self.breakpoints = set()   148    149     def _get_class(self, module, name):   150         attr = self._objlist.access(module, name)   151         if attr is not None:   152             return attr.get_value()   153         else:   154             return None   155    156     # Debugging methods.   157    158     def dump(self):   159         print "PC", self.pc, "->", self.load(self.pc)   160         print "PC stack", self.pc_stack   161         print "Frame stack:"   162         if self.local_sp_stack:   163             start = self.local_sp_stack[0]   164             for end in self.local_sp_stack[1:]:   165                 print "  %2d" % start, self.frame_stack[start:end]   166                 start = end   167             else:   168                 print "  %2d" % start, self.frame_stack[start:]   169         print   170         print "Local stack pointers", self.local_sp_stack   171         print "Invocation stack pointers", self.invocation_sp_stack   172         print "Handler stack", self.handler_stack   173         print "Handler frame stack", self.handler_local_sp_stack   174         print "Handler PC stack", self.handler_pc_stack   175         print   176         print "Instruction", self.instruction   177         print "Operand", self.operand   178         print "Value", self.value   179         print "Status", self.status   180         print "Source", self.source   181         print "Callable", self.callable   182         print "Result", self.result   183         print "Exception", self.exception   184    185     def show(self, start=None, end=None):   186         self.show_memory(self.memory[start:end], self.coverage[start:end], start or 0)   187    188     def show_pc(self, run_in=10):   189         start = max(0, self.pc - run_in)   190         end = self.pc + run_in   191         memory = self.memory[start:end]   192         coverage = self.coverage[start:end]   193         self.show_memory(memory, coverage, start)   194    195     def show_memory(self, memory, coverage, start):   196         for i, (c, x) in enumerate(map(None, coverage, memory)):   197             location = start + i   198             if location == self.pc:   199                 print "->",   200             elif location in self.pc_stack:   201                 print "..",   202             else:   203                 print "  ",   204             print "%-5s %5d %r" % (c or "", location, x)   205    206     def step(self, dump=0):   207         self.execute()   208         self.show_pc()   209         if dump:   210             self.dump()   211    212     def set_break(self, location):   213         self.breakpoints.add(location)   214    215     def up(self):   216         retaddr = self.pc_stack[-1]   217         self.set_break(retaddr)   218         self.run()   219    220     # Internal operations.   221    222     def load(self, address):   223    224         "Return the value at the given 'address'."   225    226         try:   227             return self.memory[address]   228         except IndexError:   229             raise IllegalAddress(address)   230         except TypeError:   231             raise IllegalAddress(address)   232    233     def save(self, address, value):   234    235         "Save to the given 'address' the specified 'value'."   236    237         try:   238             self.memory[address] = value   239         except IndexError:   240             raise IllegalAddress(address)   241         except TypeError:   242             raise IllegalAddress(address)   243    244     def new(self, size):   245    246         """   247         Allocate space of the given 'size', returning the address of the space.   248         """   249    250         addr = len(self.memory)   251         for i in range(0, size):   252             self.memory.append(None)   253         return addr   254    255     def push_pc(self, data):   256    257         "Push 'data' onto the PC stack."   258    259         self.pc_stack.append(data)   260    261     def pull_pc(self):   262    263         "Pull a value from the PC stack and return it."   264    265         try:   266             return self.pc_stack.pop()   267         except IndexError:   268             raise EmptyPCStack   269    270     def run(self):   271    272         "Execute code in the memory, starting from the current PC address."   273    274         breakpoint = 0   275    276         try:   277             while 1:   278                 self.execute()   279         except EmptyPCStack:   280             pass   281         except BreakpointReached:   282             breakpoint = 1   283    284         print "Execution terminated",   285         if self.exception is not None:   286             ref = self.exception   287             addr = self.load(ref + Library.instance_data_offset)   288             print "with exception:", self.load(ref)   289             print "At address %d: %r" % (addr, self.load(addr))   290         elif breakpoint:   291             print "with breakpoint."   292             print "At address", self.pc   293         else:   294             print "successfully."   295         print "After", self.counter, "instructions at cost", self.cost, "units."   296    297     def test(self, module):   298    299         """   300         Test the code in the memory by running the code and investigating the   301         contents of variables. Use 'module' to identify result variables.   302         """   303    304         self.run()   305         success = 1   306    307         if self.exception is None:   308             for name in module.keys():   309                 if name.startswith("result"):   310                     label, expected = name.split("_")   311                     attr = module[name]   312    313                     # NOTE: Assumptions about headers and content made.   314    315                     attr_location = module.location + 1 + attr.position   316                     value = self.load(attr_location)   317    318                     if value is not None:   319                         content = self.load(value.ref + Library.instance_data_offset)   320                         print label, expected, content   321                         success = success and (int(expected) == content)   322                     else:   323                         print label, expected, "missing"   324                         success = 0   325    326             return success   327         else:   328             return 0   329    330     def execute(self):   331    332         "Execute code in the memory at the current PC address."   333    334         if self.pc in self.breakpoints:   335             self.breakpoints.remove(self.pc)   336             raise BreakpointReached   337    338         self.instruction = self.load(self.pc)   339    340         # Process any inputs of the instruction.   341    342         self.process_inputs()   343    344         # Perform the instruction itself.   345    346         next_pc = self.perform(self.instruction)   347    348         # Update the coverage.   349    350         self.coverage[self.pc] += 1   351    352         # Update the program counter.   353    354         if next_pc is None:   355             self.pc += 1   356         else:   357             self.pc = next_pc   358    359     def get_method(self, instruction):   360    361         "Return the handler method for the given 'instruction'."   362    363         instruction_name = instruction.__class__.__name__   364         if self.debug:   365             print "%8d %s" % (self.pc, instruction_name)   366         method = getattr(self, instruction_name, None)   367         if method is None:   368             raise IllegalInstruction, (self.pc, instruction_name)   369         return method   370    371     def perform(self, instruction, is_input=0):   372    373         "Perform the 'instruction', returning the next PC value or None."   374    375         if not is_input:   376             self.counter += 1   377             self.cost += instruction.cost   378         self.operand = instruction.get_operand()   379         method = self.get_method(instruction)   380         return method()   381    382     def process_inputs(self):   383    384         """   385         Process any inputs of the current instruction. This permits any directly   386         connected sub-instructions to produce the effects that separate   387         instructions would otherwise have.   388         """   389    390         value = self.value   391         if self.instruction.source is not None:   392             self.perform(self.instruction.source, 1)   393             self.source = self.value   394         self.value = value   395         if self.instruction.input is not None:   396             self.perform(self.instruction.input, 1)   397    398     def jump(self, addr, next):   399    400         """   401         Jump to the subroutine at (or identified by) 'addr'. If 'addr'   402         identifies a library function then invoke the library function and set   403         PC to 'next' afterwards; otherwise, set PC to 'addr'.   404         """   405    406         # Trap library functions introduced through the use of strings instead   407         # of proper locations.   408    409         if isinstance(addr, str):   410             handler = self.library and self.library.native_functions[addr](self.library)   411             if handler is None:   412                 return next   413             else:   414                 return handler   415         else:   416             self.push_pc(self.pc + 1)   417             return addr   418    419     # Instructions.   420    421     def LoadConst(self):   422         self.value = DataValue(self.operand, self.operand)   423    424     def LoadClass(self):   425         self.value = DataValue(PlaceholderContext, self.operand)   426    427     def LoadFunction(self):   428         self.value = DataValue(ReplaceableContext, self.operand)   429    430     def LoadName(self):   431         frame = self.local_sp_stack[-1]   432         self.value = self.frame_stack[frame + self.operand]   433    434     def StoreName(self):   435         frame = self.local_sp_stack[-1]   436         self.frame_stack[frame + self.operand] = self.source # uses the source value   437    438     LoadTemp = LoadName   439    440     def StoreTemp(self):   441         frame = self.local_sp_stack[-1]   442         self.frame_stack[frame + self.operand] = self.value   443    444     def LoadAddress(self):   445         # Preserve context (potentially null).   446         self.value = self.load(self.operand)   447    448     def LoadAddressContext(self):   449         value = self.load(self.operand)   450         inst_value = self.value   451         self.value = DataValue(inst_value.ref, value.ref)   452    453     def LoadAddressContextCond(self):   454         value = self.load(self.operand)   455         inst_value = self.value   456         self.value = self._LoadAddressContextCond(value.context, value.ref, inst_value.ref)   457    458     def StoreAddress(self):   459         # Preserve context.   460         self.save(self.operand, self.source)   461    462     def StoreAddressContext(self):   463         # Overwrite context if null.   464         context_value = self.value   465         source_value = self.source   466         if source_value.context is ReplaceableContext:   467             context = context_value.ref   468         else:   469             context = source_value.context   470         self.save(self.operand, DataValue(context, source_value.ref))   471    472     def MakeInstance(self):   473         size = self.operand   474         value = self.value   475         # NOTE: Referencing the instance template.   476         addr = self._MakeObject(size, value.ref - Library.instance_template_size)   477         # Introduce object as context for the new object.   478         self.value = DataValue(addr, addr)   479    480     def MakeFragment(self):   481         size = self.operand   482         # Reserve twice the amount of space.   483         addr = self._MakeFragment(size, size * 2)   484         # NOTE: Context is not relevant for fragments.   485         self.value = DataValue(None, addr)   486    487     def LoadAttr(self):   488         value = self.value   489         # Retrieved context should already be appropriate for the instance.   490         # NOTE: Adding 1 to skip any header.   491         self.value = self.load(value.ref + self.operand + 1)   492    493     def StoreAttr(self):   494         value = self.value   495         # Target should already be an instance.   496         # NOTE: Adding 1 to skip any header.   497         self.save(value.ref + self.operand + 1, self.source)   498    499     def LoadAttrIndex(self):   500         value = self.value   501         data = self.load(value.ref)   502         element = self.objlist[data.classcode + self.operand]   503    504         if element is not None:   505             attr_index, static_attr, offset = element   506             if attr_index == self.operand:   507                 if static_attr:   508                     self.value = self.load(offset) # offset is address of class/module attribute   509                 else:   510                     self.value = self.load(value.ref + offset)   511                 return   512    513         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   514         return self.RaiseException()   515    516     # LoadAttrIndexContext not defined.   517    518     def LoadAttrIndexContextCond(self):   519         inst_value = self.value   520         data = self.load(inst_value.ref)   521         element = self.objlist[data.classcode + self.operand]   522    523         if element is not None:   524             attr_index, static_attr, offset = element   525             if attr_index == self.operand:   526                 if static_attr:   527                     loaded_value = self.load(offset) # offset is address of class/module attribute   528                     if data.attrcode is None: # absent attrcode == class/module   529                         self.value = loaded_value   530                     else:   531                         self.value = self._LoadAddressContextCond(loaded_value.context, loaded_value.ref, inst_value.ref)   532                 else:   533                     self.value = self.load(inst_value.ref + offset)   534                 return   535    536         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   537         return self.RaiseException()   538    539     def StoreAttrIndex(self):   540         value = self.value   541         data = self.load(value.ref)   542         element = self.objlist[data.classcode + self.operand]   543    544         if element is not None:   545             attr_index, static_attr, offset = element   546             if attr_index == self.operand:   547                 if static_attr:   548                     self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)   549                     return self.RaiseException()   550                 else:   551                     self.save(value.ref + offset, self.source)   552                     return   553    554         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   555         return self.RaiseException()   556    557     # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden.   558    559     def MakeFrame(self):   560         self.invocation_sp_stack.append(len(self.frame_stack))   561         self.frame_stack.extend([None] * self.operand)   562    563     def DropFrame(self):   564         self.local_sp_stack.pop()   565         frame = self.invocation_sp_stack.pop()   566         del self.frame_stack[frame:] # reset stack before call   567    568     def StoreFrame(self):   569         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   570         self.frame_stack[frame + self.operand] = self.value   571    572     def StoreFrameIndex(self):   573         value = self.value   574         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   575         data = self.load(value.ref)   576         element = self.paramlist[data.funccode + self.operand]   577    578         if element is not None:   579             # NOTE: Need to ensure correct positioning where a context has been generated.   580             param_index, offset = element   581             if param_index == self.operand:   582                 self.frame_stack[frame + offset] = self.source   583                 return   584    585         self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)   586         return self.RaiseException()   587    588     def LoadCallable(self):   589         value = self.value   590         data = self.load(value.ref)   591         self.callable = data.codeaddr   592    593     def StoreCallable(self):   594         value = self.value   595         # NOTE: Should improve the representation and permit direct saving.   596         data = self.load(value.ref)   597         self.save(value.ref, data.with_callable(self.callable))   598    599     def LoadContext(self):   600         value = self.value   601         # NOTE: Omission of the context of the context would make things like   602         # NOTE: self() inside methods impossible.   603         self.value = DataValue(value.context, value.context)   604    605     def CheckContext(self):   606         self.status = self.value.ref is not ReplaceableContext   607    608     def CheckClass(self):   609         value = self.value   610         if value.ref in (ReplaceableContext, PlaceholderContext):   611             self.status = 0   612             return   613    614         data = self.load(value.ref)   615    616         # Classes are not themselves usable as the self argument.   617         # NOTE: This may change at some point.   618         # However, where classes appear as the context, instance   619         # compatibility is required in the first argument.   620    621         self.status = data.attrcode is None # absent attrcode == class   622    623     def CheckFrame(self):   624         (nargs, ndefaults) = self.operand   625    626         # The frame is actually installed as the locals.   627         # Retrieve the context from the first local.   628    629         frame = self.local_sp_stack[-1]   630         nlocals = len(self.frame_stack[frame:])   631    632         if not ((nargs - ndefaults) <= nlocals):   633             raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)   634             self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)   635             return self.RaiseException()   636    637     def CheckExtra(self):   638         nargs = self.operand   639    640         # The frame is actually installed as the locals.   641         # Retrieve the context from the first local.   642    643         frame = self.local_sp_stack[-1]   644         nlocals = len(self.frame_stack[frame:])   645    646         # Provide the extra star parameter if necessary.   647    648         if nlocals == nargs:   649             self.frame_stack.extend([None]) # ExtendFrame(1)   650    651     def FillDefaults(self):   652         value = self.value   653         (nargs, ndefaults) = self.operand   654    655         # The frame is actually installed as the locals.   656    657         frame = self.local_sp_stack[-1]   658         nlocals = len(self.frame_stack[frame:])   659    660         # Support population of defaults.   661         # This involves copying the "attributes" of a function into the frame.   662    663         default = nlocals - (nargs - ndefaults)   664         self.frame_stack.extend([None] * (nargs - nlocals))   665         pos = nlocals   666    667         while pos < nargs:   668             self.frame_stack[frame + pos] = self.load(value.ref + default + 1) # skip header   669             default += 1   670             pos += 1   671    672     def CopyExtra(self):   673         start = self.operand   674    675         # The frame is the source of the extra arguments.   676    677         frame = self.local_sp_stack[-1]   678         nlocals = len(self.frame_stack[frame:])   679    680         # Make a tuple to hold the arguments.   681    682         ref = self._MakeObject(nlocals - start + 1, self.tuple_instance)   683    684         extra = 0   685         pos = start   686    687         while pos < nlocals:   688             self.save(ref + extra + 1, self.frame_stack[frame + pos]) # skip header when storing   689             extra += 1   690             pos += 1   691    692         self.value = DataValue(ref, ref)   693    694     def CheckInstance(self):   695         value = self.value   696         target_value = self.source   697    698         # For the 'self' parameter in an invoked function, the proposed context   699         # ('self') is checked against the target's context.   700    701         self.status = self._CheckInstance(value.ref, target_value.ref)   702    703     def CheckType(self):   704         value = self.value   705         target_value = self.operand   706         self.status = self._CheckType(value.ref, target_value.ref)   707    708     def JumpInFrame(self):   709         codeaddr = self.callable   710         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   711    712     def JumpWithFrame(self):   713         codeaddr = self.callable   714         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   715         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   716    717     def JumpWithFrameDirect(self):   718         operand = self.operand   719         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   720         return self.jump(operand, self.pc + 1) # return to the instruction after this one   721    722     def ExtendFrame(self):   723         self.frame_stack.extend([None] * self.operand)   724    725     def AdjustFrame(self):   726         self.invocation_sp_stack[-1] += self.operand   727    728     def Return(self):   729         return self.pull_pc()   730    731     def LoadResult(self):   732         self.value = self.result   733    734     def StoreResult(self):   735         self.result = self.value   736    737     def Jump(self):   738         return self.operand   739    740     def JumpIfTrue(self):   741         if self.status:   742             return self.operand   743    744     def JumpIfFalse(self):   745         if not self.status:   746             return self.operand   747    748     def LoadException(self):   749         self.value = DataValue(self.exception, self.exception)   750    751     def StoreException(self):   752         self.exception = self.value.ref   753    754     def ClearException(self):   755         self.exception = None   756    757     def RaiseException(self):   758         # NOTE: Adding the program counter as the first attribute after __class__.   759         self.save(self.exception + Library.instance_data_offset, self.pc)   760         # Jumping to the current handler.   761         if self.abort_upon_exception:   762             raise Exception   763         return self.handler_stack[-1]   764    765     def PushHandler(self):   766         self.handler_stack.append(self.operand)   767         self.handler_local_sp_stack.append(len(self.local_sp_stack))   768         self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack))   769         self.handler_pc_stack.append(len(self.pc_stack))   770    771     def PopHandler(self):   772         nframes = self.operand   773         # Get the new local frame pointer and PC stack references.   774         local_sp_top = self.handler_local_sp_stack[-nframes]   775         invocation_sp_top = self.handler_invocation_sp_stack[-nframes]   776         pc_top = self.handler_pc_stack[-nframes]   777         # Reduce the local frame pointer stack to refer to the handler's frame.   778         del self.local_sp_stack[local_sp_top:]   779         # Reduce the invocation frame pointer stack to refer to an outer frame.   780         del self.invocation_sp_stack[invocation_sp_top:]   781         # Reduce the PC stack to discard all superfluous return addresses.   782         del self.pc_stack[pc_top:]   783         # Remove elements from the handler stacks.   784         del self.handler_pc_stack[-nframes:]   785         del self.handler_local_sp_stack[-nframes:]   786         del self.handler_invocation_sp_stack[-nframes:]   787         del self.handler_stack[-nframes:]   788    789     def CheckException(self):   790         self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref)   791    792     def TestIdentity(self):   793         self.status = self.value.ref == self.source.ref   794    795     def TestIdentityAddress(self):   796         self.status = self.value.ref == self.operand   797    798     # LoadBoolean is implemented in the generated code.   799     # StoreBoolean is implemented by testing against the True value.   800    801     def InvertBoolean(self):   802         self.status = not self.status   803    804     # Common implementation details.   805    806     def _CheckInstance(self, ref, cls):   807         data = self.load(ref)   808         target_data = self.load(cls)   809    810         # Insist on instance vs. class.   811    812         if data.attrcode is None: # absent attrcode == class/module   813             return 0   814    815         if target_data.attrcode is not None: # present attrcode == instance   816             return 0   817    818         # Find the table entry for the descendant.   819    820         element = self.objlist[target_data.classcode + data.attrcode]   821    822         if element is not None:   823             attr_index, static_attr, offset = element   824             return attr_index == data.attrcode   825         else:   826             return 0   827    828     def _CheckType(self, ref, cls):   829         data = self.load(ref)   830         target_data = self.load(cls)   831    832         # Insist on instance vs. class.   833    834         if data.attrcode is None: # absent attrcode == class/module   835             return 0   836    837         if target_data.attrcode is not None: # present attrcode == instance   838             return 0   839    840         # Return whether the types match.   841    842         return data.classcode == target_data.classcode   843    844     def _MakeObject(self, size, ref):   845         # Load the template.   846         data = self.load(ref)   847         addr = self.new(size)   848         # Save the header, overriding the size.   849         self.save(addr, data.with_size(size))   850         return addr   851    852     def _MakeFragment(self, occupied, size):   853         addr = self.new(size)   854         # Save the header, overriding the size.   855         self.save(addr, FragmentObject(occupied, size))   856         return addr   857    858     def _LoadAddressContextCond(self, context, ref, inst_ref):   859         # Check the instance context against the target's context.   860         # This provides the context overriding for methods.   861         if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context):   862             # Replace the context with the instance.   863             return DataValue(inst_ref, ref)   864         else:   865             return DataValue(context, ref)   866    867 # Convenience functions.   868    869 def machine(program, with_builtins=0, debug=0, abort_upon_exception=0):   870     print "Making the image..."   871     code = program.get_image(with_builtins)   872     print "Getting raw structures..."   873     ot = program.get_object_table()   874     pt = program.get_parameter_table()   875     objlist = ot.as_list()   876     paramlist = pt.as_list()   877     print "Getting raw image..."   878     rc = program.get_raw_image()   879     print "Initialising the machine..."   880     importer = program.get_importer()   881     constants = {}   882     for x in (True, False, NotImplemented):   883         constants[x] = importer.get_constant(x).location   884     rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception)   885     library = Library(rm, constants)   886     rm.library = library   887     rm.pc = program.code_location   888     print "Returning program occupying %d locations." % len(rm.memory)   889     return rm   890    891 # vim: tabstop=4 expandtab shiftwidth=4