11452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#!/usr/bin/env python
21452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
31452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Copyright (C) 2016 The Android Open Source Project
41452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
51452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Licensed under the Apache License, Version 2.0 (the "License");
61452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# you may not use this file except in compliance with the License.
71452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# You may obtain a copy of the License at
81452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
91452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#      http://www.apache.org/licenses/LICENSE-2.0
101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Unless required by applicable law or agreed to in writing, software
121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# distributed under the License is distributed on an "AS IS" BASIS,
131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# See the License for the specific language governing permissions and
151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# limitations under the License.
161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Using instructions from an architecture-specific config file, generate C
191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# and assembly source files for the Dalvik interpreter.
201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeimport sys, string, re, time
231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeefrom string import Template
241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeinterp_defs_file = "../../dex_instruction_list.h" # need opcode list
261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeekNumPackedOpcodes = 256
271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeesplitops = False
291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeverbose = False
301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeehandler_size_bits = -1000
311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeehandler_size_bytes = -1000
321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeein_op_start = 0             # 0=not started, 1=started, 2=ended
331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeein_alt_op_start = 0         # 0=not started, 1=started, 2=ended
341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedefault_op_dir = None
351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedefault_alt_stub = None
361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeopcode_locations = {}
371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeealt_opcode_locations = {}
381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeasm_stub_text = []
391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeefallback_stub_text = []
401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeelabel_prefix = ".L"         # use ".L" to hide labels from gdb
411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeealt_label_prefix = ".L_ALT" # use ".L" to hide labels from gdb
421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeestyle = None                # interpreter style
431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeegenerate_alt_table = False
4405dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovfunction_type_format = ".type   %s, %%function"
4505dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovfunction_size_format = ".size   %s, .-%s"
4605dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovglobal_name_format = "%s"
471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Exception class.
491452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeclass DataParseError(SyntaxError):
501452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    "Failure when parsing data file"
511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
531452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Set any omnipresent substitution values.
541452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
551452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef getGlobalSubDict():
561452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    return { "handler_size_bits":handler_size_bits,
571452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee             "handler_size_bytes":handler_size_bytes }
581452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
591452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
601452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
611452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Set interpreter style.
621452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
631452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef setHandlerStyle(tokens):
641452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global style
651452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
661452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("handler-style requires one argument")
671452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    style = tokens[1]
681452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if style != "computed-goto":
691452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("handler-style (%s) invalid" % style)
701452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Set handler_size_bytes to the value of tokens[1], and handler_size_bits to
741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# log2(handler_size_bytes).  Throws an exception if "bytes" is not 0 or
751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# a power of two.
761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef setHandlerSize(tokens):
781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global handler_size_bits, handler_size_bytes
791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if style != "computed-goto":
801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print "Warning: handler-size valid only for computed-goto interpreters"
811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
821452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("handler-size requires one argument")
831452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if handler_size_bits != -1000:
841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("handler-size may only be set once")
851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # compute log2(n), and make sure n is 0 or a power of 2
871452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    handler_size_bytes = bytes = int(tokens[1])
881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    bits = -1
891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    while bytes > 0:
901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        bytes //= 2     # halve with truncating division
911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        bits += 1
921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if handler_size_bytes == 0 or handler_size_bytes != (1 << bits):
941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("handler-size (%d) must be power of 2" \
951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                % orig_bytes)
961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    handler_size_bits = bits
971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Copy a file in to asm output file.
1011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef importFile(tokens):
1031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
1041452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("import requires one argument")
1051452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    source = tokens[1]
1061452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if source.endswith(".S"):
1071452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        appendSourceFile(tokens[1], getGlobalSubDict(), asm_fp, None)
1081452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    else:
1091452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("don't know how to import %s (expecting .cpp/.S)"
1101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                % source)
1111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
1121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Copy a file in to the C or asm output file.
1151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef setAsmStub(tokens):
1171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global asm_stub_text
1181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
1191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("import requires one argument")
1201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    try:
1211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        stub_fp = open(tokens[1])
1221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_stub_text = stub_fp.readlines()
1231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    except IOError, err:
1241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        stub_fp.close()
1251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("unable to load asm-stub: %s" % str(err))
1261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    stub_fp.close()
1271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
1281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Copy a file in to the C or asm output file.
1311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef setFallbackStub(tokens):
1331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global fallback_stub_text
1341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
1351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("import requires one argument")
1361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    try:
1371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        stub_fp = open(tokens[1])
1381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        fallback_stub_text = stub_fp.readlines()
1391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    except IOError, err:
1401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        stub_fp.close()
1411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("unable to load fallback-stub: %s" % str(err))
1421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    stub_fp.close()
1431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1441452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1451452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Record location of default alt stub
1461452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef setAsmAltStub(tokens):
1481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global default_alt_stub, generate_alt_table
1491452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
1501452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("import requires one argument")
1511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    default_alt_stub = tokens[1]
1521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    generate_alt_table = True
15305dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
15405dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov# Change the default function type format
15505dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
15605dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovdef setFunctionTypeFormat(tokens):
15705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    global function_type_format
15805dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    function_type_format = tokens[1]
15905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
16005dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov# Change the default function size format
16105dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
16205dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovdef setFunctionSizeFormat(tokens):
16305dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    global function_size_format
16405dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    function_size_format = tokens[1]
16505dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
16605dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov# Change the global name format
16705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov#
16805dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkovdef setGlobalNameFormat(tokens):
16905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    global global_name_format
17005dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    global_name_format = tokens[1]
1711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Start of opcode list.
1741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef opStart(tokens):
1761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global in_op_start
1771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global default_op_dir
1781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 2:
1791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("opStart takes a directory name argument")
1801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if in_op_start != 0:
1811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("opStart can only be specified once")
1821452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    default_op_dir = tokens[1]
1831452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    in_op_start = 1
1841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
1851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
1871452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Set location of a single alt opcode's source file.
1881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
1891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef altEntry(tokens):
1901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global generate_alt_table
1911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 3:
1921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("alt requires exactly two arguments")
1931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if in_op_start != 1:
1941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("alt statements must be between opStart/opEnd")
1951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    try:
1961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        index = opcodes.index(tokens[1])
1971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    except ValueError:
1981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("unknown opcode %s" % tokens[1])
1991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if alt_opcode_locations.has_key(tokens[1]):
2001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print "Note: alt overrides earlier %s (%s -> %s)" \
2011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                % (tokens[1], alt_opcode_locations[tokens[1]], tokens[2])
2021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    alt_opcode_locations[tokens[1]] = tokens[2]
2031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    generate_alt_table = True
2041452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2051452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2061452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
2071452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Set location of a single opcode's source file.
2081452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2091452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef opEntry(tokens):
2101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    #global opcode_locations
2111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 3:
2121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("op requires exactly two arguments")
2131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if in_op_start != 1:
2141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("op statements must be between opStart/opEnd")
2151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    try:
2161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        index = opcodes.index(tokens[1])
2171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    except ValueError:
2181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("unknown opcode %s" % tokens[1])
2191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if opcode_locations.has_key(tokens[1]):
2201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print "Note: op overrides earlier %s (%s -> %s)" \
2211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                % (tokens[1], opcode_locations[tokens[1]], tokens[2])
2221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    opcode_locations[tokens[1]] = tokens[2]
2231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Parse arch config file --
2261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# End of opcode list; emit instruction blocks.
2271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef opEnd(tokens):
2291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    global in_op_start
2301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 1:
2311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("opEnd takes no arguments")
2321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if in_op_start != 1:
2331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("opEnd must follow opStart, and only appear once")
2341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    in_op_start = 2
2351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    loadAndEmitOpcodes()
2371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if splitops == False:
2381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if generate_alt_table:
2391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            loadAndEmitAltOpcodes()
2401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef genaltop(tokens):
2421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if in_op_start != 2:
2431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee       raise DataParseError("alt-op can be specified only after op-end")
2441452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(tokens) != 1:
2451452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise DataParseError("opEnd takes no arguments")
2461452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if generate_alt_table:
2471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        loadAndEmitAltOpcodes()
2481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2491452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2501452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Extract an ordered list of instructions from the VM sources.  We use the
2511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# "goto table" definition macro, which has exactly kNumPackedOpcodes
2521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# entries.
2531452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2541452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef getOpcodeList():
2551452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    opcodes = []
2561452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    opcode_fp = open(interp_defs_file)
2571452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    opcode_re = re.compile(r"^\s*V\((....), (\w+),.*", re.DOTALL)
2581452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for line in opcode_fp:
2591452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        match = opcode_re.match(line)
2601452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if not match:
2611452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            continue
2621452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        opcodes.append("op_" + match.group(2).lower())
2631452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    opcode_fp.close()
2641452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2651452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if len(opcodes) != kNumPackedOpcodes:
2661452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print "ERROR: found %d opcodes in Interp.h (expected %d)" \
2671452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                % (len(opcodes), kNumPackedOpcodes)
2681452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        raise SyntaxError, "bad opcode count"
2691452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    return opcodes
2701452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef emitAlign():
2721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if style == "computed-goto":
2731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.write("    .balign %d\n" % handler_size_bytes)
2741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Load and emit opcodes for all kNumPackedOpcodes instructions.
2771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
2781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef loadAndEmitOpcodes():
2791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    sister_list = []
2801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    assert len(opcodes) == kNumPackedOpcodes
2811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    need_dummy_start = False
28205dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    start_label = global_name_format % "artMterpAsmInstructionStart"
28305dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    end_label = global_name_format % "artMterpAsmInstructionEnd"
2841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # point MterpAsmInstructionStart at the first handler or stub
2861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("\n    .global %s\n" % start_label)
28705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    asm_fp.write("    " + (function_type_format % start_label) + "\n");
2881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("%s = " % start_label + label_prefix + "_op_nop\n")
2891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("    .text\n\n")
2901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for i in xrange(kNumPackedOpcodes):
2921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        op = opcodes[i]
2931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if opcode_locations.has_key(op):
2951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            location = opcode_locations[op]
2961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
2971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            location = default_op_dir
2981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
2991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if location == "FALLBACK":
3001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            emitFallback(i)
3011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
3021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            loadAndEmitAsm(location, i, sister_list)
3031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3041452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # For a 100% C implementation, there are no asm handlers or stubs.  We
3051452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # need to have the MterpAsmInstructionStart label point at op_nop, and it's
3061452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # too annoying to try to slide it in after the alignment psuedo-op, so
3071452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # we take the low road and just emit a dummy op_nop here.
3081452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if need_dummy_start:
3091452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        emitAlign()
3101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.write(label_prefix + "_op_nop:   /* dummy */\n");
3111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAlign()
31305dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    asm_fp.write("    " + (function_size_format % (start_label, start_label)) + "\n")
3141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("    .global %s\n" % end_label)
3151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("%s:\n" % end_label)
3161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if style == "computed-goto":
31805dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        start_sister_label = global_name_format % "artMterpAsmSisterStart"
31905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        end_sister_label = global_name_format % "artMterpAsmSisterEnd"
3201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        emitSectionComment("Sister implementations", asm_fp)
32105dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("    .global %s\n" % start_sister_label)
32205dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("    " + (function_type_format % start_sister_label) + "\n");
3231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.write("    .text\n")
3241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.write("    .balign 4\n")
32505dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("%s:\n" % start_sister_label)
3261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.writelines(sister_list)
32705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("\n    " + (function_size_format % (start_sister_label, start_sister_label)) + "\n")
32805dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("    .global %s\n" % end_sister_label)
32905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov        asm_fp.write("%s:\n\n" % end_sister_label)
3301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Load an alternate entry stub
3331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef loadAndEmitAltStub(source, opindex):
3351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    op = opcodes[opindex]
3361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if verbose:
3371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print " alt emit %s --> stub" % source
3381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict = getGlobalSubDict()
3391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict.update({ "opcode":op, "opnum":opindex })
3401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAsmHeader(asm_fp, dict, alt_label_prefix)
3421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    appendSourceFile(source, dict, asm_fp, None)
3431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3441452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3451452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Load and emit alternate opcodes for all kNumPackedOpcodes instructions.
3461452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef loadAndEmitAltOpcodes():
3481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    assert len(opcodes) == kNumPackedOpcodes
34905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    start_label = global_name_format % "artMterpAsmAltInstructionStart"
35005dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    end_label = global_name_format % "artMterpAsmAltInstructionEnd"
3511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # point MterpAsmInstructionStart at the first handler or stub
3531452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("\n    .global %s\n" % start_label)
35405dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    asm_fp.write("    " + (function_type_format % start_label) + "\n");
3551452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("    .text\n\n")
3561452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("%s = " % start_label + label_prefix + "_ALT_op_nop\n")
3571452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3581452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for i in xrange(kNumPackedOpcodes):
3591452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        op = opcodes[i]
3601452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if alt_opcode_locations.has_key(op):
3611452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            source = "%s/alt_%s.S" % (alt_opcode_locations[op], op)
3621452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
3631452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            source = default_alt_stub
3641452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        loadAndEmitAltStub(source, i)
3651452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3661452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAlign()
36705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov    asm_fp.write("    " + (function_size_format % (start_label, start_label)) + "\n")
3681452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("    .global %s\n" % end_label)
3691452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("%s:\n" % end_label)
3701452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Load an assembly fragment and emit it.
3731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef loadAndEmitAsm(location, opindex, sister_list):
3751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    op = opcodes[opindex]
3761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    source = "%s/%s.S" % (location, op)
3771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict = getGlobalSubDict()
3781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict.update({ "opcode":op, "opnum":opindex })
3791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    if verbose:
3801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        print " emit %s --> asm" % source
3811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3821452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAsmHeader(asm_fp, dict, label_prefix)
3831452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    appendSourceFile(source, dict, asm_fp, sister_list)
3841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Emit fallback fragment
3871452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef emitFallback(opindex):
3891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    op = opcodes[opindex]
3901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict = getGlobalSubDict()
3911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    dict.update({ "opcode":op, "opnum":opindex })
3921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAsmHeader(asm_fp, dict, label_prefix)
3931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for line in fallback_stub_text:
3941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        asm_fp.write(line)
3951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.write("\n")
3961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
3971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
3981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Output the alignment directive and label for an assembly piece.
3991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef emitAsmHeader(outfp, dict, prefix):
4011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    outfp.write("/* ------------------------------ */\n")
4021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # The alignment directive ensures that the handler occupies
4031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # at least the correct amount of space.  We don't try to deal
4041452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # with overflow here.
4051452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAlign()
4061452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # Emit a label so that gdb will say the right thing.  We prepend an
4071452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # underscore so the symbol name doesn't clash with the Opcode enum.
4081452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    outfp.write(prefix + "_%(opcode)s: /* 0x%(opnum)02x */\n" % dict)
4091452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Output a generic instruction stub that updates the "glue" struct and
4121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# calls the C implementation.
4131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef emitAsmStub(outfp, dict):
4151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    emitAsmHeader(outfp, dict, label_prefix)
4161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for line in asm_stub_text:
4171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        templ = Template(line)
4181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        outfp.write(templ.substitute(dict))
4191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Append the file specified by "source" to the open "outfp".  Each line will
4221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# be template-replaced using the substitution dictionary "dict".
4231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# If the first line of the file starts with "%" it is taken as a directive.
4251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# A "%include" line contains a filename and, optionally, a Python-style
4261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# dictionary declaration with substitution strings.  (This is implemented
4271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# with recursion.)
4281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# If "sister_list" is provided, and we find a line that contains only "&",
4301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# all subsequent lines from the file will be appended to sister_list instead
4311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# of copied to the output.
4321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# This may modify "dict".
4341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef appendSourceFile(source, dict, outfp, sister_list):
4361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    outfp.write("/* File: %s */\n" % source)
4371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    infp = open(source, "r")
4381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    in_sister = False
4391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for line in infp:
4401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if line.startswith("%include"):
4411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            # Parse the "include" line
4421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            tokens = line.strip().split(' ', 2)
4431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if len(tokens) < 2:
4441452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError("malformed %%include in %s" % source)
4451452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4461452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            alt_source = tokens[1].strip("\"")
4471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if alt_source == source:
4481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError("self-referential %%include in %s"
4491452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                        % source)
4501452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            new_dict = dict.copy()
4521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if len(tokens) == 3:
4531452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                new_dict.update(eval(tokens[2]))
4541452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            #print " including src=%s dict=%s" % (alt_source, new_dict)
4551452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            appendSourceFile(alt_source, new_dict, outfp, sister_list)
4561452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            continue
4571452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4581452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        elif line.startswith("%default"):
4591452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            # copy keywords into dictionary
4601452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            tokens = line.strip().split(' ', 1)
4611452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if len(tokens) < 2:
4621452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError("malformed %%default in %s" % source)
4631452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            defaultValues = eval(tokens[1])
4641452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            for entry in defaultValues:
4651452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                dict.setdefault(entry, defaultValues[entry])
4661452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            continue
4671452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4681452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        elif line.startswith("%break") and sister_list != None:
4691452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            # allow more than one %break, ignoring all following the first
4701452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if style == "computed-goto" and not in_sister:
4711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                in_sister = True
4721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                sister_list.append("\n/* continuation for %(opcode)s */\n"%dict)
4731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            continue
4741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        # perform keyword substitution if a dictionary was provided
4761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if dict != None:
4771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            templ = Template(line)
4781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            try:
4791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                subline = templ.substitute(dict)
4801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            except KeyError, err:
4811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError("keyword substitution failed in %s: %s"
4821452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                        % (source, str(err)))
4831452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            except:
4841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                print "ERROR: substitution failed: " + line
4851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise
4861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
4871452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            subline = line
4881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        # write output to appropriate file
4901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if in_sister:
4911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            sister_list.append(subline)
4921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
4931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            outfp.write(subline)
4941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    outfp.write("\n")
4951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    infp.close()
4961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
4971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
4981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Emit a C-style section header comment.
4991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeedef emitSectionComment(str, fp):
5011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    equals = "========================================" \
5021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee             "==================================="
5031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5041452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    fp.write("\n/*\n * %s\n *  %s\n * %s\n */\n" %
5051452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        (equals, str, equals))
5061452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5071452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5081452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5091452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# ===========================================================================
5101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# "main" code
5111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Check args.
5151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeif len(sys.argv) != 3:
5171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    print "Usage: %s target-arch output-dir" % sys.argv[0]
5181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    sys.exit(2)
5191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeetarget_arch = sys.argv[1]
5211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeoutput_dir = sys.argv[2]
5221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Extract opcode list.
5251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeopcodes = getOpcodeList()
5271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#for op in opcodes:
5281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#    print "  %s" % op
5291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5311452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Open config file.
5321452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5331452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeetry:
5341452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    config_fp = open("config_%s" % target_arch)
5351452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeexcept:
5361452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    print "Unable to open config file 'config_%s'" % target_arch
5371452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    sys.exit(1)
5381452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5391452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5401452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Open and prepare output files.
5411452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5421452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeetry:
5431452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp = open("%s/mterp_%s.S" % (output_dir, target_arch), "w")
5441452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeexcept:
5451452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    print "Unable to open output files"
5461452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    print "Make sure directory '%s' exists and existing files are writable" \
5471452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            % output_dir
5481452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # Ideally we'd remove the files to avoid confusing "make", but if they
5491452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # failed to open we probably won't be able to remove them either.
5501452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    sys.exit(1)
5511452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5521452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeprint "Generating %s" % (asm_fp.name)
5531452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5541452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeefile_header = """/*
5551452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * This file was generated automatically by gen-mterp.py for '%s'.
5561452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee *
5571452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * --> DO NOT EDIT <--
5581452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee */
5591452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5601452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee""" % (target_arch)
5611452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5621452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeasm_fp.write(file_header)
5631452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
5641452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5651452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Process the config file.
5661452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
5671452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeefailed = False
5681452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeetry:
5691452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    for line in config_fp:
5701452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        line = line.strip()         # remove CRLF, leading spaces
5711452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        tokens = line.split(' ')    # tokenize
5721452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        #print "%d: %s" % (len(tokens), tokens)
5731452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        if len(tokens[0]) == 0:
5741452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            #print "  blank"
5751452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            pass
5761452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        elif tokens[0][0] == '#':
5771452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            #print "  comment"
5781452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            pass
5791452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee        else:
5801452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if tokens[0] == "handler-size":
5811452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                setHandlerSize(tokens)
5821452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "import":
5831452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                importFile(tokens)
5841452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "asm-stub":
5851452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                setAsmStub(tokens)
5861452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "asm-alt-stub":
5871452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                setAsmAltStub(tokens)
5881452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "op-start":
5891452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                opStart(tokens)
5901452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "op-end":
5911452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                opEnd(tokens)
5921452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "alt":
5931452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                altEntry(tokens)
5941452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "op":
5951452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                opEntry(tokens)
5961452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "handler-style":
5971452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                setHandlerStyle(tokens)
5981452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "alt-ops":
5991452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                genaltop(tokens)
6001452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "split-ops":
6011452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                splitops = True
6021452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            elif tokens[0] == "fallback-stub":
6031452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee               setFallbackStub(tokens)
60405dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov            elif tokens[0] == "function-type-format":
60505dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov               setFunctionTypeFormat(tokens)
60605dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov            elif tokens[0] == "function-size-format":
60705dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov               setFunctionSizeFormat(tokens)
60805dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov            elif tokens[0] == "global-name-format":
60905dfaaa8d1783bcf8fe603dd8ed260a939e846c0Serguei Katkov               setGlobalNameFormat(tokens)
6101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            else:
6111452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError, "unrecognized command '%s'" % tokens[0]
6121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee            if style == None:
6131452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                print "tokens[0] = %s" % tokens[0]
6141452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee                raise DataParseError, "handler-style must be first command"
6151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeexcept DataParseError, err:
6161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    print "Failed: " + str(err)
6171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    # TODO: remove output files so "make" doesn't get confused
6181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    failed = True
6191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.close()
6201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp = None
6211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
6221452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeconfig_fp.close()
6231452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
6241452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
6251452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee# Done!
6261452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee#
6271452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeeif asm_fp:
6281452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee    asm_fp.close()
6291452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee
6301452bee8f06b9f76a333ddf4760e4beaa82f8099buzbeesys.exit(failed)
631