You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
modification of LIST_APPEND opcode handling
This commit is contained in:
@@ -13,6 +13,7 @@ hasjabs = []
|
|||||||
haslocal = []
|
haslocal = []
|
||||||
hascompare = []
|
hascompare = []
|
||||||
hasfree = []
|
hasfree = []
|
||||||
|
hasArgumentExtended = []
|
||||||
PJIF = PJIT = JA = JF = 0
|
PJIF = PJIT = JA = JF = 0
|
||||||
|
|
||||||
opmap = {}
|
opmap = {}
|
||||||
@@ -37,6 +38,10 @@ def jabs_op(name, op):
|
|||||||
def_op(name, op)
|
def_op(name, op)
|
||||||
hasjabs.append(op)
|
hasjabs.append(op)
|
||||||
|
|
||||||
|
def def_extArg(name, op):
|
||||||
|
def_op(name, op)
|
||||||
|
hasArgumentExtended.append(op)
|
||||||
|
|
||||||
def updateGlobal():
|
def updateGlobal():
|
||||||
globals().update({'PJIF': opmap['JUMP_IF_FALSE']})
|
globals().update({'PJIF': opmap['JUMP_IF_FALSE']})
|
||||||
globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
|
globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
|
||||||
@@ -63,7 +68,7 @@ def_op('UNARY_CONVERT', 13) # 25
|
|||||||
|
|
||||||
def_op('UNARY_INVERT', 15) # 34
|
def_op('UNARY_INVERT', 15) # 34
|
||||||
|
|
||||||
def_op('LIST_APPEND', 18) # 68
|
def_extArg('LIST_APPEND', 18) # 68
|
||||||
def_op('BINARY_POWER', 19) # 28
|
def_op('BINARY_POWER', 19) # 28
|
||||||
def_op('BINARY_MULTIPLY', 20) # 36
|
def_op('BINARY_MULTIPLY', 20) # 36
|
||||||
def_op('BINARY_DIVIDE', 21) # 12
|
def_op('BINARY_DIVIDE', 21) # 12
|
||||||
|
@@ -13,6 +13,7 @@ hasjabs = []
|
|||||||
haslocal = []
|
haslocal = []
|
||||||
hascompare = []
|
hascompare = []
|
||||||
hasfree = []
|
hasfree = []
|
||||||
|
hasArgumentExtended = []
|
||||||
PJIF = PJIT = JA = JF = 0
|
PJIF = PJIT = JA = JF = 0
|
||||||
|
|
||||||
opmap = {}
|
opmap = {}
|
||||||
@@ -37,6 +38,10 @@ def jabs_op(name, op):
|
|||||||
def_op(name, op)
|
def_op(name, op)
|
||||||
hasjabs.append(op)
|
hasjabs.append(op)
|
||||||
|
|
||||||
|
def def_extArg(name, op):
|
||||||
|
def_op(name, op)
|
||||||
|
hasArgumentExtended.append(op)
|
||||||
|
|
||||||
def updateGlobal():
|
def updateGlobal():
|
||||||
globals().update({'PJIF': opmap['JUMP_IF_FALSE']})
|
globals().update({'PJIF': opmap['JUMP_IF_FALSE']})
|
||||||
globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
|
globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
|
||||||
@@ -63,7 +68,7 @@ def_op('UNARY_CONVERT', 13)
|
|||||||
|
|
||||||
def_op('UNARY_INVERT', 15)
|
def_op('UNARY_INVERT', 15)
|
||||||
|
|
||||||
def_op('LIST_APPEND', 18)
|
def_extArg('LIST_APPEND', 18)
|
||||||
def_op('BINARY_POWER', 19)
|
def_op('BINARY_POWER', 19)
|
||||||
def_op('BINARY_MULTIPLY', 20)
|
def_op('BINARY_MULTIPLY', 20)
|
||||||
def_op('BINARY_DIVIDE', 21)
|
def_op('BINARY_DIVIDE', 21)
|
||||||
|
@@ -13,6 +13,7 @@ hasjabs = []
|
|||||||
haslocal = []
|
haslocal = []
|
||||||
hascompare = []
|
hascompare = []
|
||||||
hasfree = []
|
hasfree = []
|
||||||
|
hasArgumentExtended = []
|
||||||
PJIF = PJIT = JA = JF = 0
|
PJIF = PJIT = JA = JF = 0
|
||||||
|
|
||||||
opmap = {}
|
opmap = {}
|
||||||
@@ -133,6 +134,7 @@ name_op('DELETE_NAME', 91) # ""
|
|||||||
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
|
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
|
||||||
jrel_op('FOR_ITER', 93)
|
jrel_op('FOR_ITER', 93)
|
||||||
def_op('LIST_APPEND', 94)
|
def_op('LIST_APPEND', 94)
|
||||||
|
|
||||||
name_op('STORE_ATTR', 95) # Index in name list
|
name_op('STORE_ATTR', 95) # Index in name list
|
||||||
name_op('DELETE_ATTR', 96) # ""
|
name_op('DELETE_ATTR', 96) # ""
|
||||||
name_op('STORE_GLOBAL', 97) # ""
|
name_op('STORE_GLOBAL', 97) # ""
|
||||||
|
@@ -206,13 +206,16 @@ class Scanner(object):
|
|||||||
elif t == target:
|
elif t == target:
|
||||||
result.append(i)
|
result.append(i)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def op_size(self, op):
|
def op_size(self, op):
|
||||||
if op < self.opc.HAVE_ARGUMENT:
|
if op < self.opc.HAVE_ARGUMENT and op not in self.opc.hasArgumentExtended:
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
|
def op_hasArgument(self, op):
|
||||||
|
return self.op_size(op) > 1
|
||||||
|
|
||||||
def op_range(self, start, end):
|
def op_range(self, start, end):
|
||||||
while start < end:
|
while start < end:
|
||||||
yield start
|
yield start
|
||||||
|
@@ -31,13 +31,10 @@ class Scanner25(scan.Scanner):
|
|||||||
customize = {}
|
customize = {}
|
||||||
Token = self.Token # shortcut
|
Token = self.Token # shortcut
|
||||||
self.code = array('B', co.co_code)
|
self.code = array('B', co.co_code)
|
||||||
n = len(self.code)
|
|
||||||
# linestarts contains bloc code adresse (addr,block)
|
# linestarts contains bloc code adresse (addr,block)
|
||||||
self.linestarts = list(dis.findlinestarts(co))
|
self.linestarts = list(dis.findlinestarts(co))
|
||||||
self.prev = [0]
|
self.prev = [0]
|
||||||
# change jump struct
|
|
||||||
self.restructRelativeJump()
|
|
||||||
|
|
||||||
# class and names
|
# class and names
|
||||||
if classname:
|
if classname:
|
||||||
classname = '_' + classname.lstrip('_') + '__'
|
classname = '_' + classname.lstrip('_') + '__'
|
||||||
@@ -54,40 +51,18 @@ class Scanner25(scan.Scanner):
|
|||||||
names = co.co_names
|
names = co.co_names
|
||||||
varnames = co.co_varnames
|
varnames = co.co_varnames
|
||||||
self.names = names
|
self.names = names
|
||||||
# add instruction to remonde in "toDel" list
|
|
||||||
toDel = []
|
# list of instruction to remove/add or change to match with bytecode 2.7
|
||||||
# add instruction to change in "toChange" list
|
|
||||||
self.toChange = []
|
self.toChange = []
|
||||||
for i in self.op_range(0, n):
|
self.restructBytecode()
|
||||||
op = self.code[i]
|
codelen = len(self.code)
|
||||||
ret = self.getOpcodeToDel(i)
|
|
||||||
if ret != None:
|
|
||||||
toDel += ret
|
|
||||||
|
|
||||||
#self.print_bytecode()
|
|
||||||
|
|
||||||
if toDel:
|
|
||||||
toDel = sorted(list(set(toDel)))
|
|
||||||
delta = 0
|
|
||||||
self.restructCode(toDel)
|
|
||||||
for x in toDel:
|
|
||||||
if self.code[x-delta] >= HAVE_ARGUMENT:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 3
|
|
||||||
else:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 1
|
|
||||||
|
|
||||||
# mapping adresses of prev instru
|
# mapping adresses of prev instru
|
||||||
n = len(self.code)
|
for i in self.op_range(0, codelen):
|
||||||
for i in self.op_range(0, n):
|
|
||||||
op = self.code[i]
|
op = self.code[i]
|
||||||
self.prev.append(i)
|
self.prev.append(i)
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
self.prev.append(i)
|
|
||||||
self.prev.append(i)
|
self.prev.append(i)
|
||||||
|
self.prev.append(i)
|
||||||
j = 0
|
j = 0
|
||||||
linestarts = self.linestarts
|
linestarts = self.linestarts
|
||||||
self.lines = []
|
self.lines = []
|
||||||
@@ -100,17 +75,16 @@ class Scanner25(scan.Scanner):
|
|||||||
j += 1
|
j += 1
|
||||||
last_op = self.code[self.prev[start_byte]]
|
last_op = self.code[self.prev[start_byte]]
|
||||||
(prev_start_byte, prev_line_no) = (start_byte, line_no)
|
(prev_start_byte, prev_line_no) = (start_byte, line_no)
|
||||||
while j < n:
|
while j < codelen:
|
||||||
self.lines.append(linetuple(prev_line_no, n))
|
self.lines.append(linetuple(prev_line_no, codelen))
|
||||||
j+=1
|
j+=1
|
||||||
# self.lines contains (block,addrLastInstr)
|
# self.lines contains (block,addrLastInstr)
|
||||||
cf = self.find_jump_targets(self.code)
|
cf = self.find_jump_targets(self.code)
|
||||||
# contains (code, [addrRefToCode])
|
# contains (code, [addrRefToCode])
|
||||||
|
|
||||||
last_stmt = self.next_stmt[0]
|
last_stmt = self.next_stmt[0]
|
||||||
i = self.next_stmt[last_stmt]
|
i = self.next_stmt[last_stmt]
|
||||||
replace = {}
|
replace = {}
|
||||||
while i < n-1:
|
while i < codelen-1:
|
||||||
if self.lines[last_stmt].next > i:
|
if self.lines[last_stmt].next > i:
|
||||||
if self.code[last_stmt] == PRINT_ITEM:
|
if self.code[last_stmt] == PRINT_ITEM:
|
||||||
if self.code[i] == PRINT_ITEM:
|
if self.code[i] == PRINT_ITEM:
|
||||||
@@ -120,7 +94,7 @@ class Scanner25(scan.Scanner):
|
|||||||
last_stmt = i
|
last_stmt = i
|
||||||
i = self.next_stmt[i]
|
i = self.next_stmt[i]
|
||||||
|
|
||||||
imports = self.all_instr(0, n, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
|
imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
|
||||||
if len(imports) > 1:
|
if len(imports) > 1:
|
||||||
last_import = imports[0]
|
last_import = imports[0]
|
||||||
for i in imports[1:]:
|
for i in imports[1:]:
|
||||||
@@ -130,7 +104,7 @@ class Scanner25(scan.Scanner):
|
|||||||
last_import = i
|
last_import = i
|
||||||
|
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
for offset in self.op_range(0, n):
|
for offset in self.op_range(0, codelen):
|
||||||
op = self.code[offset]
|
op = self.code[offset]
|
||||||
op_name = opname[op]
|
op_name = opname[op]
|
||||||
oparg = None; pattr = None
|
oparg = None; pattr = None
|
||||||
@@ -141,7 +115,7 @@ class Scanner25(scan.Scanner):
|
|||||||
rv.append(Token('COME_FROM', None, repr(j),
|
rv.append(Token('COME_FROM', None, repr(j),
|
||||||
offset="%s_%d" % (offset, k) ))
|
offset="%s_%d" % (offset, k) ))
|
||||||
k += 1
|
k += 1
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
oparg = self.get_argument(offset) + extended_arg
|
oparg = self.get_argument(offset) + extended_arg
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
if op == EXTENDED_ARG:
|
if op == EXTENDED_ARG:
|
||||||
@@ -238,6 +212,10 @@ class Scanner25(scan.Scanner):
|
|||||||
'''
|
'''
|
||||||
opcode = self.code[i]
|
opcode = self.code[i]
|
||||||
opsize = self.op_size(opcode)
|
opsize = self.op_size(opcode)
|
||||||
|
|
||||||
|
if i+opsize >= len(self.code):
|
||||||
|
return None
|
||||||
|
|
||||||
if opcode == EXTENDED_ARG:
|
if opcode == EXTENDED_ARG:
|
||||||
raise 'TODO'
|
raise 'TODO'
|
||||||
# del POP_TOP
|
# del POP_TOP
|
||||||
@@ -288,7 +266,7 @@ class Scanner25(scan.Scanner):
|
|||||||
end += self.op_size(LOAD_FAST)
|
end += self.op_size(LOAD_FAST)
|
||||||
# log JA/POP_TOP to del and update PJIF
|
# log JA/POP_TOP to del and update PJIF
|
||||||
while start < end:
|
while start < end:
|
||||||
start = self.first_instr(start, len(self.code), (PJIF,PJIT))
|
start = self.first_instr(start, end, (PJIF,PJIT)) # end = len(self.code)
|
||||||
if start == None: break
|
if start == None: break
|
||||||
target = self.get_target(start)
|
target = self.get_target(start)
|
||||||
if self.code[target] == POP_TOP and self.code[target-3] == JA:
|
if self.code[target] == POP_TOP and self.code[target-3] == JA:
|
||||||
@@ -357,65 +335,144 @@ class Scanner25(scan.Scanner):
|
|||||||
return toDel
|
return toDel
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def restructRelativeJump(self):
|
def getOpcodeToExp(self):
|
||||||
'''
|
# we handle listExp, if opcode have to be resized
|
||||||
change relative JUMP_IF_FALSE/TRUE to absolut jump
|
listExp = []
|
||||||
and remap the target of PJIF/PJIT
|
i=0
|
||||||
'''
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[i]
|
||||||
for i in self.op_range(0, len(self.code)):
|
if op in self.opc.hasArgumentExtended:
|
||||||
if(self.code[i] in (PJIF,PJIT)):
|
listExp += [i]
|
||||||
target = self.get_argument(i)
|
elif self.op_hasArgument(op):
|
||||||
target += i + 3
|
i+=2
|
||||||
self.restructJump(i, target)
|
i+=1
|
||||||
|
return listExp
|
||||||
for i in self.op_range(0, len(self.code)):
|
|
||||||
if(self.code[i] in (PJIF,PJIT)):
|
|
||||||
target = self.get_target(i)
|
|
||||||
if self.code[target] == JA:
|
|
||||||
target = self.get_target(target)
|
|
||||||
self.restructJump(i, target)
|
|
||||||
|
|
||||||
def restructCode(self, listDel):
|
|
||||||
'''
|
|
||||||
restruct linestarts and jump destination after removing bad opcode
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
def restructCode(self, listDel, listExp):
|
||||||
|
'''
|
||||||
|
restruct linestarts and jump destination
|
||||||
|
'''
|
||||||
|
# restruct linestarts with deleted / modificated opcode
|
||||||
result = list()
|
result = list()
|
||||||
for block in self.linestarts:
|
for block in self.linestarts:
|
||||||
startBlock = 0
|
startBlock = 0
|
||||||
for toDel in listDel:
|
for toDel in listDel:
|
||||||
if toDel < block[0]:
|
if toDel < block[0]:
|
||||||
startBlock -= self.op_size(self.code[toDel])
|
startBlock -= self.op_size(self.code[toDel])
|
||||||
else:
|
for toExp in listExp:
|
||||||
break
|
if toExp < block[0]:
|
||||||
|
startBlock += 2
|
||||||
result.append((block[0]+startBlock, block[1]))
|
result.append((block[0]+startBlock, block[1]))
|
||||||
self.linestarts = result
|
self.linestarts = result
|
||||||
|
# handle opcodeToChange deplacement
|
||||||
for index in xrange(len(self.toChange)):
|
for index in xrange(len(self.toChange)):
|
||||||
change = self.toChange[index]
|
change = self.toChange[index]
|
||||||
delta = 0
|
delta = 0
|
||||||
for toDel in listDel:
|
for toDel in listDel:
|
||||||
if change > toDel:
|
if change > toDel:
|
||||||
delta += self.op_size(self.code[toDel])
|
delta -= self.op_size(self.code[toDel])
|
||||||
else:
|
for toExp in listExp:
|
||||||
break
|
if change > toExp:
|
||||||
self.toChange[index] -= delta
|
delta += 2
|
||||||
|
self.toChange[index] += delta
|
||||||
|
# restruct jmp opcode
|
||||||
|
if listDel:
|
||||||
|
for jmp in self.op_range(0, len(self.code)):
|
||||||
|
op = self.code[jmp]
|
||||||
|
if op in hasjrel+hasjabs:
|
||||||
|
offset = 0
|
||||||
|
jmpTarget = self.get_target(jmp)
|
||||||
|
for toDel in listDel:
|
||||||
|
if toDel < jmpTarget:
|
||||||
|
if op in hasjabs or jmp < toDel:
|
||||||
|
offset-=self.op_size(self.code[toDel])
|
||||||
|
self.restructJump(jmp, jmpTarget+offset)
|
||||||
|
if listExp:
|
||||||
|
jmp = 0
|
||||||
|
while jmp < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[jmp]
|
||||||
|
if op in hasjrel+hasjabs:
|
||||||
|
offset = 0
|
||||||
|
jmpTarget = self.get_target(jmp)
|
||||||
|
for toExp in listExp:
|
||||||
|
if toExp < jmpTarget:
|
||||||
|
if op in hasjabs or jmp < toExp:
|
||||||
|
offset+=2
|
||||||
|
self.restructJump(jmp, jmpTarget+offset)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
jmp += 3
|
||||||
|
else: jmp += 1
|
||||||
|
|
||||||
|
def restructBytecode(self):
|
||||||
|
'''
|
||||||
|
add/change/delete bytecode for suiting bytecode 2.7
|
||||||
|
'''
|
||||||
|
# we can't use op_range for the moment
|
||||||
|
# convert jump opcode to 2.7
|
||||||
|
self.restructRelativeJump()
|
||||||
|
|
||||||
for jmp in self.op_range(0, len(self.code)):
|
listExp = self.getOpcodeToExp()
|
||||||
op = self.code[jmp]
|
# change code structure
|
||||||
if op in hasjrel+hasjabs: # jmp
|
if listExp:
|
||||||
offset = 0
|
listExp = sorted(list(set(listExp)))
|
||||||
jmpTarget = self.get_target(jmp)
|
self.restructCode([], listExp)
|
||||||
for toDel in listDel:
|
# we add arg to expended opcode
|
||||||
if toDel < jmpTarget:
|
offset=0
|
||||||
if op in hasjabs:
|
for toExp in listExp:
|
||||||
offset-=self.op_size(self.code[toDel])
|
self.code.insert(toExp+offset+1, 0)
|
||||||
elif jmp < toDel:
|
self.code.insert(toExp+offset+1, 0)
|
||||||
offset-=self.op_size(self.code[toDel])
|
offset+=2
|
||||||
else:
|
# op_range is now ok :)
|
||||||
break
|
# add instruction to change in "toChange" list + MAJ toDel
|
||||||
self.restructJump(jmp, self.get_target(jmp)+offset)
|
listDel = []
|
||||||
|
for i in self.op_range(0, len(self.code)):
|
||||||
|
ret = self.getOpcodeToDel(i)
|
||||||
|
if ret != None:
|
||||||
|
listDel += ret
|
||||||
|
|
||||||
|
# change code structure after deleting byte
|
||||||
|
if listDel:
|
||||||
|
listDel = sorted(list(set(listDel)))
|
||||||
|
self.restructCode(listDel, [])
|
||||||
|
# finaly we delete useless opcode
|
||||||
|
delta = 0
|
||||||
|
for x in listDel:
|
||||||
|
if self.op_hasArgument(self.code[x-delta]):
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
delta += 3
|
||||||
|
else:
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
delta += 1
|
||||||
|
|
||||||
|
def restructRelativeJump(self):
|
||||||
|
'''
|
||||||
|
change relative JUMP_IF_FALSE/TRUE to absolut jump
|
||||||
|
and remap the target of PJIF/PJIT
|
||||||
|
'''
|
||||||
|
i=0
|
||||||
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[i]
|
||||||
|
if(op in (PJIF,PJIT)):
|
||||||
|
target = self.get_argument(i)
|
||||||
|
target += i + 3
|
||||||
|
self.restructJump(i, target)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
i += 3
|
||||||
|
else: i += 1
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[i]
|
||||||
|
if(op in (PJIF,PJIT)):
|
||||||
|
target = self.get_target(i)
|
||||||
|
if self.code[target] == JA:
|
||||||
|
target = self.get_target(target)
|
||||||
|
self.restructJump(i, target)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
i += 3
|
||||||
|
else: i += 1
|
||||||
|
|
||||||
def restructJump(self, pos, newTarget):
|
def restructJump(self, pos, newTarget):
|
||||||
if not (self.code[pos] in hasjabs+hasjrel):
|
if not (self.code[pos] in hasjabs+hasjrel):
|
||||||
@@ -428,7 +485,7 @@ class Scanner25(scan.Scanner):
|
|||||||
raise 'TODO'
|
raise 'TODO'
|
||||||
self.code[pos+2] = (target >> 8) & 0xFF
|
self.code[pos+2] = (target >> 8) & 0xFF
|
||||||
self.code[pos+1] = target & 0xFF
|
self.code[pos+1] = target & 0xFF
|
||||||
|
|
||||||
def build_stmt_indices(self):
|
def build_stmt_indices(self):
|
||||||
code = self.code
|
code = self.code
|
||||||
start = 0;
|
start = 0;
|
||||||
@@ -442,7 +499,7 @@ class Scanner25(scan.Scanner):
|
|||||||
STORE_ATTR, DELETE_ATTR, STORE_SUBSCR, DELETE_SUBSCR,
|
STORE_ATTR, DELETE_ATTR, STORE_SUBSCR, DELETE_SUBSCR,
|
||||||
RETURN_VALUE, RAISE_VARARGS, POP_TOP,
|
RETURN_VALUE, RAISE_VARARGS, POP_TOP,
|
||||||
PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO,
|
PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO,
|
||||||
JUMP_ABSOLUTE, EXEC_STMT,
|
JUMP_ABSOLUTE, EXEC_STMT
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)]
|
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)]
|
||||||
@@ -539,8 +596,6 @@ class Scanner25(scan.Scanner):
|
|||||||
in python2.3+
|
in python2.3+
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# TODO: check the struct boundaries more precisely -Dan
|
|
||||||
|
|
||||||
code = self.code
|
code = self.code
|
||||||
# Ev remove this test and make op a mandatory argument -Dan
|
# Ev remove this test and make op a mandatory argument -Dan
|
||||||
if op is None:
|
if op is None:
|
||||||
@@ -630,7 +685,6 @@ class Scanner25(scan.Scanner):
|
|||||||
end = self.restrict_to_parent(target, parent)
|
end = self.restrict_to_parent(target, parent)
|
||||||
if target != end:
|
if target != end:
|
||||||
self.fixed_jumps[pos] = end
|
self.fixed_jumps[pos] = end
|
||||||
#print target, end, parent
|
|
||||||
## Add the try block
|
## Add the try block
|
||||||
self.structs.append({'type': 'try',
|
self.structs.append({'type': 'try',
|
||||||
'start': start,
|
'start': start,
|
||||||
@@ -808,7 +862,7 @@ class Scanner25(scan.Scanner):
|
|||||||
## Determine structures and fix jumps for 2.3+
|
## Determine structures and fix jumps for 2.3+
|
||||||
self.detect_structure(i, op)
|
self.detect_structure(i, op)
|
||||||
|
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
label = self.fixed_jumps.get(i)
|
label = self.fixed_jumps.get(i)
|
||||||
oparg = self.get_argument(i)
|
oparg = self.get_argument(i)
|
||||||
if label is None:
|
if label is None:
|
||||||
|
@@ -32,12 +32,9 @@ class Scanner26(scan.Scanner):
|
|||||||
customize = {}
|
customize = {}
|
||||||
Token = self.Token # shortcut
|
Token = self.Token # shortcut
|
||||||
self.code = array('B', co.co_code)
|
self.code = array('B', co.co_code)
|
||||||
n = len(self.code)
|
|
||||||
# linestarts contains bloc code adresse (addr,block)
|
# linestarts contains bloc code adresse (addr,block)
|
||||||
self.linestarts = list(dis.findlinestarts(co))
|
self.linestarts = list(dis.findlinestarts(co))
|
||||||
self.prev = [0]
|
self.prev = [0]
|
||||||
# change jump struct
|
|
||||||
self.restructRelativeJump()
|
|
||||||
# class and names
|
# class and names
|
||||||
if classname:
|
if classname:
|
||||||
classname = '_' + classname.lstrip('_') + '__'
|
classname = '_' + classname.lstrip('_') + '__'
|
||||||
@@ -55,41 +52,19 @@ class Scanner26(scan.Scanner):
|
|||||||
varnames = co.co_varnames
|
varnames = co.co_varnames
|
||||||
self.names = names
|
self.names = names
|
||||||
|
|
||||||
# add instruction to remonde in "toDel" list
|
# list of instruction to remove/add or change to match with bytecode 2.7
|
||||||
toDel = []
|
|
||||||
# add instruction to change in "toChange" list
|
|
||||||
self.toChange = []
|
self.toChange = []
|
||||||
for i in self.op_range(0, n):
|
self.restructBytecode()
|
||||||
op = self.code[i]
|
codelen = len(self.code)
|
||||||
ret = self.getOpcodeToDel(i)
|
# mapping adresses of prev instru
|
||||||
if ret != None:
|
for i in self.op_range(0, codelen):
|
||||||
toDel += ret
|
|
||||||
if toDel:
|
|
||||||
toDel = sorted(list(set(toDel)))
|
|
||||||
delta = 0
|
|
||||||
self.restructCode(toDel)
|
|
||||||
for x in toDel:
|
|
||||||
if self.code[x-delta] >= HAVE_ARGUMENT:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 3
|
|
||||||
else:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 1
|
|
||||||
|
|
||||||
# mapping adresses of prev instru
|
|
||||||
n = len(self.code)
|
|
||||||
for i in self.op_range(0, n):
|
|
||||||
op = self.code[i]
|
op = self.code[i]
|
||||||
self.prev.append(i)
|
self.prev.append(i)
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
self.prev.append(i)
|
self.prev.append(i)
|
||||||
self.prev.append(i)
|
self.prev.append(i)
|
||||||
|
|
||||||
j = 0
|
j = 0
|
||||||
linestarts = self.linestarts
|
linestarts = self.linestarts
|
||||||
|
|
||||||
self.lines = []
|
self.lines = []
|
||||||
linetuple = namedtuple('linetuple', ['l_no', 'next'])
|
linetuple = namedtuple('linetuple', ['l_no', 'next'])
|
||||||
linestartoffsets = {a for (a, _) in linestarts}
|
linestartoffsets = {a for (a, _) in linestarts}
|
||||||
@@ -100,8 +75,8 @@ class Scanner26(scan.Scanner):
|
|||||||
j += 1
|
j += 1
|
||||||
last_op = self.code[self.prev[start_byte]]
|
last_op = self.code[self.prev[start_byte]]
|
||||||
(prev_start_byte, prev_line_no) = (start_byte, line_no)
|
(prev_start_byte, prev_line_no) = (start_byte, line_no)
|
||||||
while j < n:
|
while j < codelen:
|
||||||
self.lines.append(linetuple(prev_line_no, n))
|
self.lines.append(linetuple(prev_line_no, codelen))
|
||||||
j+=1
|
j+=1
|
||||||
# self.lines contains (block,addrLastInstr)
|
# self.lines contains (block,addrLastInstr)
|
||||||
cf = self.find_jump_targets(self.code)
|
cf = self.find_jump_targets(self.code)
|
||||||
@@ -110,7 +85,7 @@ class Scanner26(scan.Scanner):
|
|||||||
last_stmt = self.next_stmt[0]
|
last_stmt = self.next_stmt[0]
|
||||||
i = self.next_stmt[last_stmt]
|
i = self.next_stmt[last_stmt]
|
||||||
replace = {}
|
replace = {}
|
||||||
while i < n-1:
|
while i < codelen-1:
|
||||||
if self.lines[last_stmt].next > i:
|
if self.lines[last_stmt].next > i:
|
||||||
if self.code[last_stmt] == PRINT_ITEM:
|
if self.code[last_stmt] == PRINT_ITEM:
|
||||||
if self.code[i] == PRINT_ITEM:
|
if self.code[i] == PRINT_ITEM:
|
||||||
@@ -120,7 +95,7 @@ class Scanner26(scan.Scanner):
|
|||||||
last_stmt = i
|
last_stmt = i
|
||||||
i = self.next_stmt[i]
|
i = self.next_stmt[i]
|
||||||
|
|
||||||
imports = self.all_instr(0, n, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
|
imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
|
||||||
if len(imports) > 1:
|
if len(imports) > 1:
|
||||||
last_import = imports[0]
|
last_import = imports[0]
|
||||||
for i in imports[1:]:
|
for i in imports[1:]:
|
||||||
@@ -130,7 +105,7 @@ class Scanner26(scan.Scanner):
|
|||||||
last_import = i
|
last_import = i
|
||||||
|
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
for offset in self.op_range(0, n):
|
for offset in self.op_range(0, codelen):
|
||||||
op = self.code[offset]
|
op = self.code[offset]
|
||||||
op_name = opname[op]
|
op_name = opname[op]
|
||||||
oparg = None; pattr = None
|
oparg = None; pattr = None
|
||||||
@@ -141,7 +116,7 @@ class Scanner26(scan.Scanner):
|
|||||||
rv.append(Token('COME_FROM', None, repr(j),
|
rv.append(Token('COME_FROM', None, repr(j),
|
||||||
offset="%s_%d" % (offset, k) ))
|
offset="%s_%d" % (offset, k) ))
|
||||||
k += 1
|
k += 1
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
oparg = self.get_argument(offset) + extended_arg
|
oparg = self.get_argument(offset) + extended_arg
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
if op == EXTENDED_ARG:
|
if op == EXTENDED_ARG:
|
||||||
@@ -296,7 +271,7 @@ class Scanner26(scan.Scanner):
|
|||||||
end += self.op_size(LOAD_FAST)
|
end += self.op_size(LOAD_FAST)
|
||||||
# log JA/POP_TOP to del and update PJIF
|
# log JA/POP_TOP to del and update PJIF
|
||||||
while start < end:
|
while start < end:
|
||||||
start = self.first_instr(start, len(self.code), (PJIF,PJIT))
|
start = self.first_instr(start, end, (PJIF,PJIT))
|
||||||
if start == None: break
|
if start == None: break
|
||||||
target = self.get_target(start)
|
target = self.get_target(start)
|
||||||
if self.code[target] == POP_TOP and self.code[target-3] == JA:
|
if self.code[target] == POP_TOP and self.code[target-3] == JA:
|
||||||
@@ -356,64 +331,145 @@ class Scanner26(scan.Scanner):
|
|||||||
return toDel
|
return toDel
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def restructRelativeJump(self):
|
def getOpcodeToExp(self):
|
||||||
'''
|
# we handle listExp, if opcode have to be resized
|
||||||
change relative JUMP_IF_FALSE/TRUE to absolut jump
|
listExp = []
|
||||||
and remap the target of PJIF/PJIT
|
i=0
|
||||||
'''
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
for i in self.op_range(0, len(self.code)):
|
op = self.code[i]
|
||||||
if(self.code[i] in (PJIF,PJIT)):
|
if op in self.opc.hasArgumentExtended:
|
||||||
target = self.get_argument(i)
|
listExp += [i]
|
||||||
target += i + 3
|
elif self.op_hasArgument(op):
|
||||||
self.restructJump(i, target)
|
i+=2
|
||||||
|
i+=1
|
||||||
|
return listExp
|
||||||
|
|
||||||
for i in self.op_range(0, len(self.code)):
|
def restructCode(self, listDel, listExp):
|
||||||
if(self.code[i] in (PJIF,PJIT)):
|
|
||||||
target = self.get_target(i)
|
|
||||||
if self.code[target] == JA:
|
|
||||||
target = self.get_target(target)
|
|
||||||
self.restructJump(i, target)
|
|
||||||
|
|
||||||
def restructCode(self, listDel):
|
|
||||||
'''
|
'''
|
||||||
restruct linestarts and jump destination after removing a POP_TOP
|
restruct linestarts and jump destination after converting bytecode
|
||||||
'''
|
'''
|
||||||
|
# restruct linestarts with deleted / modificated opcode
|
||||||
result = list()
|
result = list()
|
||||||
for block in self.linestarts:
|
for block in self.linestarts:
|
||||||
startBlock = 0
|
startBlock = 0
|
||||||
for toDel in listDel:
|
for toDel in listDel:
|
||||||
if toDel < block[0]:
|
if toDel < block[0]:
|
||||||
startBlock -= self.op_size(self.code[toDel])
|
startBlock -= self.op_size(self.code[toDel])
|
||||||
else:
|
for toExp in listExp:
|
||||||
break
|
if toExp < block[0]:
|
||||||
|
startBlock += 2
|
||||||
result.append((block[0]+startBlock, block[1]))
|
result.append((block[0]+startBlock, block[1]))
|
||||||
self.linestarts = result
|
self.linestarts = result
|
||||||
|
# handle opcodeToChange deplacement
|
||||||
for index in xrange(len(self.toChange)):
|
for index in xrange(len(self.toChange)):
|
||||||
change = self.toChange[index]
|
change = self.toChange[index]
|
||||||
delta = 0
|
delta = 0
|
||||||
for toDel in listDel:
|
for toDel in listDel:
|
||||||
if change > toDel:
|
if change > toDel:
|
||||||
delta += self.op_size(self.code[toDel])
|
delta -= self.op_size(self.code[toDel])
|
||||||
else:
|
for toExp in listExp:
|
||||||
break
|
if change > toExp:
|
||||||
self.toChange[index] -= delta
|
delta += 2
|
||||||
|
self.toChange[index] += delta
|
||||||
|
# restruct jmp opcode
|
||||||
|
if listDel:
|
||||||
|
for jmp in self.op_range(0, len(self.code)):
|
||||||
|
op = self.code[jmp]
|
||||||
|
if op in hasjrel+hasjabs:
|
||||||
|
offset = 0
|
||||||
|
jmpTarget = self.get_target(jmp)
|
||||||
|
for toDel in listDel:
|
||||||
|
if toDel < jmpTarget:
|
||||||
|
if op in hasjabs or jmp < toDel:
|
||||||
|
offset-=self.op_size(self.code[toDel])
|
||||||
|
self.restructJump(jmp, jmpTarget+offset)
|
||||||
|
if listExp:
|
||||||
|
jmp = 0
|
||||||
|
while jmp < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[jmp]
|
||||||
|
if op in hasjrel+hasjabs:
|
||||||
|
offset = 0
|
||||||
|
jmpTarget = self.get_target(jmp)
|
||||||
|
for toExp in listExp:
|
||||||
|
if toExp < jmpTarget:
|
||||||
|
if op in hasjabs or jmp < toExp:
|
||||||
|
offset+=2
|
||||||
|
self.restructJump(jmp, jmpTarget+offset)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
jmp += 3
|
||||||
|
else: jmp += 1
|
||||||
|
|
||||||
|
def restructBytecode(self):
|
||||||
|
'''
|
||||||
|
add/change/delete bytecode for suiting bytecode 2.7
|
||||||
|
'''
|
||||||
|
# we can't use op_range for the moment
|
||||||
|
# convert jump opcode to 2.7
|
||||||
|
self.restructRelativeJump()
|
||||||
|
|
||||||
for jmp in self.op_range(0, len(self.code)):
|
listExp = self.getOpcodeToExp()
|
||||||
op = self.code[jmp]
|
# change code structure
|
||||||
if op in hasjrel+hasjabs: # jmp
|
if listExp:
|
||||||
offset = 0
|
listExp = sorted(list(set(listExp)))
|
||||||
jmpTarget = self.get_target(jmp)
|
self.restructCode([], listExp)
|
||||||
for toDel in listDel:
|
# we add arg to expended opcode
|
||||||
if toDel < jmpTarget:
|
offset=0
|
||||||
if op in hasjabs:
|
for toExp in listExp:
|
||||||
offset-=self.op_size(self.code[toDel])
|
self.code.insert(toExp+offset+1, 0)
|
||||||
elif jmp < toDel:
|
self.code.insert(toExp+offset+1, 0)
|
||||||
offset-=self.op_size(self.code[toDel])
|
offset+=2
|
||||||
else:
|
# op_range is now ok :)
|
||||||
break
|
# add instruction to change in "toChange" list + MAJ toDel
|
||||||
self.restructJump(jmp, self.get_target(jmp)+offset)
|
listDel = []
|
||||||
|
for i in self.op_range(0, len(self.code)):
|
||||||
|
ret = self.getOpcodeToDel(i)
|
||||||
|
if ret != None:
|
||||||
|
listDel += ret
|
||||||
|
|
||||||
|
# change code structure after deleting byte
|
||||||
|
if listDel:
|
||||||
|
listDel = sorted(list(set(listDel)))
|
||||||
|
self.restructCode(listDel, [])
|
||||||
|
# finaly we delete useless opcode
|
||||||
|
delta = 0
|
||||||
|
for x in listDel:
|
||||||
|
if self.op_hasArgument(self.code[x-delta]):
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
delta += 3
|
||||||
|
else:
|
||||||
|
self.code.pop(x-delta)
|
||||||
|
delta += 1
|
||||||
|
|
||||||
|
def restructRelativeJump(self):
|
||||||
|
'''
|
||||||
|
change relative JUMP_IF_FALSE/TRUE to absolut jump
|
||||||
|
and remap the target of PJIF/PJIT
|
||||||
|
'''
|
||||||
|
i=0
|
||||||
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[i]
|
||||||
|
if(op in (PJIF,PJIT)):
|
||||||
|
target = self.get_argument(i)
|
||||||
|
target += i + 3
|
||||||
|
self.restructJump(i, target)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
i += 3
|
||||||
|
else: i += 1
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i < len(self.code): # we can't use op_range for the moment
|
||||||
|
op = self.code[i]
|
||||||
|
if(op in (PJIF,PJIT)):
|
||||||
|
target = self.get_target(i)
|
||||||
|
if self.code[target] == JA:
|
||||||
|
target = self.get_target(target)
|
||||||
|
self.restructJump(i, target)
|
||||||
|
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
||||||
|
i += 3
|
||||||
|
else: i += 1
|
||||||
|
|
||||||
def restructJump(self, pos, newTarget):
|
def restructJump(self, pos, newTarget):
|
||||||
if not (self.code[pos] in hasjabs+hasjrel):
|
if not (self.code[pos] in hasjabs+hasjrel):
|
||||||
raise 'Can t change this argument. Opcode is not a jump'
|
raise 'Can t change this argument. Opcode is not a jump'
|
||||||
@@ -425,7 +481,7 @@ class Scanner26(scan.Scanner):
|
|||||||
raise 'TODO'
|
raise 'TODO'
|
||||||
self.code[pos+2] = (target >> 8) & 0xFF
|
self.code[pos+2] = (target >> 8) & 0xFF
|
||||||
self.code[pos+1] = target & 0xFF
|
self.code[pos+1] = target & 0xFF
|
||||||
|
|
||||||
def build_stmt_indices(self):
|
def build_stmt_indices(self):
|
||||||
code = self.code
|
code = self.code
|
||||||
start = 0;
|
start = 0;
|
||||||
@@ -805,7 +861,7 @@ class Scanner26(scan.Scanner):
|
|||||||
## Determine structures and fix jumps for 2.3+
|
## Determine structures and fix jumps for 2.3+
|
||||||
self.detect_structure(i, op)
|
self.detect_structure(i, op)
|
||||||
|
|
||||||
if op >= HAVE_ARGUMENT:
|
if self.op_hasArgument(op):
|
||||||
label = self.fixed_jumps.get(i)
|
label = self.fixed_jumps.get(i)
|
||||||
oparg = self.get_argument(i)
|
oparg = self.get_argument(i)
|
||||||
if label is None:
|
if label is None:
|
||||||
|
@@ -194,6 +194,12 @@ class Scanner27(scan.Scanner):
|
|||||||
print >>out
|
print >>out
|
||||||
return rv, customize
|
return rv, customize
|
||||||
|
|
||||||
|
def op_size(self, op):
|
||||||
|
if op < self.opc.HAVE_ARGUMENT:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 3
|
||||||
|
|
||||||
def build_stmt_indices(self):
|
def build_stmt_indices(self):
|
||||||
code = self.code
|
code = self.code
|
||||||
start = 0;
|
start = 0;
|
||||||
|
Reference in New Issue
Block a user