OILS / opy / byterun / pyvm2.py View on Github | oilshell.org

1028 lines, 679 significant
1"""A pure-Python Python bytecode interpreter."""
2# Based on:
3# pyvm2 by Paul Swartz (z3p), from http://www.twistedmatrix.com/users/z3p/
4
5from __future__ import print_function, division
6import linecache
7import operator
8import os
9import repr as repr_lib # Don't conflict with builtin repr()
10import sys
11import traceback
12import types
13
14# Function used in MAKE_FUNCTION, MAKE_CLOSURE
15# Generator used in YIELD_FROM, which we might not need.
16from pyobj import Frame, Block, Function, Generator
17
18from opy.lib import dis
19
20# Create a repr that won't overflow.
21repr_obj = repr_lib.Repr()
22repr_obj.maxother = 120
23repper = repr_obj.repr
24
25VERBOSE = True
26VERBOSE = False
27
28# Different than log
29def debug(msg, *args):
30 if not VERBOSE:
31 return
32
33 debug1(msg, *args)
34
35
36def debug1(msg, *args):
37 if args:
38 msg = msg % args
39 print(msg, file=sys.stderr)
40
41
42class VirtualMachineError(Exception):
43 """For raising errors in the operation of the VM."""
44 pass
45
46
47class GuestException(Exception):
48 """For errors raised by the interpreter program.
49
50 NOTE: I added this because the host traceback was conflated with the guest
51 traceback.
52 """
53
54 def __init__(self, exctype, value, frames):
55 self.exctype = exctype
56 if isinstance(value, GuestException):
57 raise AssertionError
58 self.value = value
59 self.frames = frames
60
61 def __str__(self):
62 parts = []
63 parts.append('Guest Exception Traceback:')
64 parts.append('')
65 for f in self.frames:
66 filename = f.f_code.co_filename
67 lineno = f.line_number()
68 parts.append(
69 '- File "%s", line %d, in %s' %
70 (filename, lineno, f.f_code.co_name))
71 linecache.checkcache(filename)
72 line = linecache.getline(filename, lineno, f.f_globals)
73 if line:
74 parts.append(' ' + line.strip())
75 parts.append('')
76 parts.append('exctype: %s' % self.exctype)
77 parts.append('value: %s' % self.value)
78
79 return '\n'.join(parts) + '\n'
80
81
82def run_code(vm, code, f_globals=None):
83 """Main entry point.
84
85 Used by tests and by execfile.
86 """
87 frame = vm.make_frame(code, f_globals=f_globals)
88 val = vm.run_frame(frame)
89 vm.check_invariants()
90 if os.getenv('BYTERUN_SUMMARY'):
91 debug1('*** Byterun executed for %d ticks', vm.num_ticks)
92 # If we return the number of ticks here, the unit tests break.
93 return val
94
95
96class VirtualMachine(object):
97
98 def __init__(self, subset=False, verbose=VERBOSE):
99 """
100 Args:
101 subset: turn off bytecodes that OPy doesn't need (e.g. print
102 statement, etc.)
103 verbose: turn on logging
104 """
105 self.subset = subset
106 self.more_info = False
107 #self.more_info = True
108 self.verbose = verbose
109 # some objects define __repr__, which means our debug() logging screws
110 # things up! Even though they don't have side effects, this somehow
111 # matters.
112 self.repr_ok = True
113
114 # The call stack of frames.
115 self.frames = []
116 # The current frame.
117 self.frame = None
118 self.return_value = None
119
120 self.last_exception = None
121 self.except_frames = [] # Frames saved for GuestException
122 self.cur_line = None # current line number
123 self.num_ticks = 0
124
125 def top(self):
126 return self.frame.top()
127
128 def pop(self, i=0):
129 return self.frame.pop(i=i)
130
131 def push(self, *vals):
132 self.frame.push(*vals)
133
134 def popn(self, n):
135 return self.frame.popn(n)
136
137 def peek(self, n):
138 return self.frame.peek(n)
139
140 def jump(self, offset):
141 self.frame.jump(offset)
142
143 def make_frame(self, code, callargs={}, f_globals=None, f_locals=None):
144 """
145 Called by self.run_code and Function.__call__.
146 """
147 # NOTE: repper causes problems running code! See testdata/repr_method.py
148 #debug("make_frame: code=%r, callargs=%s", code, repper(callargs))
149 if f_globals is not None:
150 f_globals = f_globals
151 if f_locals is None:
152 f_locals = f_globals
153 elif self.frames:
154 f_globals = self.frame.f_globals
155 f_locals = {}
156 else:
157 f_globals = f_locals = {
158 '__builtins__': __builtins__,
159 '__name__': '__main__',
160 '__doc__': None,
161 '__package__': None,
162 }
163 f_locals.update(callargs)
164 frame = Frame(code, f_globals, f_locals, self.frame)
165 return frame
166
167 def resume_frame(self, frame):
168 """Called by Generator."""
169 frame.f_back = self.frame
170
171 # NOTE: Could raise exceptions!
172 val = self.run_frame(frame)
173
174 frame.f_back = None
175 return val
176
177 def log_tick(self, byteName, arguments, opoffset, linestarts):
178 """ Log arguments, block stack, and data stack for each opcode."""
179 indent = " " * (len(self.frames)-1)
180 stack_rep = repper(self.frame.stack)
181 #block_stack_rep = repper(self.frame.block_stack)
182 # repr_lib is causing problems
183 if self.repr_ok:
184 stack_rep = repr(self.frame.stack)
185 #block_stack_rep = repr(self.frame.block_stack)
186
187 arg_str = ''
188 if arguments and self.repr_ok:
189 arg_str = ' %r' % (arguments[0],)
190
191 # TODO: Should increment
192
193 li = linestarts.get(opoffset, None)
194 if li is not None and self.cur_line != li:
195 self.cur_line = li
196
197 debug('%s%d: %s%s (line %s)', indent, opoffset, byteName, arg_str,
198 self.cur_line)
199 if self.repr_ok:
200 debug(' %sval stack: %s', indent, stack_rep)
201 #debug(' %sblock stack: %s', indent, block_stack_rep)
202 debug('')
203
204 def dispatch(self, byteName, arguments):
205 """ Dispatch by bytename to the corresponding methods.
206 Exceptions are caught and set on the virtual machine."""
207 why = None
208 try:
209 if byteName.startswith('UNARY_'):
210 self.unaryOperator(byteName[6:])
211 elif byteName.startswith('BINARY_'):
212 self.binaryOperator(byteName[7:])
213 elif byteName.startswith('INPLACE_'):
214 self.inplaceOperator(byteName[8:])
215 elif 'SLICE+' in byteName:
216 self.sliceOperator(byteName)
217 else:
218 # dispatch
219 bytecode_fn = getattr(self, 'byte_%s' % byteName, None)
220 if not bytecode_fn: # pragma: no cover
221 raise VirtualMachineError(
222 "unknown bytecode type: %s" % byteName
223 )
224 why = bytecode_fn(*arguments)
225
226 except:
227 # Deal with exceptions encountered while executing the op.
228 self.last_exception = sys.exc_info()[:2] + (None,)
229
230 # NOTE: Why doesn't byterun use this info?
231 #tb = sys.exc_info()[2]
232 #traceback.print_tb(tb)
233
234 #debug1("Caught exception during execution of %s: %d", byteName,
235 # len(self.frames))
236 why = 'exception'
237 self.except_frames = list(self.frames)
238
239 return why
240
241 # Helpers for run_frame
242 def _push_frame(self, frame):
243 self.frames.append(frame)
244 self.frame = frame
245
246 def _pop_frame(self):
247 self.frames.pop()
248 if self.frames:
249 self.frame = self.frames[-1]
250 else:
251 self.frame = None
252
253 def run_frame(self, frame):
254 """Run a frame until it returns or raises an exception.
255
256 This function raises GuestException or returns the return value.
257
258 Corresponds to PyEval_EvalFrameEx in ceval.c. That returns 'PyObject*
259 retval' -- but how does it indicate an exception?
260
261 I think retval is NULL, and then
262
263 """
264 # bytecode offset -> line number
265 #print('frame %s ' % frame)
266 # NOTE: Also done in Frmae.line_number()
267 linestarts = dict(dis.findlinestarts(frame.f_code))
268 #print('STARTS %s ' % linestarts)
269
270 self._push_frame(frame)
271 while True:
272 self.num_ticks += 1
273
274 opoffset = self.frame.f_lasti # For logging only
275 byteName, arguments = self.frame.decode_next()
276 if self.verbose:
277 self.log_tick(byteName, arguments, opoffset, linestarts)
278
279 # When unwinding the block stack, we need to keep track of why we
280 # are doing it.
281
282 # NOTE: In addition to returning why == 'exception', this can also
283 # RAISE GuestException from recursive call via call_function.
284
285 why = self.dispatch(byteName, arguments)
286 if why == 'exception':
287 # TODO: ceval calls PyTraceBack_Here, not sure what that does.
288 pass
289
290 if why == 'reraise':
291 why = 'exception'
292
293 if why != 'yield':
294
295 # NOTE: why is used in a frame INTERNALLY after bytecode dispatch.
296 # But what about ACROSS frames. We need to unwind the call
297 # stack too! How is that done?
298 # I don't want it to be done with GuestException!
299
300 while why and frame.block_stack:
301 debug('WHY %s', why)
302 debug('STACK %s', frame.block_stack)
303 why = self.frame.handle_block_stack(why, self)
304
305 if why:
306 break
307
308 # TODO: handle generator exception state
309
310 self._pop_frame()
311
312 if why == 'exception':
313 exctype, value, tb = self.last_exception
314
315 #debug('exctype: %s' % exctype)
316 #debug('value: %s' % value)
317 #debug('unused tb: %s' % tb)
318
319 if self.more_info:
320 # Recursive function calls can cause this I guess.
321 if isinstance(value, GuestException):
322 raise value
323 else:
324 # Raise an exception with the EMULATED (guest) stack frames.
325 raise GuestException(exctype, value, self.except_frames)
326 else:
327 raise exctype, value, tb
328
329 #debug1('num_ticks: %d' % num_ticks)
330 return self.return_value
331
332 def check_invariants(self):
333 # Check some invariants
334 if self.frames: # pragma: no cover
335 raise VirtualMachineError("Frames left over!")
336 if self.frame and self.frame.stack: # pragma: no cover
337 raise VirtualMachineError("Data left on stack! %r" % self.frame.stack)
338
339 ## Stack manipulation
340
341 def byte_LOAD_CONST(self, const):
342 self.push(const)
343
344 def byte_POP_TOP(self):
345 self.pop()
346
347 def byte_DUP_TOP(self):
348 self.push(self.top())
349
350 def byte_DUP_TOPX(self, count):
351 items = self.popn(count)
352 for i in [1, 2]:
353 self.push(*items)
354
355 def byte_DUP_TOP_TWO(self):
356 # Py3 only
357 a, b = self.popn(2)
358 self.push(a, b, a, b)
359
360 def byte_ROT_TWO(self):
361 a, b = self.popn(2)
362 self.push(b, a)
363
364 def byte_ROT_THREE(self):
365 a, b, c = self.popn(3)
366 self.push(c, a, b)
367
368 def byte_ROT_FOUR(self):
369 a, b, c, d = self.popn(4)
370 self.push(d, a, b, c)
371
372 ## Names
373
374 def byte_LOAD_NAME(self, name):
375 frame = self.frame
376 if name in frame.f_locals:
377 val = frame.f_locals[name]
378 elif name in frame.f_globals:
379 val = frame.f_globals[name]
380 elif name in frame.f_builtins:
381 val = frame.f_builtins[name]
382 else:
383 raise NameError("name '%s' is not defined" % name)
384 self.push(val)
385
386 def byte_STORE_NAME(self, name):
387 self.frame.f_locals[name] = self.pop()
388
389 def byte_DELETE_NAME(self, name):
390 del self.frame.f_locals[name]
391
392 def byte_LOAD_FAST(self, name):
393 if name in self.frame.f_locals:
394 val = self.frame.f_locals[name]
395 else:
396 raise UnboundLocalError(
397 "local variable '%s' referenced before assignment" % name
398 )
399 self.push(val)
400
401 def byte_STORE_FAST(self, name):
402 self.frame.f_locals[name] = self.pop()
403
404 def byte_DELETE_FAST(self, name):
405 del self.frame.f_locals[name]
406
407 def byte_LOAD_GLOBAL(self, name):
408 f = self.frame
409 if name in f.f_globals:
410 val = f.f_globals[name]
411 elif name in f.f_builtins:
412 val = f.f_builtins[name]
413 else:
414 raise NameError("global name '%s' is not defined" % name)
415 self.push(val)
416
417 def byte_STORE_GLOBAL(self, name):
418 f = self.frame
419 f.f_globals[name] = self.pop()
420
421 def byte_LOAD_DEREF(self, name):
422 self.push(self.frame.cells[name].get())
423
424 def byte_STORE_DEREF(self, name):
425 self.frame.cells[name].set(self.pop())
426
427 def byte_LOAD_LOCALS(self):
428 self.push(self.frame.f_locals)
429
430 ## Operators
431
432 UNARY_OPERATORS = {
433 'POSITIVE': operator.pos,
434 'NEGATIVE': operator.neg,
435 'NOT': operator.not_,
436 'CONVERT': repr,
437 'INVERT': operator.invert,
438 }
439
440 def unaryOperator(self, op):
441 x = self.pop()
442 self.push(self.UNARY_OPERATORS[op](x))
443
444 BINARY_OPERATORS = {
445 'POWER': pow,
446 'MULTIPLY': operator.mul,
447 'DIVIDE': getattr(operator, 'div', lambda x, y: None),
448 'FLOOR_DIVIDE': operator.floordiv,
449 'TRUE_DIVIDE': operator.truediv,
450 'MODULO': operator.mod,
451 'ADD': operator.add,
452 'SUBTRACT': operator.sub,
453 'SUBSCR': operator.getitem,
454 'LSHIFT': operator.lshift,
455 'RSHIFT': operator.rshift,
456 'AND': operator.and_,
457 'XOR': operator.xor,
458 'OR': operator.or_,
459 }
460
461 def binaryOperator(self, op):
462 x, y = self.popn(2)
463 self.push(self.BINARY_OPERATORS[op](x, y))
464
465 def inplaceOperator(self, op):
466 x, y = self.popn(2)
467 if op == 'POWER':
468 x **= y
469 elif op == 'MULTIPLY':
470 x *= y
471 elif op in ['DIVIDE', 'FLOOR_DIVIDE']:
472 x //= y
473 elif op == 'TRUE_DIVIDE':
474 x /= y
475 elif op == 'MODULO':
476 x %= y
477 elif op == 'ADD':
478 x += y
479 elif op == 'SUBTRACT':
480 x -= y
481 elif op == 'LSHIFT':
482 x <<= y
483 elif op == 'RSHIFT':
484 x >>= y
485 elif op == 'AND':
486 x &= y
487 elif op == 'XOR':
488 x ^= y
489 elif op == 'OR':
490 x |= y
491 else: # pragma: no cover
492 raise VirtualMachineError("Unknown in-place operator: %r" % op)
493 self.push(x)
494
495 def sliceOperator(self, op):
496 start = 0
497 end = None # we will take this to mean end
498 op, count = op[:-2], int(op[-1])
499 if count == 1:
500 start = self.pop()
501 elif count == 2:
502 end = self.pop()
503 elif count == 3:
504 end = self.pop()
505 start = self.pop()
506 l = self.pop()
507 if end is None:
508 end = len(l)
509 if op.startswith('STORE_'):
510 l[start:end] = self.pop()
511 elif op.startswith('DELETE_'):
512 del l[start:end]
513 else:
514 self.push(l[start:end])
515
516 COMPARE_OPERATORS = [
517 operator.lt,
518 operator.le,
519 operator.eq,
520 operator.ne,
521 operator.gt,
522 operator.ge,
523 lambda x, y: x in y,
524 lambda x, y: x not in y,
525 lambda x, y: x is y,
526 lambda x, y: x is not y,
527 lambda x, y: issubclass(x, Exception) and issubclass(x, y),
528 ]
529
530 def byte_COMPARE_OP(self, opnum):
531 x, y = self.popn(2)
532 self.push(self.COMPARE_OPERATORS[opnum](x, y))
533
534 ## Attributes and indexing
535
536 def byte_LOAD_ATTR(self, attr):
537 obj = self.pop()
538 #debug1('obj=%s, attr=%s', obj, attr)
539 #debug1('dir(obj)=%s', dir(obj))
540 val = getattr(obj, attr)
541 self.push(val)
542
543 def byte_STORE_ATTR(self, name):
544 val, obj = self.popn(2)
545 setattr(obj, name, val)
546
547 def byte_DELETE_ATTR(self, name):
548 obj = self.pop()
549 delattr(obj, name)
550
551 def byte_STORE_SUBSCR(self):
552 val, obj, subscr = self.popn(3)
553 obj[subscr] = val
554
555 def byte_DELETE_SUBSCR(self):
556 obj, subscr = self.popn(2)
557 del obj[subscr]
558
559 ## Building
560
561 def byte_BUILD_TUPLE(self, count):
562 elts = self.popn(count)
563 self.push(tuple(elts))
564
565 def byte_BUILD_LIST(self, count):
566 elts = self.popn(count)
567 self.push(elts)
568
569 def byte_BUILD_SET(self, count):
570 # TODO: Not documented in Py2 docs.
571 elts = self.popn(count)
572 self.push(set(elts))
573
574 def byte_BUILD_MAP(self, size):
575 # size is ignored.
576 self.push({})
577
578 def byte_STORE_MAP(self):
579 the_map, val, key = self.popn(3)
580 the_map[key] = val
581 self.push(the_map)
582
583 def byte_UNPACK_SEQUENCE(self, count):
584 seq = self.pop()
585 for x in reversed(seq):
586 self.push(x)
587
588 def byte_BUILD_SLICE(self, count):
589 if count == 2:
590 x, y = self.popn(2)
591 self.push(slice(x, y))
592 elif count == 3:
593 x, y, z = self.popn(3)
594 self.push(slice(x, y, z))
595 else: # pragma: no cover
596 raise VirtualMachineError("Strange BUILD_SLICE count: %r" % count)
597
598 def byte_LIST_APPEND(self, count):
599 val = self.pop()
600 the_list = self.peek(count)
601 the_list.append(val)
602
603 def byte_SET_ADD(self, count):
604 val = self.pop()
605 the_set = self.peek(count)
606 the_set.add(val)
607
608 def byte_MAP_ADD(self, count):
609 val, key = self.popn(2)
610 the_map = self.peek(count)
611 the_map[key] = val
612
613 ## Printing
614
615 if 0: # Only used in the interactive interpreter, not in modules.
616 def byte_PRINT_EXPR(self):
617 print(self.pop())
618
619 def byte_PRINT_ITEM(self):
620 item = self.pop()
621 self.print_item(item)
622
623 def byte_PRINT_ITEM_TO(self):
624 to = self.pop()
625 item = self.pop()
626 self.print_item(item, to)
627
628 def byte_PRINT_NEWLINE(self):
629 self.print_newline()
630
631 def byte_PRINT_NEWLINE_TO(self):
632 to = self.pop()
633 self.print_newline(to)
634
635 def print_item(self, item, to=None):
636 if to is None:
637 to = sys.stdout
638 if to.softspace:
639 print(" ", end="", file=to)
640 to.softspace = 0
641 print(item, end="", file=to)
642 if isinstance(item, str):
643 if (not item) or (not item[-1].isspace()) or (item[-1] == " "):
644 to.softspace = 1
645 else:
646 to.softspace = 1
647
648 def print_newline(self, to=None):
649 if to is None:
650 to = sys.stdout
651 print("", file=to)
652 to.softspace = 0
653
654 ## Jumps
655
656 def byte_JUMP_FORWARD(self, jump):
657 self.jump(jump)
658
659 def byte_JUMP_ABSOLUTE(self, jump):
660 self.jump(jump)
661
662 if 0: # Not in py2.7
663 def byte_JUMP_IF_TRUE(self, jump):
664 val = self.top()
665 if val:
666 self.jump(jump)
667
668 def byte_JUMP_IF_FALSE(self, jump):
669 val = self.top()
670 if not val:
671 self.jump(jump)
672
673 def byte_POP_JUMP_IF_TRUE(self, jump):
674 val = self.pop()
675 if val:
676 self.jump(jump)
677
678 def byte_POP_JUMP_IF_FALSE(self, jump):
679 val = self.pop()
680 if not val:
681 self.jump(jump)
682
683 def byte_JUMP_IF_TRUE_OR_POP(self, jump):
684 val = self.top()
685 if val:
686 self.jump(jump)
687 else:
688 self.pop()
689
690 def byte_JUMP_IF_FALSE_OR_POP(self, jump):
691 val = self.top()
692 if not val:
693 self.jump(jump)
694 else:
695 self.pop()
696
697 ## Blocks
698
699 def byte_SETUP_LOOP(self, dest):
700 self.frame.push_block('loop', dest)
701
702 def byte_GET_ITER(self):
703 self.push(iter(self.pop()))
704
705 def byte_FOR_ITER(self, jump):
706 iterobj = self.top()
707 try:
708 v = next(iterobj)
709 self.push(v)
710 except StopIteration:
711 self.pop()
712 self.jump(jump)
713
714 def byte_BREAK_LOOP(self):
715 return 'break'
716
717 def byte_CONTINUE_LOOP(self, dest):
718 # This is a trick with the return value.
719 # While unrolling blocks, continue and return both have to preserve
720 # state as the finally blocks are executed. For continue, it's
721 # where to jump to, for return, it's the value to return. It gets
722 # pushed on the stack for both, so continue puts the jump destination
723 # into return_value.
724 self.return_value = dest
725 return 'continue'
726
727 def byte_SETUP_EXCEPT(self, dest):
728 self.frame.push_block('setup-except', dest)
729
730 def byte_SETUP_FINALLY(self, dest):
731 self.frame.push_block('finally', dest)
732
733 def byte_END_FINALLY(self):
734 v = self.pop()
735 #debug('V %s', v)
736 if isinstance(v, str):
737 why = v
738 if why in ('return', 'continue'):
739 self.return_value = self.pop()
740 elif v is None:
741 why = None
742 elif issubclass(v, BaseException):
743 exctype = v
744 val = self.pop()
745 tb = self.pop()
746 self.last_exception = (exctype, val, tb)
747
748 why = 'reraise'
749 else: # pragma: no cover
750 raise VirtualMachineError("Confused END_FINALLY")
751 return why
752
753 def byte_POP_BLOCK(self):
754 self.frame.pop_block()
755
756 def byte_RAISE_VARARGS(self, argc):
757 # NOTE: the dis docs are completely wrong about the order of the
758 # operands on the stack!
759 exctype = val = tb = None
760 if argc == 0:
761 exctype, val, tb = self.last_exception
762 elif argc == 1:
763 exctype = self.pop()
764 elif argc == 2:
765 val = self.pop()
766 exctype = self.pop()
767 elif argc == 3:
768 tb = self.pop()
769 val = self.pop()
770 exctype = self.pop()
771
772 # There are a number of forms of "raise", normalize them somewhat.
773 if isinstance(exctype, BaseException):
774 val = exctype
775 exctype = type(val)
776
777 self.last_exception = (exctype, val, tb)
778
779 if tb:
780 return 'reraise'
781 else:
782 return 'exception'
783
784 def byte_SETUP_WITH(self, dest):
785 ctxmgr = self.pop()
786 self.push(ctxmgr.__exit__)
787 ctxmgr_obj = ctxmgr.__enter__()
788 self.frame.push_block('with', dest)
789 self.push(ctxmgr_obj)
790
791 def byte_WITH_CLEANUP(self):
792 # The code here does some weird stack manipulation: the exit function
793 # is buried in the stack, and where depends on what's on top of it.
794 # Pull out the exit function, and leave the rest in place.
795 v = w = None
796 u = self.top()
797 if u is None:
798 exit_func = self.pop(1)
799 elif isinstance(u, str):
800 if u in ('return', 'continue'):
801 exit_func = self.pop(2)
802 else:
803 exit_func = self.pop(1)
804 u = None
805 elif issubclass(u, BaseException):
806 w, v, u = self.popn(3)
807 exit_func = self.pop()
808 self.push(w, v, u)
809 else: # pragma: no cover
810 raise VirtualMachineError("Confused WITH_CLEANUP")
811 exit_ret = exit_func(u, v, w)
812 err = (u is not None) and bool(exit_ret)
813 if err:
814 # An error occurred, and was suppressed
815 self.popn(3)
816 self.push(None)
817
818 ## Functions
819
820 def byte_MAKE_FUNCTION(self, argc):
821 """Make a runtime object from a types.CodeObject, typically in a .pyc file."""
822 name = None
823 code = self.pop()
824 defaults = self.popn(argc)
825 globs = self.frame.f_globals
826 fn = Function(name, code, globs, defaults, None, self)
827 self.push(fn)
828
829 def byte_LOAD_CLOSURE(self, name):
830 self.push(self.frame.cells[name])
831
832 def byte_MAKE_CLOSURE(self, argc):
833 name = None
834 closure, code = self.popn(2)
835 defaults = self.popn(argc)
836 globs = self.frame.f_globals
837 fn = Function(name, code, globs, defaults, closure, self)
838 self.push(fn)
839
840 def byte_CALL_FUNCTION(self, arg):
841 return self.call_function(arg, [], {})
842
843 def byte_CALL_FUNCTION_VAR(self, arg):
844 args = self.pop()
845 return self.call_function(arg, args, {})
846
847 def byte_CALL_FUNCTION_KW(self, arg):
848 kwargs = self.pop()
849 return self.call_function(arg, [], kwargs)
850
851 def byte_CALL_FUNCTION_VAR_KW(self, arg):
852 args, kwargs = self.popn(2)
853 return self.call_function(arg, args, kwargs)
854
855 def call_function(self, arg, args, kwargs):
856 len_kw, len_pos = divmod(arg, 256)
857 namedargs = {}
858 for i in xrange(len_kw):
859 key, val = self.popn(2)
860 namedargs[key] = val
861 namedargs.update(kwargs)
862 posargs = self.popn(len_pos)
863 posargs.extend(args)
864
865 #debug('*** call_function stack = %s', self.frame.stack)
866
867 func = self.pop()
868 #debug1('*** call_function POPPED %s', func)
869 if getattr(func, 'func_name', None) == 'decode_next':
870 raise AssertionError('BAD: %s' % func)
871
872 frame = self.frame
873 if hasattr(func, 'im_func'):
874 # Methods get self as an implicit first parameter.
875
876 #debug('')
877 #debug('im_self %r', (func.im_self,))
878 #debug('posargs %r', (posargs,))
879
880 if func.im_self is not None:
881 posargs.insert(0, func.im_self)
882
883 #debug('posargs AFTER %r', (posargs,))
884
885 # TODO: We have the frame here, but I also want the location.
886 # dis has it!
887
888 # The first parameter must be the correct type.
889 if not isinstance(posargs[0], func.im_class):
890 # Must match Python interpreter to pass unit tests!
891 if self.more_info:
892 # More informative error that shows the frame.
893 raise TypeError(
894 'unbound method %s() must be called with %s instance '
895 'as first argument, was called with %s instance '
896 '(frame: %s)' % (
897 func.im_func.func_name,
898 func.im_class.__name__,
899 type(posargs[0]).__name__,
900 #posargs[0],
901 self.frame,
902 )
903 )
904 else:
905 raise TypeError(
906 'unbound method %s() must be called with %s instance '
907 'as first argument (got %s instance instead)' % (
908 func.im_func.func_name,
909 func.im_class.__name__,
910 type(posargs[0]).__name__,
911 )
912 )
913 func = func.im_func
914
915 # BUG FIX: The callable must be a pyobj.Function, not a native Python
916 # function (types.FunctionType). The latter will be executed using the
917 # HOST CPython interpreter rather than the byterun interpreter.
918
919 # Cases:
920 # 1. builtin functions like int(). We want to use the host here.
921 # 2. User-defined functions from this module. These are created with
922 # MAKE_FUNCTION, which properly turns them into pyobj.Function.
923 # 3. User-defined function from another module. These are created with
924 # __import__, which yields a native function.
925 # 4. pyobj.Generator is on the stack, and you get its next() value.
926 # We should do something smarter.
927
928 # This check is broken!
929 # next() and send() that is a native python function. We DO NOT need
930 # to wrap it.
931
932 do_wrap = False
933 #debug1('FUNC %s', dir(func))
934 if isinstance(func, types.FunctionType):
935 do_wrap = True
936
937 # Hack for case #4.
938 if getattr(func, '__doc__', None) == 'DO_NOT_INTERPRET':
939 do_wrap = False
940 #raise AssertionError
941
942 #debug1('do_wrap: %s', do_wrap)
943
944 if do_wrap:
945 #debug1('*** WRAPPING %s', func)
946 #debug1('%s', dir(func))
947 #debug1('__doc__ %s', func.__doc__)
948
949 defaults = func.func_defaults or ()
950 byterun_func = Function(
951 func.func_name, func.func_code, func.func_globals,
952 defaults, func.func_closure, self)
953 else:
954 byterun_func = func
955
956 #debug1(' Calling: %s', byterun_func)
957 retval = byterun_func(*posargs, **namedargs)
958 self.push(retval)
959
960 def byte_RETURN_VALUE(self):
961 self.return_value = self.pop()
962 if self.frame.generator:
963 self.frame.generator.finished = True
964 return "return"
965
966 def byte_YIELD_VALUE(self):
967 self.return_value = self.pop()
968 return "yield"
969
970 def byte_YIELD_FROM(self):
971 u = self.pop()
972 x = self.top()
973
974 try:
975 if not isinstance(x, Generator) or u is None:
976 # Call next on iterators.
977 retval = next(x)
978 else:
979 retval = x.send(u)
980 self.return_value = retval
981 except StopIteration as e:
982 self.pop()
983 self.push(e.value)
984 else:
985 # YIELD_FROM decrements f_lasti, so that it will be called
986 # repeatedly until a StopIteration is raised.
987 self.jump(self.frame.f_lasti - 1)
988 # Returning "yield" prevents the block stack cleanup code
989 # from executing, suspending the frame in its current state.
990 return "yield"
991
992 ## Importing
993
994 def byte_IMPORT_NAME(self, name):
995 level, fromlist = self.popn(2)
996 frame = self.frame
997
998 # NOTE: This can read .pyc files not compiled with OPy!
999 # TODO: Respect OPY_PATH
1000
1001 #debug1('IMPORT name=%s fromlist=%s level=%s', name, fromlist, level)
1002
1003 mod = __import__(name, frame.f_globals, frame.f_locals, fromlist, level)
1004
1005 #debug1('IMPORTED %s -> %s' % (name, mod))
1006
1007 self.push(mod)
1008
1009 def byte_IMPORT_STAR(self):
1010 # TODO: this doesn't use __all__ properly.
1011 mod = self.pop()
1012 for attr in dir(mod):
1013 if attr[0] != '_':
1014 self.frame.f_locals[attr] = getattr(mod, attr)
1015
1016 def byte_IMPORT_FROM(self, name):
1017 mod = self.top()
1018 self.push(getattr(mod, name))
1019
1020 ## And the rest...
1021
1022 def byte_EXEC_STMT(self):
1023 stmt, globs, locs = self.popn(3)
1024 exec stmt in globs, locs
1025
1026 def byte_BUILD_CLASS(self):
1027 name, bases, methods = self.popn(3)
1028 self.push(type(name, bases, methods))