micropython

rsvp.py

414:ea8cd6ca4083
2011-05-08 Paul Boddie Fixed the placeholder default for getattr which was a hybrid of the old and new mechanisms for defining such a placeholder.
     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         self._StoreAddressContext(self.operand, context_value, source_value)   467    468     def MakeInstance(self):   469         size = self.operand   470         value = self.value   471         # NOTE: Referencing the instance template.   472         addr = self._MakeObject(size, value.ref - Library.instance_template_size)   473         # Introduce object as context for the new object.   474         self.value = DataValue(addr, addr)   475    476     def MakeFragment(self):   477         size = self.operand   478         # Reserve twice the amount of space.   479         addr = self._MakeFragment(size, size * 2)   480         # NOTE: Context is not relevant for fragments.   481         self.value = DataValue(None, addr)   482    483     def LoadAttr(self):   484         value = self.value   485         # Retrieved context should already be appropriate for the instance.   486         # NOTE: Adding 1 to skip any header.   487         self.value = self.load(value.ref + self.operand + 1)   488    489     def StoreAttr(self):   490         value = self.value   491         # Target should already be an instance.   492         # NOTE: Adding 1 to skip any header.   493         self.save(value.ref + self.operand + 1, self.source)   494    495     def LoadAttrIndex(self):   496         value = self.value   497         data = self.load(value.ref)   498         element = self.objlist[data.classcode + self.operand]   499    500         if element is not None:   501             attr_index, static_attr, offset = element   502             if attr_index == self.operand:   503                 if static_attr:   504                     self.value = self.load(offset) # offset is address of class/module attribute   505                 else:   506                     self.value = self.load(value.ref + offset)   507                 return   508    509         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   510         return self.RaiseException()   511    512     # LoadAttrIndexContext not defined.   513    514     def LoadAttrIndexContextCond(self):   515         inst_value = self.value   516         data = self.load(inst_value.ref)   517         element = self.objlist[data.classcode + self.operand]   518    519         if element is not None:   520             attr_index, static_attr, offset = element   521             if attr_index == self.operand:   522                 if static_attr:   523                     loaded_value = self.load(offset) # offset is address of class/module attribute   524                     if data.attrcode is None: # absent attrcode == class/module   525                         self.value = loaded_value   526                     else:   527                         self.value = self._LoadAddressContextCond(loaded_value.context, loaded_value.ref, inst_value.ref)   528                 else:   529                     self.value = self.load(inst_value.ref + offset)   530                 return   531    532         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   533         return self.RaiseException()   534    535     def StoreAttrIndex(self):   536         value = self.value   537         data = self.load(value.ref)   538         element = self.objlist[data.classcode + self.operand]   539    540         if element is not None:   541             attr_index, static_attr, offset = element   542             if attr_index == self.operand:   543                 if static_attr:   544                     self._StoreAddressContext(offset, value, self.source)   545                     return   546                 else:   547                     self.save(value.ref + offset, self.source)   548                     return   549    550         self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)   551         return self.RaiseException()   552    553     # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden.   554    555     def MakeFrame(self):   556         self.invocation_sp_stack.append(len(self.frame_stack))   557         self.frame_stack.extend([None] * self.operand)   558    559     def DropFrame(self):   560         self.local_sp_stack.pop()   561         frame = self.invocation_sp_stack.pop()   562         del self.frame_stack[frame:] # reset stack before call   563    564     def StoreFrame(self):   565         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   566         self.frame_stack[frame + self.operand] = self.value   567    568     def StoreFrameIndex(self):   569         value = self.value   570         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   571         data = self.load(value.ref)   572         element = self.paramlist[data.funccode + self.operand]   573    574         if element is not None:   575             # NOTE: Need to ensure correct positioning where a context has been generated.   576             param_index, offset = element   577             if param_index == self.operand:   578                 self.frame_stack[frame + offset] = self.source   579                 return   580    581         self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)   582         return self.RaiseException()   583    584     def LoadCallable(self):   585         value = self.value   586         data = self.load(value.ref)   587         self.callable = data.codeaddr   588    589     def StoreCallable(self):   590         value = self.value   591         # NOTE: Should improve the representation and permit direct saving.   592         data = self.load(value.ref)   593         self.save(value.ref, data.with_callable(self.callable))   594    595     def LoadContext(self):   596         value = self.value   597         # NOTE: Omission of the context of the context would make things like   598         # NOTE: self() inside methods impossible.   599         self.value = DataValue(value.context, value.context)   600    601     def CheckContext(self):   602         self.status = self.value.ref is not ReplaceableContext   603    604     def CheckClass(self):   605         value = self.value   606         if value.ref in (ReplaceableContext, PlaceholderContext):   607             self.status = 0   608             return   609    610         data = self.load(value.ref)   611    612         # Classes are not themselves usable as the self argument.   613         # NOTE: This may change at some point.   614         # However, where classes appear as the context, instance   615         # compatibility is required in the first argument.   616    617         self.status = data.attrcode is None # absent attrcode == class   618    619     def CheckFrame(self):   620         (nargs, ndefaults) = self.operand   621    622         # The frame is actually installed as the locals.   623         # Retrieve the context from the first local.   624    625         frame = self.local_sp_stack[-1]   626         nlocals = len(self.frame_stack[frame:])   627    628         if not ((nargs - ndefaults) <= nlocals):   629             raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)   630             self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)   631             return self.RaiseException()   632    633     def CheckExtra(self):   634         nargs = self.operand   635    636         # The frame is actually installed as the locals.   637         # Retrieve the context from the first local.   638    639         frame = self.local_sp_stack[-1]   640         nlocals = len(self.frame_stack[frame:])   641    642         # Provide the extra star parameter if necessary.   643    644         if nlocals == nargs:   645             self.frame_stack.extend([None]) # ExtendFrame(1)   646    647     def FillDefaults(self):   648         value = self.value   649         (nargs, ndefaults) = self.operand   650    651         # The frame is actually installed as the locals.   652    653         frame = self.local_sp_stack[-1]   654         nlocals = len(self.frame_stack[frame:])   655    656         # Support population of defaults.   657         # This involves copying the "attributes" of a function into the frame.   658    659         default = nlocals - (nargs - ndefaults)   660         self.frame_stack.extend([None] * (nargs - nlocals))   661         pos = nlocals   662    663         while pos < nargs:   664             self.frame_stack[frame + pos] = self.load(value.ref + default + 1) # skip header   665             default += 1   666             pos += 1   667    668     def CopyExtra(self):   669         start = self.operand   670    671         # The frame is the source of the extra arguments.   672    673         frame = self.local_sp_stack[-1]   674         nlocals = len(self.frame_stack[frame:])   675    676         # Make a tuple to hold the arguments.   677    678         ref = self._MakeObject(nlocals - start + 1, self.tuple_instance)   679    680         extra = 0   681         pos = start   682    683         while pos < nlocals:   684             self.save(ref + extra + 1, self.frame_stack[frame + pos]) # skip header when storing   685             extra += 1   686             pos += 1   687    688         self.value = DataValue(ref, ref)   689    690     def CheckInstance(self):   691         value = self.value   692         target_value = self.source   693    694         # For the 'self' parameter in an invoked function, the proposed context   695         # ('self') is checked against the target's context.   696    697         self.status = self._CheckInstance(value.ref, target_value.ref)   698    699     def CheckType(self):   700         value = self.value   701         target_value = self.operand   702         self.status = self._CheckType(value.ref, target_value.ref)   703    704     def JumpInFrame(self):   705         codeaddr = self.callable   706         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   707    708     def JumpWithFrame(self):   709         codeaddr = self.callable   710         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   711         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   712    713     def JumpWithFrameDirect(self):   714         operand = self.operand   715         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   716         return self.jump(operand, self.pc + 1) # return to the instruction after this one   717    718     def ExtendFrame(self):   719         self.frame_stack.extend([None] * self.operand)   720    721     def AdjustFrame(self):   722         self.invocation_sp_stack[-1] += self.operand   723    724     def Return(self):   725         return self.pull_pc()   726    727     def LoadResult(self):   728         self.value = self.result   729    730     def StoreResult(self):   731         self.result = self.value   732    733     def Jump(self):   734         return self.operand   735    736     def JumpIfTrue(self):   737         if self.status:   738             return self.operand   739    740     def JumpIfFalse(self):   741         if not self.status:   742             return self.operand   743    744     def LoadException(self):   745         self.value = DataValue(self.exception, self.exception)   746    747     def StoreException(self):   748         self.exception = self.value.ref   749    750     def ClearException(self):   751         self.exception = None   752    753     def RaiseException(self):   754         # NOTE: Adding the program counter as the first attribute after __class__.   755         self.save(self.exception + Library.instance_data_offset, self.pc)   756         # Jumping to the current handler.   757         if self.abort_upon_exception:   758             raise Exception   759         return self.handler_stack[-1]   760    761     def PushHandler(self):   762         self.handler_stack.append(self.operand)   763         self.handler_local_sp_stack.append(len(self.local_sp_stack))   764         self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack))   765         self.handler_pc_stack.append(len(self.pc_stack))   766    767     def PopHandler(self):   768         nframes = self.operand   769         # Get the new local frame pointer and PC stack references.   770         local_sp_top = self.handler_local_sp_stack[-nframes]   771         invocation_sp_top = self.handler_invocation_sp_stack[-nframes]   772         pc_top = self.handler_pc_stack[-nframes]   773         # Reduce the local frame pointer stack to refer to the handler's frame.   774         del self.local_sp_stack[local_sp_top:]   775         # Reduce the invocation frame pointer stack to refer to an outer frame.   776         del self.invocation_sp_stack[invocation_sp_top:]   777         # Reduce the PC stack to discard all superfluous return addresses.   778         del self.pc_stack[pc_top:]   779         # Remove elements from the handler stacks.   780         del self.handler_pc_stack[-nframes:]   781         del self.handler_local_sp_stack[-nframes:]   782         del self.handler_invocation_sp_stack[-nframes:]   783         del self.handler_stack[-nframes:]   784    785     def CheckException(self):   786         self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref)   787    788     def TestIdentity(self):   789         self.status = self.value.ref == self.source.ref   790    791     def TestIdentityAddress(self):   792         self.status = self.value.ref == self.operand   793    794     # LoadBoolean is implemented in the generated code.   795     # StoreBoolean is implemented by testing against the True value.   796    797     def InvertBoolean(self):   798         self.status = not self.status   799    800     # Common implementation details.   801    802     def _CheckInstance(self, ref, cls):   803         data = self.load(ref)   804         target_data = self.load(cls)   805    806         # Insist on instance vs. class.   807    808         if data.attrcode is None: # absent attrcode == class/module   809             return 0   810    811         if target_data.attrcode is not None: # present attrcode == instance   812             return 0   813    814         # Find the table entry for the descendant.   815    816         element = self.objlist[target_data.classcode + data.attrcode]   817    818         if element is not None:   819             attr_index, static_attr, offset = element   820             return attr_index == data.attrcode   821         else:   822             return 0   823    824     def _CheckType(self, ref, cls):   825         data = self.load(ref)   826         target_data = self.load(cls)   827    828         # Insist on instance vs. class.   829    830         if data.attrcode is None: # absent attrcode == class/module   831             return 0   832    833         if target_data.attrcode is not None: # present attrcode == instance   834             return 0   835    836         # Return whether the types match.   837    838         return data.classcode == target_data.classcode   839    840     def _MakeObject(self, size, ref):   841         # Load the template.   842         data = self.load(ref)   843         addr = self.new(size)   844         # Save the header, overriding the size.   845         self.save(addr, data.with_size(size))   846         return addr   847    848     def _MakeFragment(self, occupied, size):   849         addr = self.new(size)   850         # Save the header, overriding the size.   851         self.save(addr, FragmentObject(occupied, size))   852         return addr   853    854     def _LoadAddressContextCond(self, context, ref, inst_ref):   855         # Check the instance context against the target's context.   856         # This provides the context overriding for methods.   857         if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context):   858             # Replace the context with the instance.   859             return DataValue(inst_ref, ref)   860         else:   861             return DataValue(context, ref)   862    863     def _StoreAddressContext(self, location, context_value, source_value):   864         if source_value.context is ReplaceableContext:   865             context = context_value.ref   866         else:   867             context = source_value.context   868         self.save(location, DataValue(context, source_value.ref))   869    870 # Convenience functions.   871    872 def machine(program, with_builtins=0, debug=0, abort_upon_exception=0):   873     print "Making the image..."   874     code = program.get_image(with_builtins)   875     print "Getting raw structures..."   876     ot = program.get_object_table()   877     pt = program.get_parameter_table()   878     objlist = ot.as_list()   879     paramlist = pt.as_list()   880     print "Getting raw image..."   881     rc = program.get_raw_image()   882     print "Initialising the machine..."   883     importer = program.get_importer()   884     constants = {}   885     for x in (True, False, NotImplemented):   886         constants[x] = importer.get_constant(x).location   887     rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception)   888     library = Library(rm, constants)   889     rm.library = library   890     rm.pc = program.code_location   891     print "Returning program occupying %d locations." % len(rm.memory)   892     return rm   893    894 # vim: tabstop=4 expandtab shiftwidth=4