def analyze_loop(settings, code, index): instr = code[index] if not (instr[0] == byteplay.FOR_ITER and (index >= 2 and code[index - 2][0] == byteplay.GET_ITER)): return 0 # Now we found GET_ITER and FOR_ITER instructions # Try to find SETUP_LOOP for rel_index in orig_xrange(index - 3, -1, -1): if code[rel_index][0] == byteplay.SETUP_LOOP: setup_index = rel_index break else: return 0 # Try to find JUMP_ABSOLUTE and POP_BLOCK by label from FOR_ITER pop_block_label = instr[1] for rel_index in orig_xrange(index + 1, len(code) - 1): if code[rel_index][0] is pop_block_label: pop_block_index = rel_index + 1 break else: return 0 if not (code[pop_block_index - 2][0] == byteplay.JUMP_ABSOLUTE and code[pop_block_index - 2][1] is code[index - 1][0] and code[pop_block_index][0] == byteplay.POP_BLOCK): return 0 # It's busy to check POP_BLOCK instruction existence to # distinguish real for-loops from a list comprehensions # Try to find marker of current line's number for rel_index in orig_xrange(setup_index - 1, -1, -1): if code[rel_index][0] == byteplay.SetLineno: head_lineno = code[rel_index][1] break else: head_lineno = None head = code[setup_index + 1:index - 2] body = code[index + 1:pop_block_index - 2] # Don't forget that "else_body" loop part is also exists settings['head_lineno'] = head_lineno try: state = recompiler.recompile_body(settings, body) except recompiler.RecompileError as err: if settings['profile']: profiler.exc(settings, 'Recompilation failed', err) return 0 # Insert head_handler right before GET_ITER instruction head_hook = hook.create_head_hook(state, pop_block_label) code[index - 2:index - 2] = head_hook if settings['profile']: profiler.note(settings, 'Recompilation succeeded') # Return length of analyzed code return len(head_hook)
def exec_loop( iterable, settings, matcode, used_vars, real_vars_indexes, need_store_counter, globals_dict, locals_dict, folded, ): try: # Check whether iterable for-loop argument has type "xrange" range_desc = check_iterable(settings, iterable) try: # If so, retreive it's parameters start, step, iters_count, last = range_desc except TypeError: return None # Load necessary variables, check it's types and make vector # for further operations with matrixes appending unit row vector = load_vars( settings, used_vars, globals_dict, locals_dict, ) + [1] except TypeError as err: err.message = "Can't run optimized loop: " + err.message if settings['profile']: profiler.exc(settings, "Hook didn't allow optimization", err) return None # Define constant values in matrix code matcode = define_values(matcode, folded, { 'start': start, 'step': step, 'iters_count': iters_count, }) # Add last detail to matrix code before it's execution matcode.append([END]) # Run matrix code vector = run.run_matcode(settings, matcode, vector) if settings['profile']: profiler.success(settings, 'Optimized execution of %s iterations' % iters_count) # Pack real variables' values to a list that will be unpacked in # the main function to the values that would be assigned to the # globals and the locals. We can't implement storing variables like # its' loading because locals() dictionary is read-only. packed = [vector[index] for index in real_vars_indexes] if need_store_counter: packed.append(last) return packed
def analyze_loop(settings, code, index): instr = code[index] if not ( instr[0] == byteplay.FOR_ITER and (index >= 2 and code[index - 2][0] == byteplay.GET_ITER) ): return 0 # Now we found GET_ITER and FOR_ITER instructions # Try to find SETUP_LOOP for rel_index in orig_xrange(index - 3, -1, -1): if code[rel_index][0] == byteplay.SETUP_LOOP: setup_index = rel_index break else: return 0 # Try to find JUMP_ABSOLUTE and POP_BLOCK by label from FOR_ITER pop_block_label = instr[1] for rel_index in orig_xrange(index + 1, len(code) - 1): if code[rel_index][0] is pop_block_label: pop_block_index = rel_index + 1 break else: return 0 if not ( code[pop_block_index - 2][0] == byteplay.JUMP_ABSOLUTE and code[pop_block_index - 2][1] is code[index - 1][0] and code[pop_block_index][0] == byteplay.POP_BLOCK ): return 0 # It's busy to check POP_BLOCK instruction existence to # distinguish real for-loops from a list comprehensions # Try to find marker of current line's number for rel_index in orig_xrange(setup_index - 1, -1, -1): if code[rel_index][0] == byteplay.SetLineno: head_lineno = code[rel_index][1] break else: head_lineno = None head = code[setup_index + 1:index - 2] body = code[index + 1:pop_block_index - 2] # Don't forget that "else_body" loop part is also exists settings['head_lineno'] = head_lineno try: state = recompiler.recompile_body(settings, body) except recompiler.RecompileError as err: if settings['profile']: profiler.exc(settings, 'Recompilation failed', err) return 0 # Insert head_handler right before GET_ITER instruction head_hook = hook.create_head_hook(state, pop_block_label) code[index - 2:index - 2] = head_hook if settings['profile']: profiler.note(settings, 'Recompilation succeeded') # Return length of analyzed code return len(head_hook)