option to show asm and DRY.

Get ready for some 2.3 support
This commit is contained in:
rocky
2016-06-03 09:25:20 -04:00
parent 6bdddb6a58
commit eefbc40eef
11 changed files with 69 additions and 49 deletions

View File

@@ -45,12 +45,17 @@ class Code(object):
class Scanner(object): class Scanner(object):
def __init__(self, version): def __init__(self, version, show_asm=False):
self.version = version self.version = version
self.show_asm = show_asm
# FIXME: DRY # FIXME: DRY
if version == 2.7: if version == 2.7:
from xdis.opcodes import opcode_27 from xdis.opcodes import opcode_27
self.opc = opcode_27 self.opc = opcode_27
elif version == 2.3:
from xdis.opcodes import opcode_23
self.opc = opcode_23
elif version == 2.6: elif version == 2.6:
from xdis.opcodes import opcode_26 from xdis.opcodes import opcode_26
self.opc = opcode_26 self.opc = opcode_26
@@ -281,7 +286,7 @@ class Scanner(object):
target = parent['end'] target = parent['end']
return target return target
def get_scanner(version): def get_scanner(version, show_asm=False):
# Pick up appropriate scanner # Pick up appropriate scanner
# from trepan.api import debug; # from trepan.api import debug;
# debug(start_opts={'startup-profile': True}) # debug(start_opts={'startup-profile': True})
@@ -289,25 +294,28 @@ def get_scanner(version):
# FIXME: see if we can do better # FIXME: see if we can do better
if version == 2.7: if version == 2.7:
import uncompyle6.scanners.scanner27 as scan import uncompyle6.scanners.scanner27 as scan
scanner = scan.Scanner27() scanner = scan.Scanner27(show_asm=show_asm)
elif version == 2.3:
import uncompyle6.scanners.scanner23 as scan
scanner = scan.Scanner23(show_asm)
elif version == 2.6: elif version == 2.6:
import uncompyle6.scanners.scanner26 as scan import uncompyle6.scanners.scanner26 as scan
scanner = scan.Scanner26() scanner = scan.Scanner26(show_asm)
elif version == 2.5: elif version == 2.5:
import uncompyle6.scanners.scanner25 as scan import uncompyle6.scanners.scanner25 as scan
scanner = scan.Scanner25() scanner = scan.Scanner25(show_asm)
elif version == 3.2: elif version == 3.2:
import uncompyle6.scanners.scanner32 as scan import uncompyle6.scanners.scanner32 as scan
scanner = scan.Scanner32() scanner = scan.Scanner32(show_asm)
elif version == 3.3: elif version == 3.3:
import uncompyle6.scanners.scanner33 as scan import uncompyle6.scanners.scanner33 as scan
scanner = scan.Scanner33() scanner = scan.Scanner33(show_asm)
elif version == 3.4: elif version == 3.4:
import uncompyle6.scanners.scanner34 as scan import uncompyle6.scanners.scanner34 as scan
scanner = scan.Scanner34() scanner = scan.Scanner34(show_asm)
elif version == 3.5: elif version == 3.5:
import uncompyle6.scanners.scanner35 as scan import uncompyle6.scanners.scanner35 as scan
scanner = scan.Scanner35() scanner = scan.Scanner35(show_asm)
else: else:
raise RuntimeError("Unsupported Python version %s" % version) raise RuntimeError("Unsupported Python version %s" % version)
return scanner return scanner
@@ -315,9 +323,5 @@ def get_scanner(version):
if __name__ == "__main__": if __name__ == "__main__":
import inspect, uncompyle6 import inspect, uncompyle6
co = inspect.currentframe().f_code co = inspect.currentframe().f_code
scanner = get_scanner(uncompyle6.PYTHON_VERSION) scanner = get_scanner(uncompyle6.PYTHON_VERSION, True)
tokens, customize = scanner.disassemble(co, {}) tokens, customize = scanner.disassemble(co, {})
print('-' * 30)
for t in tokens:
print(t)
pass

View File

@@ -32,8 +32,8 @@ from xdis.bytecode import findlinestarts
import uncompyle6.scanner as scan import uncompyle6.scanner as scan
class Scanner2(scan.Scanner): class Scanner2(scan.Scanner):
def __init__(self, version): def __init__(self, version, show_asm=False):
scan.Scanner.__init__(self, version) scan.Scanner.__init__(self, version, show_asm)
self.pop_jump_if = frozenset([self.opc.PJIF, self.opc.PJIT]) self.pop_jump_if = frozenset([self.opc.PJIF, self.opc.PJIT])
self.jump_forward = frozenset([self.opc.JA, self.opc.JF]) self.jump_forward = frozenset([self.opc.JA, self.opc.JF])
@@ -204,6 +204,13 @@ class Scanner2(scan.Scanner):
tokens.append(Token(op_name, oparg, pattr, offset, linestart)) tokens.append(Token(op_name, oparg, pattr, offset, linestart))
else: else:
tokens.append(Token(replace[offset], oparg, pattr, offset, linestart)) tokens.append(Token(replace[offset], oparg, pattr, offset, linestart))
pass
pass
if self.show_asm:
for t in tokens:
print(t)
print()
return tokens, customize return tokens, customize
def op_size(self, op): def op_size(self, op):

View File

@@ -23,8 +23,8 @@ JUMP_OPs = opcode_25.JUMP_OPs
# The history is that 2.7 support is the cleanest, # The history is that 2.7 support is the cleanest,
# then from that we got 2.6 and so on. # then from that we got 2.6 and so on.
class Scanner25(scan.Scanner26): class Scanner25(scan.Scanner26):
def __init__(self): def __init__(self, show_asm):
scan2.Scanner2.__init__(self, 2.5) scan2.Scanner2.__init__(self, 2.5, show_asm)
self.stmt_opcodes = frozenset([ self.stmt_opcodes = frozenset([
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP, self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
self.opc.SETUP_FINALLY, self.opc.END_FINALLY, self.opc.SETUP_FINALLY, self.opc.END_FINALLY,

View File

@@ -18,8 +18,8 @@ from xdis.opcodes import opcode_26
JUMP_OPs = opcode_26.JUMP_OPs JUMP_OPs = opcode_26.JUMP_OPs
class Scanner26(scan.Scanner2): class Scanner26(scan.Scanner2):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner26, self).__init__(2.6) super(Scanner26, self).__init__(2.6, show_asm)
self.stmt_opcodes = frozenset([ self.stmt_opcodes = frozenset([
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP, self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
self.opc.SETUP_FINALLY, self.opc.END_FINALLY, self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
@@ -251,9 +251,10 @@ class Scanner26(scan.Scanner2):
pass pass
pass pass
# Debug if self.show_asm:
# for t in tokens: for t in tokens:
# print t print(t)
print()
return tokens, customize return tokens, customize
def getOpcodeToDel(self, i): def getOpcodeToDel(self, i):
@@ -586,8 +587,8 @@ class Scanner26(scan.Scanner2):
if (jump_back and jump_back != self.prev[end] if (jump_back and jump_back != self.prev[end]
and code[jump_back + 3] in self.jump_forward): and code[jump_back + 3] in self.jump_forward):
if (code[self.prev[end]] == self.opc.RETURN_VALUE if (code[self.prev[end]] == self.opc.RETURN_VALUE
or code[self.prev[end]] == self.opc.POP_BLOCK or (code[self.prev[end]] == self.opc.POP_BLOCK
and code[self.prev[self.prev[end]]] == self.opc.RETURN_VALUE): and code[self.prev[self.prev[end]]] == self.opc.RETURN_VALUE)):
jump_back = None jump_back = None
if not jump_back: # loop suite ends in return. wtf right? if not jump_back: # loop suite ends in return. wtf right?
jump_back = self.last_instr(start, end, self.opc.JA, start, False) jump_back = self.last_instr(start, end, self.opc.JA, start, False)
@@ -604,7 +605,7 @@ class Scanner26(scan.Scanner2):
else: else:
if self.get_target(jump_back) >= next_line_byte: if self.get_target(jump_back) >= next_line_byte:
jump_back = self.last_instr(start, end, self.opc.JA, start, False) jump_back = self.last_instr(start, end, self.opc.JA, start, False)
if end > jump_back + 4 and code[end] in (self.opc.JF, self.opc.JA): if end > jump_back + 4 and code[end] in self.jump_forward:
if code[jump_back + 4] in (self.opc.JA, self.opc.JF): if code[jump_back + 4] in (self.opc.JA, self.opc.JF):
if self.get_target(jump_back+4) == self.get_target(end): if self.get_target(jump_back+4) == self.get_target(end):
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
@@ -807,9 +808,7 @@ if __name__ == "__main__":
if PYTHON_VERSION == 2.6: if PYTHON_VERSION == 2.6:
import inspect import inspect
co = inspect.currentframe().f_code co = inspect.currentframe().f_code
tokens, customize = Scanner26().disassemble(co) tokens, customize = Scanner26(show_asm=True).disassemble(co)
for t in tokens:
print(t.format())
else: else:
print("Need to be Python 2.6 to demo; I am %s." % print("Need to be Python 2.6 to demo; I am %s." %
PYTHON_VERSION) PYTHON_VERSION)

View File

@@ -17,8 +17,8 @@ from xdis.opcodes import opcode_27
JUMP_OPs = opcode_27.JUMP_OPs JUMP_OPs = opcode_27.JUMP_OPs
class Scanner27(Scanner2): class Scanner27(Scanner2):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner27, self).__init__(2.7) super(Scanner27, self).__init__(2.7, show_asm)
# opcodes that start statements # opcodes that start statements
self.stmt_opcodes = frozenset([ self.stmt_opcodes = frozenset([

View File

@@ -40,8 +40,8 @@ import uncompyle6.scanner as scan
class Scanner3(scan.Scanner): class Scanner3(scan.Scanner):
def __init__(self, version): def __init__(self, version, show_asm=False):
super(Scanner3, self).__init__(version) super(Scanner3, self).__init__(version, show_asm)
def disassemble(self, co, classname=None, code_objects={}): def disassemble(self, co, classname=None, code_objects={}):
""" """

View File

@@ -8,16 +8,15 @@ scanner routine for Python 3.
from __future__ import print_function from __future__ import print_function
import xdis
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
# JUMP_OPs = xdis.opcodes.opcode_32.JUMP_OPs from xdis.opcodes import opcode_32 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
class Scanner32(Scanner3): class Scanner32(Scanner3):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner3, self).__init__(3.2) super(Scanner3, self).__init__(3.2, show_asm)
return return
pass pass

View File

@@ -8,16 +8,15 @@ scanner routine for Python 3.
from __future__ import print_function from __future__ import print_function
from xdis.opcodes import opcode_33 as opc
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_33 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
class Scanner33(Scanner3): class Scanner33(Scanner3):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner3, self).__init__(3.3) super(Scanner3, self).__init__(3.3, show_asm)
return return
pass pass

View File

@@ -17,8 +17,8 @@ JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
class Scanner34(Scanner3): class Scanner34(Scanner3):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner3, self).__init__(3.4) super(Scanner3, self).__init__(3.4, show_asm)
return return
pass pass

View File

@@ -8,17 +8,16 @@ scanner routine for Python 3.
from __future__ import print_function from __future__ import print_function
from xdis.opcodes import opcode_35 as opc
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_35 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
class Scanner35(Scanner3): class Scanner35(Scanner3):
def __init__(self): def __init__(self, show_asm=False):
super(Scanner35, self).__init__(3.5) super(Scanner35, self).__init__(3.5, show_asm)
return return
pass pass

View File

@@ -345,6 +345,16 @@ TABLE_DIRECT = {
'kv2': ( '%c: %c', 1, 2 ), 'kv2': ( '%c: %c', 1, 2 ),
'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ), 'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ),
#######################
# Python 2.3 Additions
#######################
# Import style for 2.0-2.3
'importstmt20': ( '%|import %c\n', 1),
'importstar20': ( '%|from %[1]{pattr} import *\n', ),
'importfrom20': ( '%|from %[1]{pattr} import %c\n', 2 ),
'importlist20': ( '%C', (0, sys.maxint, ', ') ),
####################### #######################
# Python 2.5 Additions # Python 2.5 Additions
####################### #######################
@@ -526,7 +536,11 @@ class SourceWalker(GenericASTTraversal, object):
self.classes = [] self.classes = []
self.pending_newlines = 0 self.pending_newlines = 0
self.hide_internal = True self.hide_internal = True
self.version = version
if 2.0 <= version <= 2.3:
TABLE_DIRECT['tryfinallystmt'] = (
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 4 )
return return
f = property(lambda s: s.params['f'], f = property(lambda s: s.params['f'],
@@ -1658,7 +1672,6 @@ class SourceWalker(GenericASTTraversal, object):
else: else:
defparams = node[:args_node.attr] defparams = node[:args_node.attr]
kw_args, annotate_args = (0, 0) kw_args, annotate_args = (0, 0)
pos_args = args_node.attr
pass pass
if self.version > 3.0 and isLambda and iscode(node[-3].attr): if self.version > 3.0 and isLambda and iscode(node[-3].attr):