mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	bpo-45152: refactor the dis module to make handling of hasconst opcodes more generic (GH-28258)
This commit is contained in:
		
							parent
							
								
									1afc7b3219
								
							
						
					
					
						commit
						40d2ac92f9
					
				
					 1 changed files with 35 additions and 19 deletions
				
			
		
							
								
								
									
										54
									
								
								Lib/dis.py
									
										
									
									
									
								
							
							
						
						
									
										54
									
								
								Lib/dis.py
									
										
									
									
									
								
							|  | @ -26,6 +26,7 @@ | ||||||
| MAKE_FUNCTION = opmap['MAKE_FUNCTION'] | MAKE_FUNCTION = opmap['MAKE_FUNCTION'] | ||||||
| MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') | MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') | ||||||
| 
 | 
 | ||||||
|  | LOAD_CONST = opmap['LOAD_CONST'] | ||||||
| 
 | 
 | ||||||
| def _try_compile(source, name): | def _try_compile(source, name): | ||||||
|     """Attempts to compile the given source, first as an expression and |     """Attempts to compile the given source, first as an expression and | ||||||
|  | @ -317,19 +318,32 @@ def get_instructions(x, *, first_line=None): | ||||||
|                                    co.co_names, co.co_consts, |                                    co.co_names, co.co_consts, | ||||||
|                                    linestarts, line_offset, co_positions=co.co_positions()) |                                    linestarts, line_offset, co_positions=co.co_positions()) | ||||||
| 
 | 
 | ||||||
| def _get_const_info(const_index, const_list): | def _get_const_value(op, arg, co_consts): | ||||||
|  |     """Helper to get the value of the const in a hasconst op. | ||||||
|  | 
 | ||||||
|  |        Returns the dereferenced constant if this is possible. | ||||||
|  |        Otherwise (if it is a LOAD_CONST and co_consts is not | ||||||
|  |        provided) returns the dis.UNKNOWN sentinel. | ||||||
|  |     """ | ||||||
|  |     assert op in hasconst | ||||||
|  | 
 | ||||||
|  |     argval = UNKNOWN | ||||||
|  |     if op == LOAD_CONST: | ||||||
|  |         if co_consts is not None: | ||||||
|  |             argval = co_consts[arg] | ||||||
|  |     return argval | ||||||
|  | 
 | ||||||
|  | def _get_const_info(op, arg, co_consts): | ||||||
|     """Helper to get optional details about const references |     """Helper to get optional details about const references | ||||||
| 
 | 
 | ||||||
|        Returns the dereferenced constant and its repr if the constant |        Returns the dereferenced constant and its repr if the value | ||||||
|        list is defined. |        can be calculated. | ||||||
|        Otherwise returns the sentinel value dis.UNKNOWN for the value |        Otherwise returns the sentinel value dis.UNKNOWN for the value | ||||||
|        and an empty string for its repr. |        and an empty string for its repr. | ||||||
|     """ |     """ | ||||||
|     if const_list is not None: |     argval = _get_const_value(op, arg, co_consts) | ||||||
|         argval = const_list[const_index] |     argrepr = repr(argval) if argval is not UNKNOWN else '' | ||||||
|         return argval, repr(argval) |     return argval, argrepr | ||||||
|     else: |  | ||||||
|         return UNKNOWN, '' |  | ||||||
| 
 | 
 | ||||||
| def _get_name_info(name_index, get_name, **extrainfo): | def _get_name_info(name_index, get_name, **extrainfo): | ||||||
|     """Helper to get optional details about named references |     """Helper to get optional details about named references | ||||||
|  | @ -371,14 +385,14 @@ def parse_exception_table(code): | ||||||
|         return entries |         return entries | ||||||
| 
 | 
 | ||||||
| def _get_instructions_bytes(code, varname_from_oparg=None, | def _get_instructions_bytes(code, varname_from_oparg=None, | ||||||
|                             names=None, constants=None, |                             names=None, co_consts=None, | ||||||
|                             linestarts=None, line_offset=0, |                             linestarts=None, line_offset=0, | ||||||
|                             exception_entries=(), co_positions=None): |                             exception_entries=(), co_positions=None): | ||||||
|     """Iterate over the instructions in a bytecode string. |     """Iterate over the instructions in a bytecode string. | ||||||
| 
 | 
 | ||||||
|     Generates a sequence of Instruction namedtuples giving the details of each |     Generates a sequence of Instruction namedtuples giving the details of each | ||||||
|     opcode.  Additional information about the code's runtime environment |     opcode.  Additional information about the code's runtime environment | ||||||
|     (e.g. variable names, constants) can be specified using optional |     (e.g. variable names, co_consts) can be specified using optional | ||||||
|     arguments. |     arguments. | ||||||
| 
 | 
 | ||||||
|     """ |     """ | ||||||
|  | @ -408,7 +422,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, | ||||||
|             #    raw name index for LOAD_GLOBAL, LOAD_CONST, etc. |             #    raw name index for LOAD_GLOBAL, LOAD_CONST, etc. | ||||||
|             argval = arg |             argval = arg | ||||||
|             if op in hasconst: |             if op in hasconst: | ||||||
|                 argval, argrepr = _get_const_info(arg, constants) |                 argval, argrepr = _get_const_info(op, arg, co_consts) | ||||||
|             elif op in hasname: |             elif op in hasname: | ||||||
|                 argval, argrepr = _get_name_info(arg, get_name) |                 argval, argrepr = _get_name_info(arg, get_name) | ||||||
|             elif op in hasjabs: |             elif op in hasjabs: | ||||||
|  | @ -457,7 +471,7 @@ def _disassemble_recursive(co, *, file=None, depth=None): | ||||||
|                 _disassemble_recursive(x, file=file, depth=depth) |                 _disassemble_recursive(x, file=file, depth=depth) | ||||||
| 
 | 
 | ||||||
| def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, | def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, | ||||||
|                        names=None, constants=None, linestarts=None, |                        names=None, co_consts=None, linestarts=None, | ||||||
|                        *, file=None, line_offset=0, exception_entries=(), |                        *, file=None, line_offset=0, exception_entries=(), | ||||||
|                        co_positions=None): |                        co_positions=None): | ||||||
|     # Omit the line number column entirely if we have no line number info |     # Omit the line number column entirely if we have no line number info | ||||||
|  | @ -476,7 +490,7 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, | ||||||
|     else: |     else: | ||||||
|         offset_width = 4 |         offset_width = 4 | ||||||
|     for instr in _get_instructions_bytes(code, varname_from_oparg, names, |     for instr in _get_instructions_bytes(code, varname_from_oparg, names, | ||||||
|                                          constants, linestarts, |                                          co_consts, linestarts, | ||||||
|                                          line_offset=line_offset, exception_entries=exception_entries, |                                          line_offset=line_offset, exception_entries=exception_entries, | ||||||
|                                          co_positions=co_positions): |                                          co_positions=co_positions): | ||||||
|         new_source_line = (show_lineno and |         new_source_line = (show_lineno and | ||||||
|  | @ -557,11 +571,13 @@ def _find_imports(co): | ||||||
|     opargs = [(op, arg) for _, op, arg in _unpack_opargs(co.co_code) |     opargs = [(op, arg) for _, op, arg in _unpack_opargs(co.co_code) | ||||||
|                   if op != EXTENDED_ARG] |                   if op != EXTENDED_ARG] | ||||||
|     for i, (op, oparg) in enumerate(opargs): |     for i, (op, oparg) in enumerate(opargs): | ||||||
|         if (op == IMPORT_NAME and i >= 2 |         if op == IMPORT_NAME and i >= 2: | ||||||
|                 and opargs[i-1][0] == opargs[i-2][0] == LOAD_CONST): |             from_op = opargs[i-1] | ||||||
|             level = consts[opargs[i-2][1]] |             level_op = opargs[i-2] | ||||||
|             fromlist = consts[opargs[i-1][1]] |             if (from_op[0] in hasconst and level_op[0] in hasconst): | ||||||
|             yield (names[oparg], level, fromlist) |                 level = _get_const_value(level_op[0], level_op[1], consts) | ||||||
|  |                 fromlist = _get_const_value(from_op[0], from_op[1], consts) | ||||||
|  |                 yield (names[oparg], level, fromlist) | ||||||
| 
 | 
 | ||||||
| def _find_store_names(co): | def _find_store_names(co): | ||||||
|     """Find names of variables which are written in the code |     """Find names of variables which are written in the code | ||||||
|  | @ -635,7 +651,7 @@ def dis(self): | ||||||
|         with io.StringIO() as output: |         with io.StringIO() as output: | ||||||
|             _disassemble_bytes(co.co_code, |             _disassemble_bytes(co.co_code, | ||||||
|                                varname_from_oparg=co._varname_from_oparg, |                                varname_from_oparg=co._varname_from_oparg, | ||||||
|                                names=co.co_names, constants=co.co_consts, |                                names=co.co_names, co_consts=co.co_consts, | ||||||
|                                linestarts=self._linestarts, |                                linestarts=self._linestarts, | ||||||
|                                line_offset=self._line_offset, |                                line_offset=self._line_offset, | ||||||
|                                file=output, |                                file=output, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Irit Katriel
						Irit Katriel