1ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#!/usr/bin/env python
2ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
3ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Copyright (C) 2007 The Android Open Source Project
4ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
5ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Licensed under the Apache License, Version 2.0 (the "License");
6ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# you may not use this file except in compliance with the License.
7ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# You may obtain a copy of the License at
8ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
9ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#      http://www.apache.org/licenses/LICENSE-2.0
10ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
11ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Unless required by applicable law or agreed to in writing, software
12ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# distributed under the License is distributed on an "AS IS" BASIS,
13ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# See the License for the specific language governing permissions and
15ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# limitations under the License.
16ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
17ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
18ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Using instructions from an architecture-specific config file, generate C
19ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# and assembly source files for the Dalvik JIT.
20ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
21ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
22ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengimport sys, string, re, time
23ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengfrom string import Template
24ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
25ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chenginterp_defs_file = "TemplateOpList.h" # need opcode list
26ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
27ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chenghandler_size_bits = -1000
28ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chenghandler_size_bytes = -1000
29ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengin_op_start = 0             # 0=not started, 1=started, 2=ended
30ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdefault_op_dir = None
31ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengopcode_locations = {}
32ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengasm_stub_text = []
33ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chenglabel_prefix = ".L"         # use ".L" to hide labels from gdb
34ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
35ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
36ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Exception class.
37ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengclass DataParseError(SyntaxError):
38ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    "Failure when parsing data file"
39ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
40ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
41ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Set any omnipresent substitution values.
42ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
43ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef getGlobalSubDict():
44ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    return { "handler_size_bits":handler_size_bits,
45ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng             "handler_size_bytes":handler_size_bytes }
46ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
47ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
48ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
49ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Set handler_size_bytes to the value of tokens[1], and handler_size_bits to
50ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# log2(handler_size_bytes).  Throws an exception if "bytes" is not a power
51ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# of two.
52ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
53ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef setHandlerSize(tokens):
54ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    global handler_size_bits, handler_size_bytes
55ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 2:
56ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("handler-size requires one argument")
57ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if handler_size_bits != -1000:
58ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("handler-size may only be set once")
59ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
60ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # compute log2(n), and make sure n is a power of 2
61ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    handler_size_bytes = bytes = int(tokens[1])
62ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    bits = -1
63ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    while bytes > 0:
64ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        bytes //= 2     # halve with truncating division
65ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        bits += 1
66ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
67ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if handler_size_bytes == 0 or handler_size_bytes != (1 << bits):
68ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("handler-size (%d) must be power of 2 and > 0" \
69ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                % orig_bytes)
70ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    handler_size_bits = bits
71ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
72ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
73ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
74ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Copy a file in to the C or asm output file.
75ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
76ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef importFile(tokens):
77ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 2:
78ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("import requires one argument")
79ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    source = tokens[1]
80ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if source.endswith(".S"):
81ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        appendSourceFile(tokens[1], getGlobalSubDict(), asm_fp, None)
82ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    else:
83ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("don't know how to import %s (expecting .c/.S)"
84ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                % source)
85ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
86ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
87ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
88ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Copy a file in to the C or asm output file.
89ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
90ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef setAsmStub(tokens):
91ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    global asm_stub_text
92ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 2:
93ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("import requires one argument")
94ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    try:
95ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        stub_fp = open(tokens[1])
96ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        asm_stub_text = stub_fp.readlines()
97ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    except IOError, err:
98ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        stub_fp.close()
99ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("unable to load asm-stub: %s" % str(err))
100ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    stub_fp.close()
101ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
102ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
103ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
104ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Start of opcode list.
105ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
106ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef opStart(tokens):
107ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    global in_op_start
108ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    global default_op_dir
109ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 2:
110ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("opStart takes a directory name argument")
111ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if in_op_start != 0:
112ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("opStart can only be specified once")
113ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    default_op_dir = tokens[1]
114ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    in_op_start = 1
115ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
116ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
117ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
118ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Set location of a single opcode's source file.
119ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
120ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef opEntry(tokens):
121ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    #global opcode_locations
122ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 3:
123ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("op requires exactly two arguments")
124ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if in_op_start != 1:
125ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("op statements must be between opStart/opEnd")
126ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    try:
127ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        index = opcodes.index(tokens[1])
128ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    except ValueError:
129ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("unknown opcode %s" % tokens[1])
130ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    opcode_locations[tokens[1]] = tokens[2]
131ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
132ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
133ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Parse arch config file --
134ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# End of opcode list; emit instruction blocks.
135ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
136ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef opEnd(tokens):
137ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    global in_op_start
138ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if len(tokens) != 1:
139ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("opEnd takes no arguments")
140ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if in_op_start != 1:
141ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        raise DataParseError("opEnd must follow opStart, and only appear once")
142ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    in_op_start = 2
143ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
144ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    loadAndEmitOpcodes()
145ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
146ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
147ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
148ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Extract an ordered list of instructions from the VM sources.  We use the
149ccaab18ae6d203108445fef7682065dfbb007657Dan Bornstein# "goto table" definition macro, which has exactly kNumPackedOpcodes
150675b642510ed79e8a7a3f23126dfac7679fd65b9Dan Bornstein# entries.
151ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
152ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef getOpcodeList():
153ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    opcodes = []
154ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    opcode_fp = open("%s/%s" % (target_arch, interp_defs_file))
155ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    opcode_re = re.compile(r"^JIT_TEMPLATE\((\w+)\)", re.DOTALL)
156ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for line in opcode_fp:
157ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        match = opcode_re.match(line)
158ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if not match:
159ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue
160ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        opcodes.append("TEMPLATE_" + match.group(1))
161ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    opcode_fp.close()
162ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
163ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    return opcodes
164ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
165ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
166ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
167ccaab18ae6d203108445fef7682065dfbb007657Dan Bornstein# Load and emit opcodes for all kNumPackedOpcodes instructions.
168ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
169ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef loadAndEmitOpcodes():
170ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    sister_list = []
171ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
172ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # point dvmAsmInstructionStart at the first handler or stub
173ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.write("\n    .global dvmCompilerTemplateStart\n")
174ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.write("    .type   dvmCompilerTemplateStart, %function\n")
1755dfcc78af479937ba8dafceefd9b1931a88dfaafArd Biesheuvel    asm_fp.write("    .section .data.rel.ro\n\n")
176ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.write("dvmCompilerTemplateStart:\n\n")
177ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
178ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for i in xrange(len(opcodes)):
179ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        op = opcodes[i]
180ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
181ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if opcode_locations.has_key(op):
182ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            location = opcode_locations[op]
183ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        else:
184ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            location = default_op_dir
185ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
186ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        loadAndEmitAsm(location, i, sister_list)
187ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
188ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # Use variable sized handlers now
189ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # asm_fp.write("\n    .balign %d\n" % handler_size_bytes)
190ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.write("    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart\n")
191ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
192ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
193ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Load an assembly fragment and emit it.
194ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
195ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef loadAndEmitAsm(location, opindex, sister_list):
196ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    op = opcodes[opindex]
197ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    source = "%s/%s.S" % (location, op)
198ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dict = getGlobalSubDict()
199ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dict.update({ "opcode":op, "opnum":opindex })
200ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print " emit %s --> asm" % source
201ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
202ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    emitAsmHeader(asm_fp, dict)
203ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    appendSourceFile(source, dict, asm_fp, sister_list)
204ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
205ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
206ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Output the alignment directive and label for an assembly piece.
207ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
208ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef emitAsmHeader(outfp, dict):
209ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("/* ------------------------------ */\n")
210ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # The alignment directive ensures that the handler occupies
211ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # at least the correct amount of space.  We don't try to deal
212ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # with overflow here.
213ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("    .balign 4\n")
214ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # Emit a label so that gdb will say the right thing.  We prepend an
2159a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    # underscore so the symbol name doesn't clash with the Opcode enum.
216ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    template_name = "dvmCompiler_%(opcode)s" % dict
217ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("    .global %s\n" % template_name);
218ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("%s:\n" % template_name);
219ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
220ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
221ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Output a generic instruction stub that updates the "glue" struct and
222ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# calls the C implementation.
223ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
224ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef emitAsmStub(outfp, dict):
225ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    emitAsmHeader(outfp, dict)
226ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for line in asm_stub_text:
227ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        templ = Template(line)
228ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        outfp.write(templ.substitute(dict))
229ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
230ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
231ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Append the file specified by "source" to the open "outfp".  Each line will
232ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# be template-replaced using the substitution dictionary "dict".
233ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
234ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# If the first line of the file starts with "%" it is taken as a directive.
235ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# A "%include" line contains a filename and, optionally, a Python-style
236ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# dictionary declaration with substitution strings.  (This is implemented
237ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# with recursion.)
238ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
239ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# If "sister_list" is provided, and we find a line that contains only "&",
240ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# all subsequent lines from the file will be appended to sister_list instead
241ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# of copied to the output.
242ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
243ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# This may modify "dict".
244ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
245ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef appendSourceFile(source, dict, outfp, sister_list):
246ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("/* File: %s */\n" % source)
247ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    infp = open(source, "r")
248ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    in_sister = False
249ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for line in infp:
250ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if line.startswith("%include"):
251ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            # Parse the "include" line
252ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            tokens = line.strip().split(' ', 2)
253ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if len(tokens) < 2:
254ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise DataParseError("malformed %%include in %s" % source)
255ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
256ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            alt_source = tokens[1].strip("\"")
257ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if alt_source == source:
258ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise DataParseError("self-referential %%include in %s"
259ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                        % source)
260ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
261ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            new_dict = dict.copy()
262ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if len(tokens) == 3:
263ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                new_dict.update(eval(tokens[2]))
264ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            #print " including src=%s dict=%s" % (alt_source, new_dict)
265ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            appendSourceFile(alt_source, new_dict, outfp, sister_list)
266ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue
267ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
268ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        elif line.startswith("%default"):
269ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            # copy keywords into dictionary
270ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            tokens = line.strip().split(' ', 1)
271ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if len(tokens) < 2:
272ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise DataParseError("malformed %%default in %s" % source)
273ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            defaultValues = eval(tokens[1])
274ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            for entry in defaultValues:
275ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                dict.setdefault(entry, defaultValues[entry])
276ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue
277ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
278ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        elif line.startswith("%verify"):
279ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            # more to come, someday
280ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue
281ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
282ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        elif line.startswith("%break") and sister_list != None:
283ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            # allow more than one %break, ignoring all following the first
284ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if not in_sister:
285ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                in_sister = True
286ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                sister_list.append("\n/* continuation for %(opcode)s */\n"%dict)
287ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue
288ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
289ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        # perform keyword substitution if a dictionary was provided
290ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if dict != None:
291ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            templ = Template(line)
292ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            try:
293ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                subline = templ.substitute(dict)
294ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            except KeyError, err:
295ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise DataParseError("keyword substitution failed in %s: %s"
296ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                        % (source, str(err)))
297ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            except:
298ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                print "ERROR: substitution failed: " + line
299ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise
300ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        else:
301ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            subline = line
302ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
303ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        # write output to appropriate file
304ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if in_sister:
305ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            sister_list.append(subline)
306ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        else:
307ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            outfp.write(subline)
308ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    outfp.write("\n")
309ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    infp.close()
310ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
311ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
312ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Emit a C-style section header comment.
313ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
314ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengdef emitSectionComment(str, fp):
315ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    equals = "========================================" \
316ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng             "==================================="
317ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
318ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    fp.write("\n/*\n * %s\n *  %s\n * %s\n */\n" %
319ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        (equals, str, equals))
320ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
321ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
322ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
323ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# ===========================================================================
324ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# "main" code
325ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
326ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
327ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
328ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Check args.
329ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
330ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengif len(sys.argv) != 3:
331ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print "Usage: %s target-arch output-dir" % sys.argv[0]
332ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    sys.exit(2)
333ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
334ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengtarget_arch = sys.argv[1]
335ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengoutput_dir = sys.argv[2]
336ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
337ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
338ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Extract opcode list.
339ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
340ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengopcodes = getOpcodeList()
341ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#for op in opcodes:
342ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#    print "  %s" % op
343ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
344ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
345ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Open config file.
346ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
347ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengtry:
348ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    config_fp = open("config-%s" % target_arch)
349ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengexcept:
350ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print "Unable to open config file 'config-%s'" % target_arch
351ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    sys.exit(1)
352ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
353ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
354ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Open and prepare output files.
355ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
356ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengtry:
357ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp = open("%s/CompilerTemplateAsm-%s.S" % (output_dir, target_arch), "w")
358ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengexcept:
359ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print "Unable to open output files"
360ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print "Make sure directory '%s' exists and existing files are writable" \
361ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            % output_dir
362ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # Ideally we'd remove the files to avoid confusing "make", but if they
363ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # failed to open we probably won't be able to remove them either.
364ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    sys.exit(1)
365ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
366ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengprint "Generating %s" % (asm_fp.name)
367ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
368ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengfile_header = """/*
369ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * This file was generated automatically by gen-template.py for '%s'.
370ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng *
371ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * --> DO NOT EDIT <--
372ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */
373ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
374ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng""" % (target_arch)
375ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
376ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengasm_fp.write(file_header)
377ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
378ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
379ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Process the config file.
380ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
381ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengfailed = False
382ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengtry:
383ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for line in config_fp:
384ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        line = line.strip()         # remove CRLF, leading spaces
385ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        tokens = line.split(' ')    # tokenize
386ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        #print "%d: %s" % (len(tokens), tokens)
387ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if len(tokens[0]) == 0:
388ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            #print "  blank"
389ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            pass
390ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        elif tokens[0][0] == '#':
391ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            #print "  comment"
392ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            pass
393ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        else:
394ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            if tokens[0] == "handler-size":
395ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                setHandlerSize(tokens)
396ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            elif tokens[0] == "import":
397ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                importFile(tokens)
398ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            elif tokens[0] == "asm-stub":
399ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                setAsmStub(tokens)
400ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            elif tokens[0] == "op-start":
401ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                opStart(tokens)
402ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            elif tokens[0] == "op-end":
403ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                opEnd(tokens)
404ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            elif tokens[0] == "op":
405ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                opEntry(tokens)
406ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            else:
407ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                raise DataParseError, "unrecognized command '%s'" % tokens[0]
408ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengexcept DataParseError, err:
409ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    print "Failed: " + str(err)
410ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    # TODO: remove output files so "make" doesn't get confused
411ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    failed = True
412ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.close()
413ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    c_fp = asm_fp = None
414ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
415ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengconfig_fp.close()
416ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
417ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
418ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng# Done!
419ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#
420ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengif asm_fp:
421ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    asm_fp.close()
422ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
423ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengsys.exit(failed)
424