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", self.frame_stack 162 print "Local stack pointers", self.local_sp_stack 163 print "Invocation stack pointers", self.invocation_sp_stack 164 print "Handler stack", self.handler_stack 165 print "Handler frame stack", self.handler_local_sp_stack 166 print "Handler PC stack", self.handler_pc_stack 167 print 168 print "Instruction", self.instruction 169 print "Operand", self.operand 170 print "Value", self.value 171 print "Status", self.status 172 print "Source", self.source 173 print "Callable", self.callable 174 print "Result", self.result 175 print "Exception", self.exception 176 177 def show(self): 178 self.show_memory(self.memory, self.coverage, 0) 179 180 def show_pc(self, run_in=10): 181 start = max(0, self.pc - run_in) 182 end = self.pc + run_in 183 memory = self.memory[start:end] 184 coverage = self.coverage[start:end] 185 self.show_memory(memory, coverage, start) 186 187 def show_memory(self, memory, coverage, start): 188 for i, (c, x) in enumerate(map(None, coverage, memory)): 189 location = start + i 190 if location == self.pc: 191 print "->", 192 elif location in self.pc_stack: 193 print "..", 194 else: 195 print " ", 196 print "%-5s %5d %r" % (c or "", location, x) 197 198 def step(self, dump=0): 199 self.execute() 200 self.show_pc() 201 if dump: 202 self.dump() 203 204 def set_break(self, location): 205 self.breakpoints.add(location) 206 207 # Internal operations. 208 209 def load(self, address): 210 211 "Return the value at the given 'address'." 212 213 try: 214 return self.memory[address] 215 except IndexError: 216 raise IllegalAddress(address) 217 except TypeError: 218 raise IllegalAddress(address) 219 220 def save(self, address, value): 221 222 "Save to the given 'address' the specified 'value'." 223 224 try: 225 self.memory[address] = value 226 except IndexError: 227 raise IllegalAddress(address) 228 except TypeError: 229 raise IllegalAddress(address) 230 231 def new(self, size): 232 233 """ 234 Allocate space of the given 'size', returning the address of the space. 235 """ 236 237 addr = len(self.memory) 238 for i in range(0, size): 239 self.memory.append(None) 240 return addr 241 242 def push_pc(self, data): 243 244 "Push 'data' onto the PC stack." 245 246 self.pc_stack.append(data) 247 248 def pull_pc(self): 249 250 "Pull a value from the PC stack and return it." 251 252 try: 253 return self.pc_stack.pop() 254 except IndexError: 255 raise EmptyPCStack 256 257 def run(self): 258 259 "Execute code in the memory, starting from the current PC address." 260 261 breakpoint = 0 262 263 try: 264 while 1: 265 self.execute() 266 except EmptyPCStack: 267 pass 268 except BreakpointReached: 269 breakpoint = 1 270 271 print "Execution terminated", 272 if self.exception is not None: 273 ref = self.exception 274 addr = self.load(ref + 1) 275 print "with exception:", self.load(ref) 276 print "At address %d: %r" % (addr, self.load(addr)) 277 elif breakpoint: 278 print "with breakpoint." 279 print "At address", self.pc 280 else: 281 print "successfully." 282 print "After", self.counter, "instructions at cost", self.cost, "units." 283 284 def test(self, module): 285 286 """ 287 Test the code in the memory by running the code and investigating the 288 contents of variables. Use 'module' to identify result variables. 289 """ 290 291 self.run() 292 success = 1 293 294 if self.exception is None: 295 for name in module.keys(): 296 if name.startswith("result"): 297 label, expected = name.split("_") 298 attr = module[name] 299 300 # NOTE: Assumptions about headers and content made. 301 302 attr_location = module.location + 1 + attr.position 303 value = self.load(attr_location) 304 305 if value is not None: 306 content = self.load(value.ref + Library.instance_data_offset) 307 print label, expected, content 308 success = success and (int(expected) == content) 309 else: 310 print label, expected, "missing" 311 success = 0 312 313 return success 314 else: 315 return 0 316 317 def execute(self): 318 319 "Execute code in the memory at the current PC address." 320 321 if self.pc in self.breakpoints: 322 self.breakpoints.remove(self.pc) 323 raise BreakpointReached 324 325 self.instruction = self.load(self.pc) 326 327 # Process any inputs of the instruction. 328 329 self.process_inputs() 330 331 # Perform the instruction itself. 332 333 next_pc = self.perform(self.instruction) 334 335 # Update the coverage. 336 337 self.coverage[self.pc] += 1 338 339 # Update the program counter. 340 341 if next_pc is None: 342 self.pc += 1 343 else: 344 self.pc = next_pc 345 346 def get_method(self, instruction): 347 348 "Return the handler method for the given 'instruction'." 349 350 instruction_name = instruction.__class__.__name__ 351 if self.debug: 352 print "%8d %s" % (self.pc, instruction_name) 353 method = getattr(self, instruction_name, None) 354 if method is None: 355 raise IllegalInstruction, (self.pc, instruction_name) 356 return method 357 358 def perform(self, instruction, is_input=0): 359 360 "Perform the 'instruction', returning the next PC value or None." 361 362 if not is_input: 363 self.counter += 1 364 self.cost += instruction.cost 365 self.operand = instruction.get_operand() 366 method = self.get_method(instruction) 367 return method() 368 369 def process_inputs(self): 370 371 """ 372 Process any inputs of the current instruction. This permits any directly 373 connected sub-instructions to produce the effects that separate 374 instructions would otherwise have. 375 """ 376 377 value = self.value 378 if self.instruction.source is not None: 379 self.perform(self.instruction.source, 1) 380 self.source = self.value 381 self.value = value 382 if self.instruction.input is not None: 383 self.perform(self.instruction.input, 1) 384 385 def jump(self, addr, next): 386 387 """ 388 Jump to the subroutine at (or identified by) 'addr'. If 'addr' 389 identifies a library function then invoke the library function and set 390 PC to 'next' afterwards; otherwise, set PC to 'addr'. 391 """ 392 393 # Trap library functions introduced through the use of strings instead 394 # of proper locations. 395 396 if isinstance(addr, str): 397 handler = self.library and self.library.native_functions[addr](self.library) 398 if handler is None: 399 return next 400 else: 401 return handler 402 else: 403 self.push_pc(self.pc + 1) 404 return addr 405 406 # Instructions. 407 408 def LoadConst(self): 409 self.value = DataValue(self.operand, self.operand) 410 411 def LoadClass(self): 412 self.value = DataValue(PlaceholderContext, self.operand) 413 414 def LoadFunction(self): 415 self.value = DataValue(ReplaceableContext, self.operand) 416 417 def LoadName(self): 418 frame = self.local_sp_stack[-1] 419 self.value = self.frame_stack[frame + self.operand] 420 421 def StoreName(self): 422 frame = self.local_sp_stack[-1] 423 self.frame_stack[frame + self.operand] = self.source # uses the source value 424 425 LoadTemp = LoadName 426 427 def StoreTemp(self): 428 frame = self.local_sp_stack[-1] 429 self.frame_stack[frame + self.operand] = self.value 430 431 def LoadAddress(self): 432 # Preserve context (potentially null). 433 self.value = self.load(self.operand) 434 435 def LoadAddressContext(self): 436 value = self.load(self.operand) 437 inst_value = self.value 438 self.value = DataValue(inst_value.ref, value.ref) 439 440 def LoadAddressContextCond(self): 441 value = self.load(self.operand) 442 inst_value = self.value 443 self.value = self._LoadAddressContextCond(value.context, value.ref, inst_value.ref) 444 445 def StoreAddress(self): 446 # Preserve context. 447 self.save(self.operand, self.source) 448 449 def StoreAddressContext(self): 450 # Overwrite context if null. 451 context_value = self.value 452 source_value = self.source 453 if source_value.context is ReplaceableContext: 454 context = context_value.ref 455 else: 456 context = source_value.context 457 self.save(self.operand, DataValue(context, source_value.ref)) 458 459 def MakeInstance(self): 460 size = self.operand 461 value = self.value 462 # NOTE: Referencing the instance template. 463 addr = self._MakeObject(size, value.ref - 2) 464 # Introduce object as context for the new object. 465 self.value = DataValue(addr, addr) 466 467 def MakeFragment(self): 468 size = self.operand 469 # Reserve twice the amount of space. 470 addr = self._MakeFragment(size, size * 2) 471 # NOTE: Context is not relevant for fragments. 472 self.value = DataValue(None, addr) 473 474 def LoadAttr(self): 475 value = self.value 476 # Retrieved context should already be appropriate for the instance. 477 # NOTE: Adding 1 to skip any header. 478 self.value = self.load(value.ref + self.operand + 1) 479 480 def StoreAttr(self): 481 value = self.value 482 # Target should already be an instance. 483 # NOTE: Adding 1 to skip any header. 484 self.save(value.ref + self.operand + 1, self.source) 485 486 def LoadAttrIndex(self): 487 value = self.value 488 data = self.load(value.ref) 489 element = self.objlist[data.classcode + self.operand] 490 491 if element is not None: 492 attr_index, static_attr, offset = element 493 if attr_index == self.operand: 494 if static_attr: 495 self.value = self.load(offset) # offset is address of class/module attribute 496 else: 497 self.value = self.load(value.ref + offset) 498 return 499 500 self.exception = self._MakeObject(2, self.attr_error_instance) 501 return self.RaiseException() 502 503 # LoadAttrIndexContext not defined. 504 505 def LoadAttrIndexContextCond(self): 506 inst_value = self.value 507 data = self.load(inst_value.ref) 508 element = self.objlist[data.classcode + self.operand] 509 510 if element is not None: 511 attr_index, static_attr, offset = element 512 if attr_index == self.operand: 513 if static_attr: 514 loaded_value = self.load(offset) # offset is address of class/module attribute 515 if data.attrcode is None: # absent attrcode == class/module 516 self.value = loaded_value 517 else: 518 self.value = self._LoadAddressContextCond(loaded_value.context, loaded_value.ref, inst_value.ref) 519 else: 520 self.value = self.load(inst_value.ref + offset) 521 return 522 523 self.exception = self._MakeObject(2, self.attr_error_instance) 524 return self.RaiseException() 525 526 def StoreAttrIndex(self): 527 value = self.value 528 data = self.load(value.ref) 529 element = self.objlist[data.classcode + self.operand] 530 531 if element is not None: 532 attr_index, static_attr, offset = element 533 if attr_index == self.operand: 534 if static_attr: 535 self.exception = self._MakeObject(2, self.type_error_instance) 536 return self.RaiseException() 537 else: 538 self.save(value.ref + offset, self.source) 539 return 540 541 self.exception = self._MakeObject(2, self.attr_error_instance) 542 return self.RaiseException() 543 544 # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden. 545 546 def MakeFrame(self): 547 self.invocation_sp_stack.append(len(self.frame_stack)) 548 self.frame_stack.extend([None] * self.operand) 549 550 def DropFrame(self): 551 self.local_sp_stack.pop() 552 frame = self.invocation_sp_stack.pop() 553 del self.frame_stack[frame:] # reset stack before call 554 555 def StoreFrame(self): 556 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 557 self.frame_stack[frame + self.operand] = self.value 558 559 def StoreFrameIndex(self): 560 value = self.value 561 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 562 data = self.load(value.ref) 563 element = self.paramlist[data.funccode + self.operand] 564 565 if element is not None: 566 # NOTE: Need to ensure correct positioning where a context has been generated. 567 param_index, offset = element 568 if param_index == self.operand: 569 self.frame_stack[frame + offset] = self.source 570 return 571 572 self.exception = self._MakeObject(2, self.type_error_instance) 573 return self.RaiseException() 574 575 def LoadCallable(self): 576 value = self.value 577 data = self.load(value.ref) 578 self.callable = data.codeaddr 579 580 def StoreCallable(self): 581 value = self.value 582 # NOTE: Should improve the representation and permit direct saving. 583 data = self.load(value.ref) 584 self.save(value.ref, data.with_callable(self.callable)) 585 586 def LoadContext(self): 587 value = self.value 588 # NOTE: Omission of the context of the context would make things like 589 # NOTE: self() inside methods impossible. 590 self.value = DataValue(value.context, value.context) 591 592 def CheckContext(self): 593 self.status = self.value.ref is not ReplaceableContext 594 595 def CheckClass(self): 596 value = self.value 597 if value.ref in (ReplaceableContext, PlaceholderContext): 598 self.status = 0 599 return 600 601 data = self.load(value.ref) 602 603 # Classes are not themselves usable as the self argument. 604 # NOTE: This may change at some point. 605 # However, where classes appear as the context, instance 606 # compatibility is required in the first argument. 607 608 self.status = data.attrcode is None # absent attrcode == class 609 610 def CheckFrame(self): 611 (nargs, ndefaults) = self.operand 612 613 # The frame is actually installed as the locals. 614 # Retrieve the context from the first local. 615 616 frame = self.local_sp_stack[-1] 617 nlocals = len(self.frame_stack[frame:]) 618 619 if not ((nargs - ndefaults) <= nlocals): 620 raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) 621 self.exception = self._MakeObject(2, self.type_error_instance) 622 return self.RaiseException() 623 624 def CheckExtra(self): 625 nargs = self.operand 626 627 # The frame is actually installed as the locals. 628 # Retrieve the context from the first local. 629 630 frame = self.local_sp_stack[-1] 631 nlocals = len(self.frame_stack[frame:]) 632 633 # Provide the extra star parameter if necessary. 634 635 if nlocals == nargs: 636 self.frame_stack.extend([None]) # ExtendFrame(1) 637 638 def FillDefaults(self): 639 value = self.value 640 (nargs, ndefaults) = self.operand 641 642 # The frame is actually installed as the locals. 643 644 frame = self.local_sp_stack[-1] 645 nlocals = len(self.frame_stack[frame:]) 646 647 # Support population of defaults. 648 # This involves copying the "attributes" of a function into the frame. 649 650 default = nlocals - (nargs - ndefaults) 651 self.frame_stack.extend([None] * (nargs - nlocals)) 652 pos = nlocals 653 654 while pos < nargs: 655 self.frame_stack[frame + pos] = self.load(value.ref + default + 1) # skip header 656 default += 1 657 pos += 1 658 659 def CopyExtra(self): 660 start = self.operand 661 662 # The frame is the source of the extra arguments. 663 664 frame = self.local_sp_stack[-1] 665 nlocals = len(self.frame_stack[frame:]) 666 667 # Make a tuple to hold the arguments. 668 669 ref = self._MakeObject(nlocals - start + 1, self.tuple_instance) 670 671 extra = 0 672 pos = start 673 674 while pos < nlocals: 675 self.save(ref + extra + 1, self.frame_stack[frame + pos]) # skip header when storing 676 extra += 1 677 pos += 1 678 679 self.value = DataValue(ref, ref) 680 681 def CheckInstance(self): 682 value = self.value 683 target_value = self.source 684 685 # For the 'self' parameter in an invoked function, the proposed context 686 # ('self') is checked against the target's context. 687 688 self.status = self._CheckInstance(value.ref, target_value.ref) 689 690 def CheckType(self): 691 value = self.value 692 target_value = self.operand 693 self.status = self._CheckType(value.ref, target_value.ref) 694 695 def JumpInFrame(self): 696 codeaddr = self.callable 697 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one 698 699 def JumpWithFrame(self): 700 codeaddr = self.callable 701 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 702 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one 703 704 def JumpWithFrameDirect(self): 705 operand = self.operand 706 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 707 return self.jump(operand, self.pc + 1) # return to the instruction after this one 708 709 def ExtendFrame(self): 710 self.frame_stack.extend([None] * self.operand) 711 712 def AdjustFrame(self): 713 self.invocation_sp_stack[-1] += self.operand 714 715 def Return(self): 716 return self.pull_pc() 717 718 def LoadResult(self): 719 self.value = self.result 720 721 def StoreResult(self): 722 self.result = self.value 723 724 def Jump(self): 725 return self.operand 726 727 def JumpIfTrue(self): 728 if self.status: 729 return self.operand 730 731 def JumpIfFalse(self): 732 if not self.status: 733 return self.operand 734 735 def LoadException(self): 736 self.value = DataValue(self.exception, self.exception) 737 738 def StoreException(self): 739 self.exception = self.value.ref 740 741 def ClearException(self): 742 self.exception = None 743 744 def RaiseException(self): 745 # NOTE: Adding the program counter as the first attribute. 746 self.save(self.exception + 1, self.pc) 747 # Jumping to the current handler. 748 if self.abort_upon_exception: 749 raise Exception 750 return self.handler_stack[-1] 751 752 def PushHandler(self): 753 self.handler_stack.append(self.operand) 754 self.handler_local_sp_stack.append(len(self.local_sp_stack)) 755 self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack)) 756 self.handler_pc_stack.append(len(self.pc_stack)) 757 758 def PopHandler(self): 759 nframes = self.operand 760 # Get the new local frame pointer and PC stack references. 761 local_sp_top = self.handler_local_sp_stack[-nframes] 762 invocation_sp_top = self.handler_invocation_sp_stack[-nframes] 763 pc_top = self.handler_pc_stack[-nframes] 764 # Reduce the local frame pointer stack to refer to the handler's frame. 765 del self.local_sp_stack[local_sp_top:] 766 # Reduce the invocation frame pointer stack to refer to an outer frame. 767 del self.invocation_sp_stack[invocation_sp_top:] 768 # Reduce the PC stack to discard all superfluous return addresses. 769 del self.pc_stack[pc_top:] 770 # Remove elements from the handler stacks. 771 del self.handler_pc_stack[-nframes:] 772 del self.handler_local_sp_stack[-nframes:] 773 del self.handler_invocation_sp_stack[-nframes:] 774 del self.handler_stack[-nframes:] 775 776 def CheckException(self): 777 self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref) 778 779 def TestIdentity(self): 780 self.status = self.value.ref == self.source.ref 781 782 def TestIdentityAddress(self): 783 self.status = self.value.ref == self.operand 784 785 # LoadBoolean is implemented in the generated code. 786 # StoreBoolean is implemented by testing against the True value. 787 788 def InvertBoolean(self): 789 self.status = not self.status 790 791 # Common implementation details. 792 793 def _CheckInstance(self, ref, cls): 794 data = self.load(ref) 795 target_data = self.load(cls) 796 797 # Insist on instance vs. class. 798 799 if data.attrcode is None: # absent attrcode == class/module 800 return 0 801 802 if target_data.attrcode is not None: # present attrcode == instance 803 return 0 804 805 # Find the table entry for the descendant. 806 807 element = self.objlist[target_data.classcode + data.attrcode] 808 809 if element is not None: 810 attr_index, static_attr, offset = element 811 return attr_index == data.attrcode 812 else: 813 return 0 814 815 def _CheckType(self, ref, cls): 816 data = self.load(ref) 817 target_data = self.load(cls) 818 819 # Insist on instance vs. class. 820 821 if data.attrcode is None: # absent attrcode == class/module 822 return 0 823 824 if target_data.attrcode is not None: # present attrcode == instance 825 return 0 826 827 # Return whether the types match. 828 829 return data.classcode == target_data.classcode 830 831 def _MakeObject(self, size, ref): 832 # Load the template. 833 data = self.load(ref) 834 addr = self.new(size) 835 # Save the header, overriding the size. 836 self.save(addr, data.with_size(size)) 837 # Copy the __class__ attribute. 838 cls_attr = self.load(ref + 1) 839 self.save(addr + 1, cls_attr) 840 return addr 841 842 def _MakeFragment(self, occupied, size): 843 addr = self.new(size) 844 # Save the header, overriding the size. 845 self.save(addr, FragmentObject(occupied, size)) 846 return addr 847 848 def _LoadAddressContextCond(self, context, ref, inst_ref): 849 # Check the instance context against the target's context. 850 # This provides the context overriding for methods. 851 if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context): 852 # Replace the context with the instance. 853 return DataValue(inst_ref, ref) 854 else: 855 return DataValue(context, ref) 856 857 # Convenience functions. 858 859 def machine(program, with_builtins=0, debug=0, abort_upon_exception=0): 860 print "Making the image..." 861 code = program.get_image(with_builtins) 862 print "Getting raw structures..." 863 ot = program.get_object_table() 864 pt = program.get_parameter_table() 865 objlist = ot.as_list() 866 paramlist = pt.as_list() 867 print "Getting raw image..." 868 rc = program.get_raw_image() 869 print "Initialising the machine..." 870 importer = program.get_importer() 871 constants = {} 872 for x in (True, False, NotImplemented): 873 constants[x] = importer.get_constant(x).location 874 rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception) 875 library = Library(rm, constants) 876 rm.library = library 877 rm.pc = program.code_location 878 print "Returning program occupying %d locations." % len(rm.memory) 879 return rm 880 881 # vim: tabstop=4 expandtab shiftwidth=4