1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import sys, re, os 18from io import StringIO 19 20SCRIPT_DIR = os.path.dirname(sys.argv[0]) 21# This file is included verbatim at the start of the in-memory python script. 22SCRIPT_SETUP_CODE = SCRIPT_DIR + "/common/gen_setup.py" 23INTERP_DEFS_FILE = SCRIPT_DIR + "/../../../libdexfile/dex/dex_instruction_list.h" 24NUM_PACKED_OPCODES = 256 25 26# Extract an ordered list of instructions from the VM sources. We use the 27# "goto table" definition macro, which has exactly NUM_PACKED_OPCODES entries. 28def getOpcodeList(): 29 opcodes = [] 30 opcode_fp = open(INTERP_DEFS_FILE) 31 opcode_re = re.compile(r"^\s*V\((....), (\w+),.*", re.DOTALL) 32 for line in opcode_fp: 33 match = opcode_re.match(line) 34 if not match: 35 continue 36 opcodes.append("op_" + match.group(2).lower()) 37 opcode_fp.close() 38 39 if len(opcodes) != NUM_PACKED_OPCODES: 40 print("ERROR: found ", len(opcodes), " opcodes in Interp.h (expected ", NUM_PACKED_OPCODES, ")") 41 raise SyntaxError("bad opcode count") 42 return opcodes 43 44indent_re = re.compile(r"^%( *)") 45 46# Finds variable references in text: $foo or ${foo} 47escape_re = re.compile(r''' 48 (?<!\$) # Look-back: must not be preceded by another $. 49 \$ 50 (\{)? # May be enclosed by { } pair. 51 (?P<name>\w+) # Save the symbol in named group. 52 (?(1)\}) # Expect } if and only if { was present. 53''', re.VERBOSE) 54 55def generate_script(output_filename, input_filenames): 56 # Create new python script and write the initial setup code. 57 script = StringIO() # File-like in-memory buffer. 58 script.write("# DO NOT EDIT: This file was generated by gen-mterp.py.\n") 59 script.write(open(SCRIPT_SETUP_CODE, "r").read()) 60 script.write("def opcodes():\n") 61 for i, opcode in enumerate(getOpcodeList()): 62 script.write(' write_opcode({0}, "{1}", {1})\n'.format(i, opcode)) 63 64 # Read all template files and translate them into python code. 65 for input_filename in sorted(input_filenames): 66 lines = open(input_filename, "r").readlines() 67 indent = "" 68 for line in lines: 69 line = line.rstrip() 70 if line.startswith("%"): 71 script.write(line.lstrip("%") + "\n") 72 indent = indent_re.match(line).group(1) 73 if line.endswith(":"): 74 indent += " " 75 else: 76 line = escape_re.sub(r"''' + \g<name> + '''", line) 77 line = line.replace("\\", "\\\\") 78 line = line.replace("$$", "$") 79 script.write(indent + "write_line('''" + line + "''')\n") 80 script.write("\n") 81 82 script.write("generate('''" + output_filename + "''')\n") 83 script.seek(0) 84 return script.read() 85 86if len(sys.argv) <= 3: 87 print("Usage: output_file input_file(s)") 88 sys.exit(1) 89 90# Generate the script and execute it. 91output_filename = sys.argv[1] 92input_filenames = sys.argv[2:] 93script_filename = output_filename + ".py" 94script = generate_script(output_filename, input_filenames) 95with open(script_filename, "w") as script_file: 96 script_file.write(script) # Write to disk for debugging. 97exec(compile(script, script_filename, mode='exec')) 98