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