modification of LIST_APPEND opcode handling

This commit is contained in:
Mysterie
2012-12-14 17:22:59 +01:00
parent 60869b0399
commit 3956a5a709
7 changed files with 308 additions and 177 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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) # ""

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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;