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, start=None, end=None): 178 self.show_memory(self.memory[start:end], self.coverage[start:end], start or 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 def up(self): 208 retaddr = self.pc_stack[-1] 209 new_breakpoint = retaddr not in self.breakpoints 210 if new_breakpoint: 211 self.set_break(retaddr) 212 self.run() 213 if new_breakpoint: 214 self.breakpoints.remove(retaddr) 215 216 # Internal operations. 217 218 def load(self, address): 219 220 "Return the value at the given 'address'." 221 222 try: 223 return self.memory[address] 224 except IndexError: 225 raise IllegalAddress(address) 226 except TypeError: 227 raise IllegalAddress(address) 228 229 def save(self, address, value): 230 231 "Save to the given 'address' the specified 'value'." 232 233 try: 234 self.memory[address] = value 235 except IndexError: 236 raise IllegalAddress(address) 237 except TypeError: 238 raise IllegalAddress(address) 239 240 def new(self, size): 241 242 """ 243 Allocate space of the given 'size', returning the address of the space. 244 """ 245 246 addr = len(self.memory) 247 for i in range(0, size): 248 self.memory.append(None) 249 return addr 250 251 def push_pc(self, data): 252 253 "Push 'data' onto the PC stack." 254 255 self.pc_stack.append(data) 256 257 def pull_pc(self): 258 259 "Pull a value from the PC stack and return it." 260 261 try: 262 return self.pc_stack.pop() 263 except IndexError: 264 raise EmptyPCStack 265 266 def run(self): 267 268 "Execute code in the memory, starting from the current PC address." 269 270 breakpoint = 0 271 272 try: 273 while 1: 274 self.execute() 275 except EmptyPCStack: 276 pass 277 except BreakpointReached: 278 breakpoint = 1 279 280 print "Execution terminated", 281 if self.exception is not None: 282 ref = self.exception 283 addr = self.load(ref + Library.instance_data_offset) 284 print "with exception:", self.load(ref) 285 print "At address %d: %r" % (addr, self.load(addr)) 286 elif breakpoint: 287 print "with breakpoint." 288 print "At address", self.pc 289 else: 290 print "successfully." 291 print "After", self.counter, "instructions at cost", self.cost, "units." 292 293 def test(self, module): 294 295 """ 296 Test the code in the memory by running the code and investigating the 297 contents of variables. Use 'module' to identify result variables. 298 """ 299 300 self.run() 301 success = 1 302 303 if self.exception is None: 304 for name in module.keys(): 305 if name.startswith("result"): 306 label, expected = name.split("_") 307 attr = module[name] 308 309 # NOTE: Assumptions about headers and content made. 310 311 attr_location = module.location + 1 + attr.position 312 value = self.load(attr_location) 313 314 if value is not None: 315 content = self.load(value.ref + Library.instance_data_offset) 316 print label, expected, content 317 success = success and (int(expected) == content) 318 else: 319 print label, expected, "missing" 320 success = 0 321 322 return success 323 else: 324 return 0 325 326 def execute(self): 327 328 "Execute code in the memory at the current PC address." 329 330 if self.pc in self.breakpoints: 331 self.breakpoints.remove(self.pc) 332 raise BreakpointReached 333 334 self.instruction = self.load(self.pc) 335 336 # Process any inputs of the instruction. 337 338 self.process_inputs() 339 340 # Perform the instruction itself. 341 342 next_pc = self.perform(self.instruction) 343 344 # Update the coverage. 345 346 self.coverage[self.pc] += 1 347 348 # Update the program counter. 349 350 if next_pc is None: 351 self.pc += 1 352 else: 353 self.pc = next_pc 354 355 def get_method(self, instruction): 356 357 "Return the handler method for the given 'instruction'." 358 359 instruction_name = instruction.__class__.__name__ 360 if self.debug: 361 print "%8d %s" % (self.pc, instruction_name) 362 method = getattr(self, instruction_name, None) 363 if method is None: 364 raise IllegalInstruction, (self.pc, instruction_name) 365 return method 366 367 def perform(self, instruction, is_input=0): 368 369 "Perform the 'instruction', returning the next PC value or None." 370 371 if not is_input: 372 self.counter += 1 373 self.cost += instruction.cost 374 self.operand = instruction.get_operand() 375 method = self.get_method(instruction) 376 return method() 377 378 def process_inputs(self): 379 380 """ 381 Process any inputs of the current instruction. This permits any directly 382 connected sub-instructions to produce the effects that separate 383 instructions would otherwise have. 384 """ 385 386 value = self.value 387 if self.instruction.source is not None: 388 self.perform(self.instruction.source, 1) 389 self.source = self.value 390 self.value = value 391 if self.instruction.input is not None: 392 self.perform(self.instruction.input, 1) 393 394 def jump(self, addr, next): 395 396 """ 397 Jump to the subroutine at (or identified by) 'addr'. If 'addr' 398 identifies a library function then invoke the library function and set 399 PC to 'next' afterwards; otherwise, set PC to 'addr'. 400 """ 401 402 # Trap library functions introduced through the use of strings instead 403 # of proper locations. 404 405 if isinstance(addr, str): 406 handler = self.library and self.library.native_functions[addr](self.library) 407 if handler is None: 408 return next 409 else: 410 return handler 411 else: 412 self.push_pc(self.pc + 1) 413 return addr 414 415 # Instructions. 416 417 def LoadConst(self): 418 self.value = DataValue(self.operand, self.operand) 419 420 def LoadClass(self): 421 self.value = DataValue(PlaceholderContext, self.operand) 422 423 def LoadFunction(self): 424 self.value = DataValue(ReplaceableContext, self.operand) 425 426 def LoadName(self): 427 frame = self.local_sp_stack[-1] 428 self.value = self.frame_stack[frame + self.operand] 429 430 def StoreName(self): 431 frame = self.local_sp_stack[-1] 432 self.frame_stack[frame + self.operand] = self.source # uses the source value 433 434 LoadTemp = LoadName 435 436 def StoreTemp(self): 437 frame = self.local_sp_stack[-1] 438 self.frame_stack[frame + self.operand] = self.value 439 440 def LoadAddress(self): 441 # Preserve context (potentially null). 442 self.value = self.load(self.operand) 443 444 def LoadAddressContext(self): 445 value = self.load(self.operand) 446 inst_value = self.value 447 self.value = DataValue(inst_value.ref, value.ref) 448 449 def LoadAddressContextCond(self): 450 value = self.load(self.operand) 451 inst_value = self.value 452 self.value = self._LoadAddressContextCond(value.context, value.ref, inst_value.ref) 453 454 def StoreAddress(self): 455 # Preserve context. 456 self.save(self.operand, self.source) 457 458 def StoreAddressContext(self): 459 # Overwrite context if null. 460 context_value = self.value 461 source_value = self.source 462 if source_value.context is ReplaceableContext: 463 context = context_value.ref 464 else: 465 context = source_value.context 466 self.save(self.operand, DataValue(context, source_value.ref)) 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 - 2) 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.exception = self._MakeObject(Library.instance_size, self.type_error_instance) 545 return self.RaiseException() 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 + 2, 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 # Copy the __class__ attribute. 847 cls_attr = self.load(ref + 1) 848 self.save(addr + 1, cls_attr) 849 return addr 850 851 def _MakeFragment(self, occupied, size): 852 addr = self.new(size) 853 # Save the header, overriding the size. 854 self.save(addr, FragmentObject(occupied, size)) 855 return addr 856 857 def _LoadAddressContextCond(self, context, ref, inst_ref): 858 # Check the instance context against the target's context. 859 # This provides the context overriding for methods. 860 if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context): 861 # Replace the context with the instance. 862 return DataValue(inst_ref, ref) 863 else: 864 return DataValue(context, ref) 865 866 # Convenience functions. 867 868 def machine(program, with_builtins=0, debug=0, abort_upon_exception=0): 869 print "Making the image..." 870 code = program.get_image(with_builtins) 871 print "Getting raw structures..." 872 ot = program.get_object_table() 873 pt = program.get_parameter_table() 874 objlist = ot.as_list() 875 paramlist = pt.as_list() 876 print "Getting raw image..." 877 rc = program.get_raw_image() 878 print "Initialising the machine..." 879 importer = program.get_importer() 880 constants = {} 881 for x in (True, False, NotImplemented): 882 constants[x] = importer.get_constant(x).location 883 rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception) 884 library = Library(rm, constants) 885 rm.library = library 886 rm.pc = program.code_location 887 print "Returning program occupying %d locations." % len(rm.memory) 888 return rm 889 890 # vim: tabstop=4 expandtab shiftwidth=4