1#!/usr/bin/env python 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 cStringIO 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 %d opcodes in Interp.h (expected %d)" \ 41 % (len(opcodes), NUM_PACKED_OPCODES) 42 raise SyntaxError, "bad opcode count" 43 return opcodes 44 45indent_re = re.compile(r"^%( *)") 46 47# Finds variable references in text: $foo or ${foo} 48escape_re = re.compile(r''' 49 (?<!\$) # Look-back: must not be preceded by another $. 50 \$ 51 (\{)? # May be enclosed by { } pair. 52 (?P<name>\w+) # Save the symbol in named group. 53 (?(1)\}) # Expect } if and only if { was present. 54''', re.VERBOSE) 55 56def generate_script(output_filename, input_filenames): 57 # Create new python script and write the initial setup code. 58 script = StringIO() # File-like in-memory buffer. 59 script.write("# DO NOT EDIT: This file was generated by gen-mterp.py.\n") 60 script.write(open(SCRIPT_SETUP_CODE, "r").read()) 61 script.write("def opcodes():\n") 62 for i, opcode in enumerate(getOpcodeList()): 63 script.write(' write_opcode({0}, "{1}", {1})\n'.format(i, opcode)) 64 65 # Read all template files and translate them into python code. 66 for input_filename in sorted(input_filenames): 67 lines = open(input_filename, "r").readlines() 68 indent = "" 69 for line in lines: 70 line = line.rstrip() 71 if line.startswith("%"): 72 script.write(line.lstrip("%") + "\n") 73 indent = indent_re.match(line).group(1) 74 if line.endswith(":"): 75 indent += " " 76 else: 77 line = escape_re.sub(r"''' + \g<name> + '''", line) 78 line = line.replace("\\", "\\\\") 79 line = line.replace("$$", "$") 80 script.write(indent + "write_line('''" + line + "''')\n") 81 script.write("\n") 82 83 script.write("generate('''" + output_filename + "''')\n") 84 script.seek(0) 85 return script.read() 86 87if len(sys.argv) <= 3: 88 print("Usage: output_file input_file(s)") 89 sys.exit(1) 90 91# Generate the script and execute it. 92output_filename = sys.argv[1] 93input_filenames = sys.argv[2:] 94script_filename = output_filename + ".py" 95script = generate_script(output_filename, input_filenames) 96with open(script_filename, "w") as script_file: 97 script_file.write(script) # Write to disk for debugging. 98exec(compile(script, script_filename, mode='exec')) 99