PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/interpreter/astcompiler/assemble.py

https://bitbucket.org/pypy/pypy/
Python | 747 lines | 665 code | 24 blank | 58 comment | 69 complexity | 35109ae875fc3349c588cf69a0c48560 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """Python control flow graph generation and bytecode assembly."""
  2. import os
  3. from rpython.rlib import rfloat
  4. from rpython.rlib.objectmodel import we_are_translated
  5. from pypy.interpreter.astcompiler import ast, misc, symtable
  6. from pypy.interpreter.error import OperationError
  7. from pypy.interpreter.pycode import PyCode
  8. from pypy.tool import stdlib_opcode as ops
  9. class StackDepthComputationError(Exception):
  10. pass
  11. class Instruction(object):
  12. """Represents a single opcode."""
  13. def __init__(self, opcode, arg=0):
  14. self.opcode = opcode
  15. self.arg = arg
  16. self.lineno = 0
  17. self.has_jump = False
  18. def size(self):
  19. """Return the size of bytes of this instruction when it is
  20. encoded.
  21. """
  22. if self.opcode >= ops.HAVE_ARGUMENT:
  23. return (6 if self.arg > 0xFFFF else 3)
  24. return 1
  25. def jump_to(self, target, absolute=False):
  26. """Indicate the target this jump instruction.
  27. The opcode must be a JUMP opcode.
  28. """
  29. self.jump = (target, absolute)
  30. self.has_jump = True
  31. def __repr__(self):
  32. data = [ops.opname[self.opcode]]
  33. template = "<%s"
  34. if self.opcode >= ops.HAVE_ARGUMENT:
  35. data.append(self.arg)
  36. template += " %i"
  37. if self.has_jump:
  38. data.append(self.jump[0])
  39. template += " %s"
  40. template += ">"
  41. return template % tuple(data)
  42. class Block(object):
  43. """A basic control flow block.
  44. It has one entry point and several possible exit points. Its
  45. instructions may be jumps to other blocks, or if control flow
  46. reaches the end of the block, it continues to next_block.
  47. """
  48. marked = False
  49. have_return = False
  50. auto_inserted_return = False
  51. def __init__(self):
  52. self.instructions = []
  53. self.next_block = None
  54. def _post_order_see(self, stack, nextblock):
  55. if nextblock.marked == 0:
  56. nextblock.marked = 1
  57. stack.append(nextblock)
  58. def post_order(self):
  59. """Return this block and its children in post order. This means
  60. that the graph of blocks is first cleaned up to ignore
  61. back-edges, thus turning it into a DAG. Then the DAG is
  62. linearized. For example:
  63. A --> B -\ => [A, D, B, C]
  64. \-> D ---> C
  65. """
  66. resultblocks = []
  67. stack = [self]
  68. self.marked = 1
  69. while stack:
  70. current = stack[-1]
  71. if current.marked == 1:
  72. current.marked = 2
  73. if current.next_block is not None:
  74. self._post_order_see(stack, current.next_block)
  75. else:
  76. i = current.marked - 2
  77. assert i >= 0
  78. while i < len(current.instructions):
  79. instr = current.instructions[i]
  80. i += 1
  81. if instr.has_jump:
  82. current.marked = i + 2
  83. self._post_order_see(stack, instr.jump[0])
  84. break
  85. else:
  86. resultblocks.append(current)
  87. stack.pop()
  88. resultblocks.reverse()
  89. return resultblocks
  90. def code_size(self):
  91. """Return the encoded size of all the instructions in this
  92. block.
  93. """
  94. i = 0
  95. for instr in self.instructions:
  96. i += instr.size()
  97. return i
  98. def get_code(self):
  99. """Encode the instructions in this block into bytecode."""
  100. code = []
  101. for instr in self.instructions:
  102. opcode = instr.opcode
  103. if opcode >= ops.HAVE_ARGUMENT:
  104. arg = instr.arg
  105. if instr.arg > 0xFFFF:
  106. ext = arg >> 16
  107. code.append(chr(ops.EXTENDED_ARG))
  108. code.append(chr(ext & 0xFF))
  109. code.append(chr(ext >> 8))
  110. arg &= 0xFFFF
  111. code.append(chr(opcode))
  112. code.append(chr(arg & 0xFF))
  113. code.append(chr(arg >> 8))
  114. else:
  115. code.append(chr(opcode))
  116. return ''.join(code)
  117. def _make_index_dict_filter(syms, flag):
  118. i = 0
  119. result = {}
  120. for name, scope in syms.iteritems():
  121. if scope == flag:
  122. result[name] = i
  123. i += 1
  124. return result
  125. def _list_to_dict(l, offset=0):
  126. result = {}
  127. index = offset
  128. for i in range(len(l)):
  129. result[l[i]] = index
  130. index += 1
  131. return result
  132. class PythonCodeMaker(ast.ASTVisitor):
  133. """Knows how to assemble a PyCode object."""
  134. def __init__(self, space, name, first_lineno, scope, compile_info):
  135. self.space = space
  136. self.name = name
  137. self.first_lineno = first_lineno
  138. self.compile_info = compile_info
  139. self.first_block = self.new_block()
  140. self.use_block(self.first_block)
  141. self.names = {}
  142. self.var_names = _list_to_dict(scope.varnames)
  143. self.cell_vars = _make_index_dict_filter(scope.symbols,
  144. symtable.SCOPE_CELL)
  145. self.free_vars = _list_to_dict(scope.free_vars, len(self.cell_vars))
  146. self.w_consts = space.newdict()
  147. self.argcount = 0
  148. self.lineno_set = False
  149. self.lineno = 0
  150. self.add_none_to_final_return = True
  151. def new_block(self):
  152. return Block()
  153. def use_block(self, block):
  154. """Start emitting bytecode into block."""
  155. self.current_block = block
  156. self.instrs = block.instructions
  157. def use_next_block(self, block=None):
  158. """Set this block as the next_block for the last and use it."""
  159. if block is None:
  160. block = self.new_block()
  161. self.current_block.next_block = block
  162. self.use_block(block)
  163. return block
  164. def is_dead_code(self):
  165. """Return False if any code can be meaningfully added to the
  166. current block, or True if it would be dead code."""
  167. # currently only True after a RETURN_VALUE.
  168. return self.current_block.have_return
  169. def emit_op(self, op):
  170. """Emit an opcode without an argument."""
  171. instr = Instruction(op)
  172. if not self.lineno_set:
  173. instr.lineno = self.lineno
  174. self.lineno_set = True
  175. if not self.is_dead_code():
  176. self.instrs.append(instr)
  177. if op == ops.RETURN_VALUE:
  178. self.current_block.have_return = True
  179. return instr
  180. def emit_op_arg(self, op, arg):
  181. """Emit an opcode with an integer argument."""
  182. instr = Instruction(op, arg)
  183. if not self.lineno_set:
  184. instr.lineno = self.lineno
  185. self.lineno_set = True
  186. if not self.is_dead_code():
  187. self.instrs.append(instr)
  188. def emit_op_name(self, op, container, name):
  189. """Emit an opcode referencing a name."""
  190. self.emit_op_arg(op, self.add_name(container, name))
  191. def emit_jump(self, op, block_to, absolute=False):
  192. """Emit a jump opcode to another block."""
  193. self.emit_op(op).jump_to(block_to, absolute)
  194. def add_name(self, container, name):
  195. """Get the index of a name in container."""
  196. name = self.scope.mangle(name)
  197. try:
  198. index = container[name]
  199. except KeyError:
  200. index = len(container)
  201. container[name] = index
  202. return index
  203. def add_const(self, obj):
  204. """Add a W_Root to the constant array and return its location."""
  205. space = self.space
  206. # To avoid confusing equal but separate types, we hash store the type
  207. # of the constant in the dictionary. Moreover, we have to keep the
  208. # difference between -0.0 and 0.0 floats, and this recursively in
  209. # tuples.
  210. w_key = self._make_key(obj)
  211. w_len = space.finditem(self.w_consts, w_key)
  212. if w_len is None:
  213. w_len = space.len(self.w_consts)
  214. space.setitem(self.w_consts, w_key, w_len)
  215. if space.int_w(w_len) == 0:
  216. self.scope.doc_removable = False
  217. return space.int_w(w_len)
  218. def _make_key(self, obj):
  219. # see the tests 'test_zeros_not_mixed*' in ../test/test_compiler.py
  220. space = self.space
  221. w_type = space.type(obj)
  222. if space.is_w(w_type, space.w_float):
  223. val = space.float_w(obj)
  224. if val == 0.0 and rfloat.copysign(1., val) < 0:
  225. w_key = space.newtuple([obj, space.w_float, space.w_None])
  226. else:
  227. w_key = space.newtuple([obj, space.w_float])
  228. elif space.is_w(w_type, space.w_complex):
  229. w_real = space.getattr(obj, space.wrap("real"))
  230. w_imag = space.getattr(obj, space.wrap("imag"))
  231. real = space.float_w(w_real)
  232. imag = space.float_w(w_imag)
  233. real_negzero = (real == 0.0 and
  234. rfloat.copysign(1., real) < 0)
  235. imag_negzero = (imag == 0.0 and
  236. rfloat.copysign(1., imag) < 0)
  237. if real_negzero and imag_negzero:
  238. tup = [obj, space.w_complex, space.w_None, space.w_None,
  239. space.w_None]
  240. elif imag_negzero:
  241. tup = [obj, space.w_complex, space.w_None, space.w_None]
  242. elif real_negzero:
  243. tup = [obj, space.w_complex, space.w_None]
  244. else:
  245. tup = [obj, space.w_complex]
  246. w_key = space.newtuple(tup)
  247. elif space.is_w(w_type, space.w_tuple):
  248. result_w = [obj, w_type]
  249. for w_item in space.fixedview(obj):
  250. result_w.append(self._make_key(w_item))
  251. w_key = space.newtuple(result_w[:])
  252. elif isinstance(obj, PyCode):
  253. w_key = space.newtuple([obj, w_type, space.id(obj)])
  254. else:
  255. w_key = space.newtuple([obj, w_type])
  256. return w_key
  257. def load_const(self, obj):
  258. index = self.add_const(obj)
  259. self.emit_op_arg(ops.LOAD_CONST, index)
  260. def update_position(self, lineno, force=False):
  261. """Possibly change the lineno for the next instructions."""
  262. if force or lineno > self.lineno:
  263. self.lineno = lineno
  264. self.lineno_set = False
  265. def _resolve_block_targets(self, blocks):
  266. """Compute the arguments of jump instructions."""
  267. last_extended_arg_count = 0
  268. # The reason for this loop is extended jumps. EXTENDED_ARG
  269. # extends the bytecode size, so it might invalidate the offsets
  270. # we've already given. Thus we have to loop until the number of
  271. # extended args is stable. Any extended jump at all is
  272. # extremely rare, so performance is not too concerning.
  273. while True:
  274. extended_arg_count = 0
  275. offset = 0
  276. force_redo = False
  277. # Calculate the code offset of each block.
  278. for block in blocks:
  279. block.offset = offset
  280. offset += block.code_size()
  281. for block in blocks:
  282. offset = block.offset
  283. for instr in block.instructions:
  284. offset += instr.size()
  285. if instr.has_jump:
  286. target, absolute = instr.jump
  287. op = instr.opcode
  288. # Optimize an unconditional jump going to another
  289. # unconditional jump.
  290. if op == ops.JUMP_ABSOLUTE or op == ops.JUMP_FORWARD:
  291. if target.instructions:
  292. target_op = target.instructions[0].opcode
  293. if target_op == ops.JUMP_ABSOLUTE:
  294. target = target.instructions[0].jump[0]
  295. instr.opcode = ops.JUMP_ABSOLUTE
  296. absolute = True
  297. elif target_op == ops.RETURN_VALUE:
  298. # Replace JUMP_* to a RETURN into
  299. # just a RETURN
  300. instr.opcode = ops.RETURN_VALUE
  301. instr.arg = 0
  302. instr.has_jump = False
  303. # The size of the code changed,
  304. # we have to trigger another pass
  305. force_redo = True
  306. continue
  307. if absolute:
  308. jump_arg = target.offset
  309. else:
  310. jump_arg = target.offset - offset
  311. instr.arg = jump_arg
  312. if jump_arg > 0xFFFF:
  313. extended_arg_count += 1
  314. if (extended_arg_count == last_extended_arg_count and
  315. not force_redo):
  316. break
  317. else:
  318. last_extended_arg_count = extended_arg_count
  319. def _build_consts_array(self):
  320. """Turn the applevel constants dictionary into a list."""
  321. w_consts = self.w_consts
  322. space = self.space
  323. consts_w = [space.w_None] * space.len_w(w_consts)
  324. w_iter = space.iter(w_consts)
  325. first = space.wrap(0)
  326. while True:
  327. try:
  328. w_key = space.next(w_iter)
  329. except OperationError as e:
  330. if not e.match(space, space.w_StopIteration):
  331. raise
  332. break
  333. w_index = space.getitem(w_consts, w_key)
  334. w_constant = space.getitem(w_key, first)
  335. w_constant = misc.intern_if_common_string(space, w_constant)
  336. consts_w[space.int_w(w_index)] = w_constant
  337. return consts_w
  338. def _get_code_flags(self):
  339. """Get an extra flags that should be attached to the code object."""
  340. raise NotImplementedError
  341. def _stacksize(self, blocks):
  342. """Compute co_stacksize."""
  343. for block in blocks:
  344. block.initial_depth = 0
  345. # Assumes that it is sufficient to walk the blocks in 'post-order'.
  346. # This means we ignore all back-edges, but apart from that, we only
  347. # look into a block when all the previous blocks have been done.
  348. self._max_depth = 0
  349. for block in blocks:
  350. depth = self._do_stack_depth_walk(block)
  351. if block.auto_inserted_return and depth != 0:
  352. os.write(2, "StackDepthComputationError in %s at %s:%s\n" % (
  353. self.compile_info.filename, self.name, self.first_lineno))
  354. raise StackDepthComputationError # fatal error
  355. return self._max_depth
  356. def _next_stack_depth_walk(self, nextblock, depth):
  357. if depth > nextblock.initial_depth:
  358. nextblock.initial_depth = depth
  359. def _do_stack_depth_walk(self, block):
  360. depth = block.initial_depth
  361. for instr in block.instructions:
  362. depth += _opcode_stack_effect(instr.opcode, instr.arg)
  363. if depth >= self._max_depth:
  364. self._max_depth = depth
  365. jump_op = instr.opcode
  366. if instr.has_jump:
  367. target_depth = depth
  368. if jump_op == ops.FOR_ITER:
  369. target_depth -= 2
  370. elif (jump_op == ops.SETUP_FINALLY or
  371. jump_op == ops.SETUP_EXCEPT or
  372. jump_op == ops.SETUP_WITH):
  373. if jump_op == ops.SETUP_WITH:
  374. target_depth -= 1 # ignore the w_result just pushed
  375. target_depth += 3 # add [exc_type, exc, unroller]
  376. if target_depth > self._max_depth:
  377. self._max_depth = target_depth
  378. elif (jump_op == ops.JUMP_IF_TRUE_OR_POP or
  379. jump_op == ops.JUMP_IF_FALSE_OR_POP):
  380. depth -= 1
  381. self._next_stack_depth_walk(instr.jump[0], target_depth)
  382. if jump_op == ops.JUMP_ABSOLUTE or jump_op == ops.JUMP_FORWARD:
  383. # Nothing more can occur.
  384. break
  385. elif jump_op == ops.RETURN_VALUE or jump_op == ops.RAISE_VARARGS:
  386. # Nothing more can occur.
  387. break
  388. else:
  389. if block.next_block:
  390. self._next_stack_depth_walk(block.next_block, depth)
  391. return depth
  392. def _build_lnotab(self, blocks):
  393. """Build the line number table for tracebacks and tracing."""
  394. current_line = self.first_lineno
  395. current_off = 0
  396. table = []
  397. push = table.append
  398. for block in blocks:
  399. offset = block.offset
  400. for instr in block.instructions:
  401. if instr.lineno:
  402. # compute deltas
  403. line = instr.lineno - current_line
  404. if line < 0:
  405. continue
  406. addr = offset - current_off
  407. # Python assumes that lineno always increases with
  408. # increasing bytecode address (lnotab is unsigned
  409. # char). Depending on when SET_LINENO instructions
  410. # are emitted this is not always true. Consider the
  411. # code:
  412. # a = (1,
  413. # b)
  414. # In the bytecode stream, the assignment to "a"
  415. # occurs after the loading of "b". This works with
  416. # the C Python compiler because it only generates a
  417. # SET_LINENO instruction for the assignment.
  418. if line or addr:
  419. while addr > 255:
  420. push(chr(255))
  421. push(chr(0))
  422. addr -= 255
  423. while line > 255:
  424. push(chr(addr))
  425. push(chr(255))
  426. line -= 255
  427. addr = 0
  428. push(chr(addr))
  429. push(chr(line))
  430. current_line = instr.lineno
  431. current_off = offset
  432. offset += instr.size()
  433. return ''.join(table)
  434. def assemble(self):
  435. """Build a PyCode object."""
  436. # Unless it's interactive, every code object must end in a return.
  437. if not self.current_block.have_return:
  438. self.use_next_block()
  439. if self.add_none_to_final_return:
  440. self.load_const(self.space.w_None)
  441. self.emit_op(ops.RETURN_VALUE)
  442. self.current_block.auto_inserted_return = True
  443. # Set the first lineno if it is not already explicitly set.
  444. if self.first_lineno == -1:
  445. if self.first_block.instructions:
  446. self.first_lineno = self.first_block.instructions[0].lineno
  447. else:
  448. self.first_lineno = 1
  449. blocks = self.first_block.post_order()
  450. self._resolve_block_targets(blocks)
  451. lnotab = self._build_lnotab(blocks)
  452. stack_depth = self._stacksize(blocks)
  453. consts_w = self._build_consts_array()
  454. names = _list_from_dict(self.names)
  455. var_names = _list_from_dict(self.var_names)
  456. cell_names = _list_from_dict(self.cell_vars)
  457. free_names = _list_from_dict(self.free_vars, len(cell_names))
  458. flags = self._get_code_flags() | self.compile_info.flags
  459. bytecode = ''.join([block.get_code() for block in blocks])
  460. return PyCode(self.space,
  461. self.argcount,
  462. len(self.var_names),
  463. stack_depth,
  464. flags,
  465. bytecode,
  466. list(consts_w),
  467. names,
  468. var_names,
  469. self.compile_info.filename,
  470. self.name,
  471. self.first_lineno,
  472. lnotab,
  473. free_names,
  474. cell_names,
  475. self.compile_info.hidden_applevel)
  476. def _list_from_dict(d, offset=0):
  477. result = [None] * len(d)
  478. for obj, index in d.iteritems():
  479. result[index - offset] = obj
  480. return result
  481. _static_opcode_stack_effects = {
  482. ops.NOP: 0,
  483. ops.STOP_CODE: 0,
  484. ops.POP_TOP: -1,
  485. ops.ROT_TWO: 0,
  486. ops.ROT_THREE: 0,
  487. ops.ROT_FOUR: 0,
  488. ops.DUP_TOP: 1,
  489. ops.UNARY_POSITIVE: 0,
  490. ops.UNARY_NEGATIVE: 0,
  491. ops.UNARY_NOT: 0,
  492. ops.UNARY_CONVERT: 0,
  493. ops.UNARY_INVERT: 0,
  494. ops.LIST_APPEND: -1,
  495. ops.SET_ADD: -1,
  496. ops.MAP_ADD: -2,
  497. ops.STORE_MAP: -2,
  498. ops.BINARY_POWER: -1,
  499. ops.BINARY_MULTIPLY: -1,
  500. ops.BINARY_DIVIDE: -1,
  501. ops.BINARY_MODULO: -1,
  502. ops.BINARY_ADD: -1,
  503. ops.BINARY_SUBTRACT: -1,
  504. ops.BINARY_SUBSCR: -1,
  505. ops.BINARY_FLOOR_DIVIDE: -1,
  506. ops.BINARY_TRUE_DIVIDE: -1,
  507. ops.BINARY_LSHIFT: -1,
  508. ops.BINARY_RSHIFT: -1,
  509. ops.BINARY_AND: -1,
  510. ops.BINARY_OR: -1,
  511. ops.BINARY_XOR: -1,
  512. ops.INPLACE_FLOOR_DIVIDE: -1,
  513. ops.INPLACE_TRUE_DIVIDE: -1,
  514. ops.INPLACE_ADD: -1,
  515. ops.INPLACE_SUBTRACT: -1,
  516. ops.INPLACE_MULTIPLY: -1,
  517. ops.INPLACE_DIVIDE: -1,
  518. ops.INPLACE_MODULO: -1,
  519. ops.INPLACE_POWER: -1,
  520. ops.INPLACE_LSHIFT: -1,
  521. ops.INPLACE_RSHIFT: -1,
  522. ops.INPLACE_AND: -1,
  523. ops.INPLACE_OR: -1,
  524. ops.INPLACE_XOR: -1,
  525. ops.SLICE+0: 0,
  526. ops.SLICE+1: -1,
  527. ops.SLICE+2: -1,
  528. ops.SLICE+3: -2,
  529. ops.STORE_SLICE+0: -2,
  530. ops.STORE_SLICE+1: -3,
  531. ops.STORE_SLICE+2: -3,
  532. ops.STORE_SLICE+3: -4,
  533. ops.DELETE_SLICE+0: -1,
  534. ops.DELETE_SLICE+1: -2,
  535. ops.DELETE_SLICE+2: -2,
  536. ops.DELETE_SLICE+3: -3,
  537. ops.STORE_SUBSCR: -3,
  538. ops.DELETE_SUBSCR: -2,
  539. ops.GET_ITER: 0,
  540. ops.FOR_ITER: 1,
  541. ops.BREAK_LOOP: 0,
  542. ops.CONTINUE_LOOP: 0,
  543. ops.SETUP_LOOP: 0,
  544. ops.PRINT_EXPR: -1,
  545. ops.PRINT_ITEM: -1,
  546. ops.PRINT_NEWLINE: 0,
  547. ops.PRINT_ITEM_TO: -2,
  548. ops.PRINT_NEWLINE_TO: -1,
  549. ops.WITH_CLEANUP: -1,
  550. ops.POP_BLOCK: 0,
  551. ops.END_FINALLY: -3, # assume always 3: we pretend that SETUP_FINALLY
  552. # pushes 3. In truth, it would only push 1 and
  553. # the corresponding END_FINALLY only pops 1.
  554. ops.SETUP_WITH: 1,
  555. ops.SETUP_FINALLY: 0,
  556. ops.SETUP_EXCEPT: 0,
  557. ops.LOAD_LOCALS: 1,
  558. ops.RETURN_VALUE: -1,
  559. ops.EXEC_STMT: -3,
  560. ops.YIELD_VALUE: 0,
  561. ops.BUILD_CLASS: -2,
  562. ops.BUILD_MAP: 1,
  563. ops.COMPARE_OP: -1,
  564. ops.LOOKUP_METHOD: 1,
  565. ops.LOAD_NAME: 1,
  566. ops.STORE_NAME: -1,
  567. ops.DELETE_NAME: 0,
  568. ops.LOAD_FAST: 1,
  569. ops.STORE_FAST: -1,
  570. ops.DELETE_FAST: 0,
  571. ops.LOAD_ATTR: 0,
  572. ops.STORE_ATTR: -2,
  573. ops.DELETE_ATTR: -1,
  574. ops.LOAD_GLOBAL: 1,
  575. ops.STORE_GLOBAL: -1,
  576. ops.DELETE_GLOBAL: 0,
  577. ops.LOAD_CLOSURE: 1,
  578. ops.LOAD_DEREF: 1,
  579. ops.STORE_DEREF: -1,
  580. ops.LOAD_CONST: 1,
  581. ops.IMPORT_STAR: -1,
  582. ops.IMPORT_NAME: -1,
  583. ops.IMPORT_FROM: 1,
  584. ops.JUMP_FORWARD: 0,
  585. ops.JUMP_ABSOLUTE: 0,
  586. ops.JUMP_IF_TRUE_OR_POP: 0,
  587. ops.JUMP_IF_FALSE_OR_POP: 0,
  588. ops.POP_JUMP_IF_TRUE: -1,
  589. ops.POP_JUMP_IF_FALSE: -1,
  590. ops.JUMP_IF_NOT_DEBUG: 0,
  591. ops.BUILD_LIST_FROM_ARG: 1,
  592. }
  593. def _compute_UNPACK_SEQUENCE(arg):
  594. return arg - 1
  595. def _compute_DUP_TOPX(arg):
  596. return arg
  597. def _compute_BUILD_TUPLE(arg):
  598. return 1 - arg
  599. def _compute_BUILD_LIST(arg):
  600. return 1 - arg
  601. def _compute_BUILD_SET(arg):
  602. return 1 - arg
  603. def _compute_MAKE_CLOSURE(arg):
  604. return -arg - 1
  605. def _compute_MAKE_FUNCTION(arg):
  606. return -arg
  607. def _compute_BUILD_SLICE(arg):
  608. if arg == 3:
  609. return -2
  610. else:
  611. return -1
  612. def _compute_RAISE_VARARGS(arg):
  613. return -arg
  614. def _num_args(oparg):
  615. return (oparg % 256) + 2 * (oparg / 256)
  616. def _compute_CALL_FUNCTION(arg):
  617. return -_num_args(arg)
  618. def _compute_CALL_FUNCTION_VAR(arg):
  619. return -_num_args(arg) - 1
  620. def _compute_CALL_FUNCTION_KW(arg):
  621. return -_num_args(arg) - 1
  622. def _compute_CALL_FUNCTION_VAR_KW(arg):
  623. return -_num_args(arg) - 2
  624. def _compute_CALL_METHOD(arg):
  625. return -_num_args(arg) - 1
  626. _stack_effect_computers = {}
  627. for name, func in globals().items():
  628. if name.startswith("_compute_"):
  629. func._always_inline_ = True
  630. _stack_effect_computers[getattr(ops, name[9:])] = func
  631. for op, value in _static_opcode_stack_effects.iteritems():
  632. def func(arg, _value=value):
  633. return _value
  634. func._always_inline_ = True
  635. _stack_effect_computers[op] = func
  636. del name, func, op, value
  637. def _opcode_stack_effect(op, arg):
  638. """Return the stack effect of a opcode an its argument."""
  639. if we_are_translated():
  640. for possible_op in ops.unrolling_opcode_descs:
  641. # EXTENDED_ARG should never get in here.
  642. if possible_op.index == ops.EXTENDED_ARG:
  643. continue
  644. if op == possible_op.index:
  645. return _stack_effect_computers[possible_op.index](arg)
  646. else:
  647. raise AssertionError("unknown opcode: %s" % (op,))
  648. else:
  649. try:
  650. return _static_opcode_stack_effects[op]
  651. except KeyError:
  652. return _stack_effect_computers[op](arg)