Index: tools/generate-x32-sources.py |
=================================================================== |
--- tools/generate-x32-sources.py (revision 0) |
+++ tools/generate-x32-sources.py (revision 0) |
@@ -0,0 +1,371 @@ |
+#!/usr/bin/env python |
+# |
danno
2013/07/17 13:33:21
As discussed offline, this file shouldn't be added
|
+# Copyright 2012 the V8 project authors. All rights reserved. |
+# Redistribution and use in source and binary forms, with or without |
+# modification, are permitted provided that the following conditions are |
+# met: |
+# |
+# * Redistributions of source code must retain the above copyright |
+# notice, this list of conditions and the following disclaimer. |
+# * Redistributions in binary form must reproduce the above |
+# copyright notice, this list of conditions and the following |
+# disclaimer in the documentation and/or other materials provided |
+# with the distribution. |
+# * Neither the name of Google Inc. nor the names of its |
+# contributors may be used to endorse or promote products derived |
+# from this software without specific prior written permission. |
+# |
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+import sys |
+import os |
+ |
+# This script generates the x32 sources from annoated x64 codes. |
+# <Usage>: |
+# ./generate-x32-source.py {debug|release} output_file_names input_file_names |
+# |
+# The annotations include: |
+# __a (argument) : Replace (n + 1) * kPointerSize with 1 * kHWRegSize + |
+# n * kPointerSize and __a with __ or remove "__a ". |
+# The size of return address is kHWRegSize for X32, the current X64 codes |
+# assume return address size is kPointerSize, so we replace the argument |
+# access offset with the right value. |
+# |
+# __k (keep) : Keep the current line unchanged and replace __k with __ |
+# or remove "__k ". |
+# We need to use 64-bit instructions for X32 when: |
+# 1) Load/Store 64-bit value. |
+# 2) Load/Store double into heap number field |
+# 3) Use push/pop for return address and FP register |
+# 4) Get signed index register for SIB access |
+# |
+# __q (quad) : Replace kPointerSize with kHWRegSize and __q with __ |
+# or remove "__q ". |
+# We need to use quadword for X32 when: |
+# 1) Pass arguments to the C++ runtime, we need 8-byte in the stack |
+# according to X32 ABI (https://sites.google.com/site/x32abi/) |
+# 2) Access a stack slot when skipping return address or FP |
+# 3) Compute size of state in the deoptimization process as we store state |
+# as quadword in the stack |
+# |
+# __n : Replace RelocInfo::NONE64 with RelocInfo::NONE32. |
+# |
+# __s (quad, keep) : Combine __k and __q. It is used when storing a register |
+# to the runtime stack for RegExp. |
+# |
+# After handling the annotations, if not __k or __s, the rest of the line will |
+# be processed according to the operator_handlers (see below). |
+ |
+argument_replacements = { |
+ "1 * kPointerSize" : "1 * kHWRegSize", |
+ "2 * kPointerSize" : "1 * kHWRegSize + 1 * kPointerSize", |
+ "3 * kPointerSize" : "1 * kHWRegSize + 2 * kPointerSize", |
+ "4 * kPointerSize" : "1 * kHWRegSize + 3 * kPointerSize", |
+ "5 * kPointerSize" : "1 * kHWRegSize + 4 * kPointerSize", |
+ "6 * kPointerSize" : "1 * kHWRegSize + 5 * kPointerSize", |
+ "i * kPointerSize" : "1 * kHWRegSize + (i - 1) * kPointerSize", |
+ "argc * kPointerSize" : "1 * kHWRegSize + (argc - 1) * kPointerSize", |
+ "(argc - 0) * kPointerSize" : "1 * kHWRegSize + (argc - 1) * kPointerSize", |
+ "(argc + 1) * kPointerSize" : "1 * kHWRegSize + argc * kPointerSize", |
+ "(argc_ + 1) * kPointerSize" : "1 * kHWRegSize + argc_ * kPointerSize", |
+} |
+ |
+def HandleArgument(line): |
+ result = line |
+ if result.find("times_pointer_size, 0)") != -1: |
+ result = result.replace("times_pointer_size, 0)", \ |
+ "times_pointer_size, kPointerSize)") |
+ else: |
+ for argument in argument_replacements: |
+ if result.find(argument) != -1: |
+ result = result.replace(argument, argument_replacements[argument]) |
+ break |
+ |
+ return (True, result) |
+ |
+def HandleKeep(line): |
+ return (False, line) |
+ |
+def HandleQuad(line): |
+ result = line |
+ result = result.replace("kPointerSize", "kHWRegSize") |
+ return (True, result) |
+ |
+def HandleNone64(line): |
+ result = line |
+ result = result.replace("RelocInfo::NONE64", "RelocInfo::NONE32") |
+ return (True, result) |
+ |
+def HandleQuadKeep(line): |
+ (cont, result) = HandleQuad(line) |
+ return HandleKeep(result) |
+ |
+annotation_handlers = { |
+ " __a" : [" ", HandleArgument], |
+ " __k" : [" ", HandleKeep], |
+ " __q" : [" ", HandleQuad], |
+ " __n" : [" ", HandleNone64], |
+ " __s" : [" ", HandleQuadKeep], |
+} |
+ |
+def Replace(line, key): |
+ return line.replace(key, operator_handlers[key][0]) |
+ |
+def HandlePushPop(line, key): |
+ if line.find("push(rbp)") == -1 and line.find("pop(rbp)") == -1: |
+ return Replace(line, key) |
+ else: |
+ return line |
+ |
+def HandleMovQ(line, key): |
+ result = line |
+ if result.find("xmm") == -1 and result.find("double_scratch") == -1 and \ |
+ result.find("V8_UINT64_C") == -1 and result.find("V8_INT64_C") == -1: |
+ result = Replace(result, key) |
+ if result.find("kZapValue") != -1 and result.find("NONE64") != -1: |
+ result = result.replace("int64_t", "int32_t") |
+ result = result.replace("NONE64", "NONE32") |
+ return result |
+ |
+operator_handlers = { |
+ "movq(" : ("movl(", HandleMovQ), |
+ "push(" : ("Push(", HandlePushPop), |
+ "pop(" : ("Pop(", HandlePushPop), |
+ "push_imm32(" : ("Push_imm32(", Replace), |
+ " cmovq(" : (" cmovl(", Replace), |
+ " xchg(" : (" xchgl(", Replace), |
+ " addq(" : (" addl(", Replace), |
+ " sbbq(" : (" sbbl(", Replace), |
+ " cmpq(" : (" cmpl(", Replace), |
+ " and_(" : (" andl(", Replace), |
+ " decq(" : (" decl(", Replace), |
+ " cqo(" : (" cdq(", Replace), |
+ " idivq(" : (" idivl(", Replace), |
+ " imul(" : (" imull(", Replace), |
+ " incq(" : (" incl(", Replace), |
+ " lea(" : (" leal(", Replace), |
+ " neg(" : (" negl(", Replace), |
+ " not_(" : (" notl(", Replace), |
+ " or_(" : (" orl(", Replace), |
+ " rol(" : (" roll(", Replace), |
+ " ror(" : (" rorl(", Replace), |
+ " sar(" : (" sarl(", Replace), |
+ " sar_cl(" : (" sarl_cl(", Replace), |
+ " shl(" : (" shll(", Replace), |
+ " shl_cl(" : (" shll_cl(", Replace), |
+ " shr(" : (" shrl(", Replace), |
+ " shr_cl(" : (" shrl_cl(", Replace), |
+ " subq(" : (" subl(", Replace), |
+ " testq(" : (" testl(", Replace), |
+ " xor_(" : (" xorl(", Replace), |
+ " movzxbq(" : (" movzxbl(", Replace), |
+ " repmovsq(" : (" repmovsl(", Replace), |
+} |
+ |
+def HandleAnnotations(line, debug): |
+ cont = True |
+ result = line |
+ for annotation in annotation_handlers: |
+ if result.find(annotation) != -1: |
+ if result.find(annotation + " ") != -1: |
+ if result.find("#define" + annotation + " __") != -1: |
+ # Add a new line to keep debugging easier if debug |
+ result = "\n" if debug else "" |
+ annotation_handlers[annotation][0] = " __" |
+ else: |
+ (cont, result) = annotation_handlers[annotation][1](result) |
+ if annotation_handlers[annotation][0] == " ": |
+ result = result.replace(annotation + " ", \ |
+ annotation_handlers[annotation][0]) |
+ else: |
+ result = result.replace(annotation, \ |
+ annotation_handlers[annotation][0]) |
+ else: |
+ if result.find("#define") != -1 or result.find("#undef") != -1: |
+ # Add a new line to keep debugging easier if debug |
+ result = "\n" if debug else "" |
+ annotation_handlers[annotation][0] = " " |
+ break |
+ |
+ return (cont, result) |
+ |
+comment_replacements = { |
+ "rbp[24]" : "rbp[20]", |
+ "rbp[32]" : "rbp[24]", |
+ "rbp[-n-8]" : "rbp[-n-4]", |
+ "rsp[16]" : "rsp[12]", |
+ "rsp[24]" : "rsp[16]", |
+ "rsp[32]" : "rsp[20]", |
+ "rsp[40]" : "rsp[24]", |
+ "rsp[48]" : "rsp[28]", |
+ "rsp[56]" : "rsp[32]", |
+ "rsp[argc * 8] " : "rsp[(argc - 1) * 4 + 8]", |
+ "rsp[kFastApiCallArguments * 8] " : \ |
+ "rsp[(kFastApiCallArguments - 1) * 4 + 8]", |
+ "rsp[8 * argc] " : "rsp[(argc - 1) * 4 + 8]", |
+ "rsp[8 * n] " : "rsp[(n - 1) * 4 + 8]", |
+ "rsp[8 * num_arguments] " : "rsp[(num_arguments - 1) * 4 + 8]", |
+ "rsp[8 * (argc + 1)]" : "rsp[argc * 4 + 8] ", |
+ "rsp[kFastApiCallArguments * 8 + 8]" : "rsp[kFastApiCallArguments * 4 + 8] ", |
+ "rsp[8 * (n + 1)]" : "rsp[n * 4 + 8] ", |
+ "rsp[(argc + 1) * 8]" : "rsp[argc * 4 + 8] ", |
+ "rsp[(argc + 6) * 8] " : "rsp[(argc + 5) * 4 + 8]", |
+ "rsp[(argc + 7) * 8] " : "rsp[(argc + 6) * 4 + 8]", |
+ "rsp[(argc - n) * 8] " : "rsp[(argc - n - 1) * 4 + 8]", |
+} |
+ |
+def HandleComment(line): |
+ result = line |
+ return result |
+ ####### Temporarily disable the comment handling################## |
+ for comment in comment_replacements: |
+ if result.find(comment) != -1: |
+ result = result.replace(comment, comment_replacements[comment]) |
+ break |
+ |
+ return result |
+ |
+def ProcessLine(line, is_assembler, debug): |
+ if line.find("#include") != -1: |
+ result = line.replace("x64", "x32") |
+ else: |
+ result = line.replace("X64", "X32") |
+ if not is_assembler: |
+ (cont, result) = HandleAnnotations(result, debug) |
+ if cont: |
+ for key in operator_handlers: |
+ if result.find(key) != -1: |
+ handler = operator_handlers[key][1] |
+ result = handler(result, key) |
+ break |
+ |
+ return result |
+ |
+ |
+def ProcessLines(lines_in, lines_out, line_number, is_assembler, debug): |
+ line_in = lines_in[line_number] |
+ |
+ if line_in.find("#ifdef V8_TARGET_ARCH_X32") != -1: |
+ # Process codes inside #ifdef V8_TARGET_ARCH_X32 lines #endif |
+ # If debug, keep the #ifdef and #endif, otherwise remove them |
+ begin = line_number |
+ if debug: |
+ lines_out.append(line_in) |
+ |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ while (line_in.find("#endif")) == -1: |
+ lines_out.append(line_in) |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ |
+ if debug: |
+ lines_out.append(line_in) |
+ |
+ return line_number - begin + 1 |
+ elif line_in.find("#ifndef V8_TARGET_ARCH_X32") != -1: |
+ # Process codes inside #ifndef V8_TARGET_ARCH_X32 x64_lines #endif or |
+ # #ifndef V8_TARGET_ARCH_X32 x64_lines #else x32_lines #endif |
+ # If debug, keep all, otherwise remove #ifdef, x64_lines, #else and #endif |
+ begin = line_number |
+ if debug: |
+ lines_out.append(line_in) |
+ |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ while (line_in.find("#else")) == -1 and (line_in.find("#endif")) == -1: |
+ if debug: |
+ lines_out.append(line_in) |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ if (line_in.find("#else")) != -1: |
+ if debug: |
+ lines_out.append(line_in) |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ while (line_in.find("#endif")) == -1: |
+ lines_out.append(line_in) |
+ line_number += 1; |
+ line_in = lines_in[line_number] |
+ if debug: |
+ lines_out.append(line_in) |
+ |
+ return line_number - begin + 1 |
+ elif (line_in.find("rsp[") != -1 or line_in.find("rbp[") != -1) \ |
+ and line_in.find("//") !=-1: |
+ line_out = HandleComment(line_in) |
+ lines_out.append(line_out) |
+ return 1 |
+ else: |
+ line_out = ProcessLine(line_in, is_assembler, debug) |
+ lines_out.append(line_out) |
+ return 1 |
+ |
+def ProcessFile(name, debug): |
+ f_in = open(name, "r") |
+ lines_in = f_in.readlines() |
+ f_in.close() |
+ |
+# Replace x64 with x32 to form the name "../../src/x32/code-stubs-x32.[h|cc]" |
+# Create x32 folder if it does not exist |
+ out_filename = name.replace("x64", "x32") |
+ if not os.path.exists(os.path.dirname(out_filename)): |
+ os.makedirs(os.path.dirname(out_filename)) |
+ |
+# Process lines of the input file |
+ is_assembler = name.find("assembler-x64") == 14 |
+ lines_out = [] |
+ line_number = 0 |
+ total_lines = len(lines_in) |
+ while line_number < total_lines: |
+ line_number += ProcessLines(lines_in, lines_out, line_number, \ |
+ is_assembler, debug) |
+ |
+# Write generated contents into output file |
+ f_out = open(out_filename, "w") |
+ for item in lines_out: |
+ f_out.write(item) |
+ f_out.close() |
+ |
+ return 0 |
+ |
+def Main(): |
+ argc = len(sys.argv) |
+ if (argc == 1): |
+ print("Usage: %s {debug|release} output_file_names input_file_names" % \ |
+ sys.argv[0]) |
+ return 1 |
+ |
+ mode = sys.argv[1].lower() |
+ if mode != "debug" and mode != 'release': |
+ print("{debug|release} mode is expected") |
+ return 1 |
+ debug = True if mode == "debug" else False |
+ |
+ if (argc == 2): |
+ print("%s: No output file names and input file names" % sys.argv[0]) |
+ return 1 |
+ |
+ if (argc % 2 == 1): |
+ print("%s: The number of output files should be equal with input files" % \ |
+ sys.argv[0]) |
+ return 1 |
+ |
+ input_start = argc/2 + 1 |
+ x64_source_lists = sys.argv[input_start:] |
+ |
+ for item in x64_source_lists: |
+ ProcessFile(item, debug) |
+ |
+if __name__ == '__main__': |
+ sys.exit(Main()) |