Added function to iterate through nested code objects, llpython.opcode_util.itercodeobjs(), and used it in llpython.addr_flow.

This commit is contained in:
Jon Riehl 2013-06-03 19:12:19 -05:00
commit b5a15a5019
2 changed files with 42 additions and 3 deletions

View file

@ -5,6 +5,7 @@
from __future__ import absolute_import from __future__ import absolute_import
from .byte_flow import BytecodeFlowBuilder from .byte_flow import BytecodeFlowBuilder
from .opcode_util import build_basic_blocks, itercodeobjs
# ______________________________________________________________________ # ______________________________________________________________________
# Class definition(s) # Class definition(s)
@ -79,15 +80,42 @@ def build_addr_flow(func):
cfg = byte_control.build_cfg(func) cfg = byte_control.build_cfg(func)
return AddressFlowBuilder().visit_cfg(cfg) return AddressFlowBuilder().visit_cfg(cfg)
# ______________________________________________________________________
def build_addr_flow_from_co(codeobj):
from .byte_control import ControlFlowBuilder
cfg = ControlFlowBuilder().visit(build_basic_blocks(codeobj),
codeobj.co_argcount)
return AddressFlowBuilder().visit_cfg(cfg)
# ______________________________________________________________________
def build_addr_flows_from_co(root_co):
return dict((co, build_addr_flow_from_co(co))
for co in itercodeobjs(root_co))
# ______________________________________________________________________ # ______________________________________________________________________
# Main (self-test) routine # Main (self-test) routine
def main(*args): def main(*args):
import pprint import pprint
try:
from .tests import llfuncs from .tests import llfuncs
except ImportError:
llfuncs = object()
if not args: if not args:
args = ('pymod',) args = ('pymod',)
for arg in args: for arg in args:
if arg.endswith('.py'):
with open(arg) as in_file:
in_source = in_file.read()
in_codeobj = compile(in_source, arg, 'exec')
flow_map = build_addr_flows_from_co(in_codeobj)
for codeobj, flow in flow_map.items():
print("_" * 70)
print(codeobj)
pprint.pprint(flow)
else:
pprint.pprint(build_addr_flow(getattr(llfuncs, arg))) pprint.pprint(build_addr_flow(getattr(llfuncs, arg)))
# ______________________________________________________________________ # ______________________________________________________________________

View file

@ -1,9 +1,10 @@
#! /usr/bin/env python #! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from collections import namedtuple
import dis import dis
import opcode import opcode
from collections import namedtuple import types
# ______________________________________________________________________ # ______________________________________________________________________
# Module data # Module data
@ -195,6 +196,16 @@ def itercode(code, start = 0):
# ______________________________________________________________________ # ______________________________________________________________________
def itercodeobjs(codeobj):
"Iterator that traverses code objects via the co_consts member."
yield codeobj
for const in codeobj.co_consts:
if isinstance(const, types.CodeType):
for childobj in itercodeobjs(const):
yield childobj
# ______________________________________________________________________
def extendlabels(code, labels = None): def extendlabels(code, labels = None):
"""Extend the set of jump target labels to account for the """Extend the set of jump target labels to account for the
passthrough targets of conditional branches. passthrough targets of conditional branches.