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