OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # | |
danno
2013/07/17 13:33:21
As discussed offline, this file shouldn't be added
| |
3 # Copyright 2012 the V8 project authors. All rights reserved. | |
4 # Redistribution and use in source and binary forms, with or without | |
5 # modification, are permitted provided that the following conditions are | |
6 # met: | |
7 # | |
8 # * Redistributions of source code must retain the above copyright | |
9 # notice, this list of conditions and the following disclaimer. | |
10 # * Redistributions in binary form must reproduce the above | |
11 # copyright notice, this list of conditions and the following | |
12 # disclaimer in the documentation and/or other materials provided | |
13 # with the distribution. | |
14 # * Neither the name of Google Inc. nor the names of its | |
15 # contributors may be used to endorse or promote products derived | |
16 # from this software without specific prior written permission. | |
17 # | |
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 import sys | |
31 import os | |
32 | |
33 # This script generates the x32 sources from annoated x64 codes. | |
34 # <Usage>: | |
35 # ./generate-x32-source.py {debug|release} output_file_names input_file_names | |
36 # | |
37 # The annotations include: | |
38 # __a (argument) : Replace (n + 1) * kPointerSize with 1 * kHWRegSize + | |
39 # n * kPointerSize and __a with __ or remove "__a ". | |
40 # The size of return address is kHWRegSize for X32, the current X64 codes | |
41 # assume return address size is kPointerSize, so we replace the argument | |
42 # access offset with the right value. | |
43 # | |
44 # __k (keep) : Keep the current line unchanged and replace __k with __ | |
45 # or remove "__k ". | |
46 # We need to use 64-bit instructions for X32 when: | |
47 # 1) Load/Store 64-bit value. | |
48 # 2) Load/Store double into heap number field | |
49 # 3) Use push/pop for return address and FP register | |
50 # 4) Get signed index register for SIB access | |
51 # | |
52 # __q (quad) : Replace kPointerSize with kHWRegSize and __q with __ | |
53 # or remove "__q ". | |
54 # We need to use quadword for X32 when: | |
55 # 1) Pass arguments to the C++ runtime, we need 8-byte in the stack | |
56 # according to X32 ABI (https://sites.google.com/site/x32abi/) | |
57 # 2) Access a stack slot when skipping return address or FP | |
58 # 3) Compute size of state in the deoptimization process as we store state | |
59 # as quadword in the stack | |
60 # | |
61 # __n : Replace RelocInfo::NONE64 with RelocInfo::NONE32. | |
62 # | |
63 # __s (quad, keep) : Combine __k and __q. It is used when storing a register | |
64 # to the runtime stack for RegExp. | |
65 # | |
66 # After handling the annotations, if not __k or __s, the rest of the line will | |
67 # be processed according to the operator_handlers (see below). | |
68 | |
69 argument_replacements = { | |
70 "1 * kPointerSize" : "1 * kHWRegSize", | |
71 "2 * kPointerSize" : "1 * kHWRegSize + 1 * kPointerSize", | |
72 "3 * kPointerSize" : "1 * kHWRegSize + 2 * kPointerSize", | |
73 "4 * kPointerSize" : "1 * kHWRegSize + 3 * kPointerSize", | |
74 "5 * kPointerSize" : "1 * kHWRegSize + 4 * kPointerSize", | |
75 "6 * kPointerSize" : "1 * kHWRegSize + 5 * kPointerSize", | |
76 "i * kPointerSize" : "1 * kHWRegSize + (i - 1) * kPointerSize", | |
77 "argc * kPointerSize" : "1 * kHWRegSize + (argc - 1) * kPointerSize", | |
78 "(argc - 0) * kPointerSize" : "1 * kHWRegSize + (argc - 1) * kPointerSize", | |
79 "(argc + 1) * kPointerSize" : "1 * kHWRegSize + argc * kPointerSize", | |
80 "(argc_ + 1) * kPointerSize" : "1 * kHWRegSize + argc_ * kPointerSize", | |
81 } | |
82 | |
83 def HandleArgument(line): | |
84 result = line | |
85 if result.find("times_pointer_size, 0)") != -1: | |
86 result = result.replace("times_pointer_size, 0)", \ | |
87 "times_pointer_size, kPointerSize)") | |
88 else: | |
89 for argument in argument_replacements: | |
90 if result.find(argument) != -1: | |
91 result = result.replace(argument, argument_replacements[argument]) | |
92 break | |
93 | |
94 return (True, result) | |
95 | |
96 def HandleKeep(line): | |
97 return (False, line) | |
98 | |
99 def HandleQuad(line): | |
100 result = line | |
101 result = result.replace("kPointerSize", "kHWRegSize") | |
102 return (True, result) | |
103 | |
104 def HandleNone64(line): | |
105 result = line | |
106 result = result.replace("RelocInfo::NONE64", "RelocInfo::NONE32") | |
107 return (True, result) | |
108 | |
109 def HandleQuadKeep(line): | |
110 (cont, result) = HandleQuad(line) | |
111 return HandleKeep(result) | |
112 | |
113 annotation_handlers = { | |
114 " __a" : [" ", HandleArgument], | |
115 " __k" : [" ", HandleKeep], | |
116 " __q" : [" ", HandleQuad], | |
117 " __n" : [" ", HandleNone64], | |
118 " __s" : [" ", HandleQuadKeep], | |
119 } | |
120 | |
121 def Replace(line, key): | |
122 return line.replace(key, operator_handlers[key][0]) | |
123 | |
124 def HandlePushPop(line, key): | |
125 if line.find("push(rbp)") == -1 and line.find("pop(rbp)") == -1: | |
126 return Replace(line, key) | |
127 else: | |
128 return line | |
129 | |
130 def HandleMovQ(line, key): | |
131 result = line | |
132 if result.find("xmm") == -1 and result.find("double_scratch") == -1 and \ | |
133 result.find("V8_UINT64_C") == -1 and result.find("V8_INT64_C") == -1: | |
134 result = Replace(result, key) | |
135 if result.find("kZapValue") != -1 and result.find("NONE64") != -1: | |
136 result = result.replace("int64_t", "int32_t") | |
137 result = result.replace("NONE64", "NONE32") | |
138 return result | |
139 | |
140 operator_handlers = { | |
141 "movq(" : ("movl(", HandleMovQ), | |
142 "push(" : ("Push(", HandlePushPop), | |
143 "pop(" : ("Pop(", HandlePushPop), | |
144 "push_imm32(" : ("Push_imm32(", Replace), | |
145 " cmovq(" : (" cmovl(", Replace), | |
146 " xchg(" : (" xchgl(", Replace), | |
147 " addq(" : (" addl(", Replace), | |
148 " sbbq(" : (" sbbl(", Replace), | |
149 " cmpq(" : (" cmpl(", Replace), | |
150 " and_(" : (" andl(", Replace), | |
151 " decq(" : (" decl(", Replace), | |
152 " cqo(" : (" cdq(", Replace), | |
153 " idivq(" : (" idivl(", Replace), | |
154 " imul(" : (" imull(", Replace), | |
155 " incq(" : (" incl(", Replace), | |
156 " lea(" : (" leal(", Replace), | |
157 " neg(" : (" negl(", Replace), | |
158 " not_(" : (" notl(", Replace), | |
159 " or_(" : (" orl(", Replace), | |
160 " rol(" : (" roll(", Replace), | |
161 " ror(" : (" rorl(", Replace), | |
162 " sar(" : (" sarl(", Replace), | |
163 " sar_cl(" : (" sarl_cl(", Replace), | |
164 " shl(" : (" shll(", Replace), | |
165 " shl_cl(" : (" shll_cl(", Replace), | |
166 " shr(" : (" shrl(", Replace), | |
167 " shr_cl(" : (" shrl_cl(", Replace), | |
168 " subq(" : (" subl(", Replace), | |
169 " testq(" : (" testl(", Replace), | |
170 " xor_(" : (" xorl(", Replace), | |
171 " movzxbq(" : (" movzxbl(", Replace), | |
172 " repmovsq(" : (" repmovsl(", Replace), | |
173 } | |
174 | |
175 def HandleAnnotations(line, debug): | |
176 cont = True | |
177 result = line | |
178 for annotation in annotation_handlers: | |
179 if result.find(annotation) != -1: | |
180 if result.find(annotation + " ") != -1: | |
181 if result.find("#define" + annotation + " __") != -1: | |
182 # Add a new line to keep debugging easier if debug | |
183 result = "\n" if debug else "" | |
184 annotation_handlers[annotation][0] = " __" | |
185 else: | |
186 (cont, result) = annotation_handlers[annotation][1](result) | |
187 if annotation_handlers[annotation][0] == " ": | |
188 result = result.replace(annotation + " ", \ | |
189 annotation_handlers[annotation][0]) | |
190 else: | |
191 result = result.replace(annotation, \ | |
192 annotation_handlers[annotation][0]) | |
193 else: | |
194 if result.find("#define") != -1 or result.find("#undef") != -1: | |
195 # Add a new line to keep debugging easier if debug | |
196 result = "\n" if debug else "" | |
197 annotation_handlers[annotation][0] = " " | |
198 break | |
199 | |
200 return (cont, result) | |
201 | |
202 comment_replacements = { | |
203 "rbp[24]" : "rbp[20]", | |
204 "rbp[32]" : "rbp[24]", | |
205 "rbp[-n-8]" : "rbp[-n-4]", | |
206 "rsp[16]" : "rsp[12]", | |
207 "rsp[24]" : "rsp[16]", | |
208 "rsp[32]" : "rsp[20]", | |
209 "rsp[40]" : "rsp[24]", | |
210 "rsp[48]" : "rsp[28]", | |
211 "rsp[56]" : "rsp[32]", | |
212 "rsp[argc * 8] " : "rsp[(argc - 1) * 4 + 8]", | |
213 "rsp[kFastApiCallArguments * 8] " : \ | |
214 "rsp[(kFastApiCallArguments - 1) * 4 + 8]", | |
215 "rsp[8 * argc] " : "rsp[(argc - 1) * 4 + 8]", | |
216 "rsp[8 * n] " : "rsp[(n - 1) * 4 + 8]", | |
217 "rsp[8 * num_arguments] " : "rsp[(num_arguments - 1) * 4 + 8]", | |
218 "rsp[8 * (argc + 1)]" : "rsp[argc * 4 + 8] ", | |
219 "rsp[kFastApiCallArguments * 8 + 8]" : "rsp[kFastApiCallArguments * 4 + 8] ", | |
220 "rsp[8 * (n + 1)]" : "rsp[n * 4 + 8] ", | |
221 "rsp[(argc + 1) * 8]" : "rsp[argc * 4 + 8] ", | |
222 "rsp[(argc + 6) * 8] " : "rsp[(argc + 5) * 4 + 8]", | |
223 "rsp[(argc + 7) * 8] " : "rsp[(argc + 6) * 4 + 8]", | |
224 "rsp[(argc - n) * 8] " : "rsp[(argc - n - 1) * 4 + 8]", | |
225 } | |
226 | |
227 def HandleComment(line): | |
228 result = line | |
229 return result | |
230 ####### Temporarily disable the comment handling################## | |
231 for comment in comment_replacements: | |
232 if result.find(comment) != -1: | |
233 result = result.replace(comment, comment_replacements[comment]) | |
234 break | |
235 | |
236 return result | |
237 | |
238 def ProcessLine(line, is_assembler, debug): | |
239 if line.find("#include") != -1: | |
240 result = line.replace("x64", "x32") | |
241 else: | |
242 result = line.replace("X64", "X32") | |
243 if not is_assembler: | |
244 (cont, result) = HandleAnnotations(result, debug) | |
245 if cont: | |
246 for key in operator_handlers: | |
247 if result.find(key) != -1: | |
248 handler = operator_handlers[key][1] | |
249 result = handler(result, key) | |
250 break | |
251 | |
252 return result | |
253 | |
254 | |
255 def ProcessLines(lines_in, lines_out, line_number, is_assembler, debug): | |
256 line_in = lines_in[line_number] | |
257 | |
258 if line_in.find("#ifdef V8_TARGET_ARCH_X32") != -1: | |
259 # Process codes inside #ifdef V8_TARGET_ARCH_X32 lines #endif | |
260 # If debug, keep the #ifdef and #endif, otherwise remove them | |
261 begin = line_number | |
262 if debug: | |
263 lines_out.append(line_in) | |
264 | |
265 line_number += 1; | |
266 line_in = lines_in[line_number] | |
267 while (line_in.find("#endif")) == -1: | |
268 lines_out.append(line_in) | |
269 line_number += 1; | |
270 line_in = lines_in[line_number] | |
271 | |
272 if debug: | |
273 lines_out.append(line_in) | |
274 | |
275 return line_number - begin + 1 | |
276 elif line_in.find("#ifndef V8_TARGET_ARCH_X32") != -1: | |
277 # Process codes inside #ifndef V8_TARGET_ARCH_X32 x64_lines #endif or | |
278 # #ifndef V8_TARGET_ARCH_X32 x64_lines #else x32_lines #endif | |
279 # If debug, keep all, otherwise remove #ifdef, x64_lines, #else and #endif | |
280 begin = line_number | |
281 if debug: | |
282 lines_out.append(line_in) | |
283 | |
284 line_number += 1; | |
285 line_in = lines_in[line_number] | |
286 while (line_in.find("#else")) == -1 and (line_in.find("#endif")) == -1: | |
287 if debug: | |
288 lines_out.append(line_in) | |
289 line_number += 1; | |
290 line_in = lines_in[line_number] | |
291 if (line_in.find("#else")) != -1: | |
292 if debug: | |
293 lines_out.append(line_in) | |
294 line_number += 1; | |
295 line_in = lines_in[line_number] | |
296 while (line_in.find("#endif")) == -1: | |
297 lines_out.append(line_in) | |
298 line_number += 1; | |
299 line_in = lines_in[line_number] | |
300 if debug: | |
301 lines_out.append(line_in) | |
302 | |
303 return line_number - begin + 1 | |
304 elif (line_in.find("rsp[") != -1 or line_in.find("rbp[") != -1) \ | |
305 and line_in.find("//") !=-1: | |
306 line_out = HandleComment(line_in) | |
307 lines_out.append(line_out) | |
308 return 1 | |
309 else: | |
310 line_out = ProcessLine(line_in, is_assembler, debug) | |
311 lines_out.append(line_out) | |
312 return 1 | |
313 | |
314 def ProcessFile(name, debug): | |
315 f_in = open(name, "r") | |
316 lines_in = f_in.readlines() | |
317 f_in.close() | |
318 | |
319 # Replace x64 with x32 to form the name "../../src/x32/code-stubs-x32.[h|cc]" | |
320 # Create x32 folder if it does not exist | |
321 out_filename = name.replace("x64", "x32") | |
322 if not os.path.exists(os.path.dirname(out_filename)): | |
323 os.makedirs(os.path.dirname(out_filename)) | |
324 | |
325 # Process lines of the input file | |
326 is_assembler = name.find("assembler-x64") == 14 | |
327 lines_out = [] | |
328 line_number = 0 | |
329 total_lines = len(lines_in) | |
330 while line_number < total_lines: | |
331 line_number += ProcessLines(lines_in, lines_out, line_number, \ | |
332 is_assembler, debug) | |
333 | |
334 # Write generated contents into output file | |
335 f_out = open(out_filename, "w") | |
336 for item in lines_out: | |
337 f_out.write(item) | |
338 f_out.close() | |
339 | |
340 return 0 | |
341 | |
342 def Main(): | |
343 argc = len(sys.argv) | |
344 if (argc == 1): | |
345 print("Usage: %s {debug|release} output_file_names input_file_names" % \ | |
346 sys.argv[0]) | |
347 return 1 | |
348 | |
349 mode = sys.argv[1].lower() | |
350 if mode != "debug" and mode != 'release': | |
351 print("{debug|release} mode is expected") | |
352 return 1 | |
353 debug = True if mode == "debug" else False | |
354 | |
355 if (argc == 2): | |
356 print("%s: No output file names and input file names" % sys.argv[0]) | |
357 return 1 | |
358 | |
359 if (argc % 2 == 1): | |
360 print("%s: The number of output files should be equal with input files" % \ | |
361 sys.argv[0]) | |
362 return 1 | |
363 | |
364 input_start = argc/2 + 1 | |
365 x64_source_lists = sys.argv[input_start:] | |
366 | |
367 for item in x64_source_lists: | |
368 ProcessFile(item, debug) | |
369 | |
370 if __name__ == '__main__': | |
371 sys.exit(Main()) | |
OLD | NEW |