OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python3 | |
2 | |
3 # Copyright 2016 the V8 project authors. All rights reserved. | |
Jarin
2016/08/10 12:02:52
Please replace with the short version of the copyr
bgeron
2016/08/10 14:37:27
Done.
| |
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 | |
31 from collections import namedtuple | |
32 import textwrap | |
33 | |
34 PREAMBLE = """ | |
35 | |
36 // Copyright 2016 the V8 project authors. All rights reserved. | |
37 // Redistribution and use in source and binary forms, with or without | |
38 // modification, are permitted provided that the following conditions are | |
39 // met: | |
40 // | |
41 // * Redistributions of source code must retain the above copyright | |
42 // notice, this list of conditions and the following disclaimer. | |
43 // * Redistributions in binary form must reproduce the above | |
44 // copyright notice, this list of conditions and the following | |
45 // disclaimer in the documentation and/or other materials provided | |
46 // with the distribution. | |
47 // * Neither the name of Google Inc. nor the names of its | |
48 // contributors may be used to endorse or promote products derived | |
49 // from this software without specific prior written permission. | |
50 // | |
51 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
52 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
53 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
54 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
55 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
56 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
57 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
58 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
59 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
60 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
61 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
62 | |
63 // Flags: --allow-natives-syntax --turbo | |
64 | |
65 // This test file was generated by tools/gen-inlining-tests.py . | |
66 | |
67 function assertOptResultEquals(expected, f) { | |
68 // f(); | |
69 // %DebugPrint(f); | |
70 eval("'dont optimize this function itself please, but do optimize f'"); | |
71 %OptimizeFunctionOnNextCall(f); | |
72 assertEquals(expected, f()); | |
73 } | |
74 | |
75 function assertOptThrowsWith(expected, f) { | |
76 // f(); | |
77 // %DebugPrint(f); | |
78 eval("'dont optimize this function itself please, but do optimize f'"); | |
79 %OptimizeFunctionOnNextCall(f); | |
80 try { | |
81 var result = f(); | |
82 fail("assertOptThrowsWith", "exception: " + expected, "result: " + result); | |
83 } catch (ex) { | |
84 assertEquals(expected, ex); | |
85 } | |
86 } | |
87 | |
88 var counter = 0; | |
89 | |
90 function increaseAndReturn15() { | |
91 counter++; | |
92 return 15; | |
93 } | |
94 | |
95 function increaseAndThrow42() { | |
96 counter++; | |
97 throw 42; | |
98 } | |
99 | |
100 function returnOrThrow(doReturn) { | |
101 if (doReturn) { | |
102 return increaseAndReturn15(); | |
103 } else { | |
104 return increaseAndThrow42(); | |
105 } | |
106 } | |
107 | |
108 // When passed either {increaseAndReturn15} or {increaseAndThrow42}, it acts | |
109 // as the other one. | |
110 function invertFunctionCall(f) { | |
111 var result; | |
112 try { | |
113 result = f(); | |
114 } catch (ex) { | |
115 return ex - 27; | |
116 } | |
117 throw result + 27; | |
118 } | |
119 | |
120 """.strip() | |
121 | |
122 # Assert Python 3; reboot to Python 3 if currently on Python 2 | |
123 import sys, os | |
124 if sys.version_info[0] == 2: | |
125 sys.stderr.write("Restarting script using Python 3.\n") | |
126 os.execl("/usr/bin/env", "env", "python3", __file__) | |
Jarin
2016/08/10 12:02:52
Would it be too hard to make this work with python
bgeron
2016/08/10 14:37:27
Easier than expected! Done.
| |
127 | |
128 def booltuples(n): | |
129 """booltuples(2) yields 4 tuples: (False, False), (False, True), | |
130 (True, False), (True, True).""" | |
131 | |
132 assert isinstance(n, int) | |
133 if n <= 0: | |
134 yield () | |
135 else: | |
136 for initial in booltuples(n-1): | |
137 yield initial + (False,) | |
138 yield initial + (True,) | |
139 | |
140 NUM_TESTS_PRINTED = 0 | |
141 | |
142 def printtest(flags): | |
143 """Print a test case. Takes a couple of boolean flags, on which the | |
144 printed Javascript code depends.""" | |
145 | |
146 assert all(isinstance(flag, bool) for flag in flags) | |
147 | |
148 ( | |
149 alternativeFn2, # use alternative #2 for returning/throwing. | |
150 alternativeFn1, # use alternative #1 for returning/throwing. | |
151 tryReturns, # in try block, call returning function | |
152 tryThrows, # in try block, call throwing function | |
153 tryFirstReturns, # in try block, returning goes before throwing | |
154 tryResultToLocal, # in try block, result goes to local variable | |
155 doCatch, # include catch block | |
156 catchReturns, # in catch block, return | |
157 catchWithLocal, # in catch block, modify or return the local variable | |
158 catchThrows, # in catch block, throw | |
159 doFinally, # include finally block | |
160 finallyReturns, # in finally block, return local variable | |
161 finallyThrows, # in finally block, throw | |
162 endReturnLocal, # at very end, return variable local | |
163 ) = flags | |
Jarin
2016/08/10 12:02:52
We would also like to test deoptimization. However
bgeron
2016/08/10 14:37:27
Ack. Let's look at this together when you're back.
| |
164 | |
165 # Some pruning | |
166 | |
167 if alternativeFn1 and alternativeFn2: return | |
168 | |
169 # In try, return or throw, or both. | |
170 if not (tryReturns or tryThrows): return | |
171 | |
172 # Either doCatch or doFinally. | |
173 if not doCatch and not doFinally: return | |
174 | |
175 # Catch flags only make sense when catching | |
176 if not doCatch and (catchReturns or catchWithLocal or catchThrows): | |
177 return | |
178 | |
179 # Finally flags only make sense when finallying | |
180 if not doFinally and (finallyReturns or finallyThrows): | |
181 return | |
182 | |
183 # tryFirstReturns is only relevant when both tryReturns and tryThrows are true . | |
184 if tryFirstReturns and not (tryReturns and tryThrows): return | |
185 | |
186 # From the try and finally block, we can return or throw, but not both. | |
187 if catchReturns and catchThrows: return | |
188 if finallyReturns and finallyThrows: return | |
189 | |
190 # If we use an alternative function, then we don't also need to test both | |
191 # tryReturns and tryThrows at the same time. | |
192 if (alternativeFn1 or alternativeFn2) and tryReturns and tryThrows: return | |
193 | |
194 # Flag check succeeded. | |
195 global NUM_TESTS_PRINTED | |
196 NUM_TESTS_PRINTED += 1 | |
197 | |
198 trueFlagNames = [name for (name, value) in flags._asdict().items() if value] | |
199 flagsMsgLine = "// Variant flags: [{}]".format(', '.join(trueFlagNames)) | |
200 print(textwrap.fill(flagsMsgLine, subsequent_indent='// ')) | |
201 print() | |
202 | |
203 if not alternativeFn1 and not alternativeFn2: | |
204 fragments = { | |
205 'increaseAndReturn15': 'increaseAndReturn15()', | |
206 'increaseAndThrow42': 'increaseAndThrow42()' | |
207 } | |
208 elif alternativeFn1: | |
209 fragments = { | |
210 'increaseAndReturn15': 'returnOrThrow(true)', | |
211 'increaseAndThrow42': 'returnOrThrow(false)' | |
212 } | |
213 else: | |
214 assert alternativeFn2 | |
215 fragments = { | |
216 'increaseAndReturn15': 'invertFunctionCall(increaseAndThrow42)', | |
217 'increaseAndThrow42': 'invertFunctionCall(increaseAndReturn15)' | |
218 } | |
219 | |
220 # As we print code, we also maintain what the result should be. Variable | |
221 # {result} can be one of three things: | |
222 # | |
223 # - None, indicating returning JS null | |
224 # - ("return", n) with n an integer | |
225 # - ("throw", n), with n an integer | |
226 | |
227 result = None | |
228 # We also maintain what the counter should be at the end. | |
229 counter = 0 | |
230 | |
231 print( "counter = 0;") | |
232 print( "var f = function() {") | |
233 print( " var local = 3;") | |
234 local = 3 | |
235 print( " try {") | |
236 print( " counter++;") | |
237 counter += 1 | |
238 resultGoesTo = "local +=" if tryResultToLocal else "return" | |
239 if tryReturns and not (tryThrows and not tryFirstReturns): | |
240 print( " {} {increaseAndReturn15};".format(resultGoesTo, **fragments)) | |
241 if result == None: | |
242 counter += 1 | |
243 if tryResultToLocal: | |
244 local += 15 | |
245 else: | |
246 result = ("return", 15) | |
247 if tryThrows: | |
248 print( " {} {increaseAndThrow42};".format(resultGoesTo, **fragments)) | |
249 if result == None: | |
250 counter += 1 | |
251 result = ("throw", 42) | |
252 if tryReturns and tryThrows and not tryFirstReturns: | |
253 print( " {} {increaseAndReturn15};".format(resultGoesTo, **fragments)) | |
254 if result == None: | |
255 counter += 1 | |
256 if tryResultToLocal: | |
257 local += 15 | |
258 else: | |
259 result = ("return", 15) | |
260 print( " counter++;") | |
261 if result == None: | |
262 counter += 1 | |
263 | |
264 if doCatch: | |
265 print( " } catch (ex) {") | |
266 print( " counter++;") | |
267 if isinstance(result, tuple) and result[0] == 'throw': | |
268 counter += 1 | |
269 if catchThrows: | |
270 print(" throw 2 + ex;") | |
271 if isinstance(result, tuple) and result[0] == "throw": | |
272 result = ('throw', 2 + result[1]) | |
273 elif catchReturns and catchWithLocal: | |
274 print(" return 2 + local;") | |
275 if isinstance(result, tuple) and result[0] == "throw": | |
276 result = ('return', 2 + local) | |
277 elif catchReturns and not catchWithLocal: | |
278 print(" return 2 + ex;"); | |
279 if isinstance(result, tuple) and result[0] == "throw": | |
280 result = ('return', 2 + result[1]) | |
281 elif catchWithLocal: | |
282 print(" local += ex;"); | |
283 if isinstance(result, tuple) and result[0] == "throw": | |
284 local += result[1] | |
285 result = None | |
286 counter += 1 | |
287 else: | |
288 if isinstance(result, tuple) and result[0] == "throw": | |
289 result = None | |
290 counter += 1 | |
291 print( " counter++;") | |
292 | |
293 if doFinally: | |
294 print( " } finally {") | |
295 print( " counter++;") | |
296 counter += 1 | |
297 if finallyThrows: | |
298 print(" throw 25;") | |
299 result = ('throw', 25) | |
300 elif finallyReturns: | |
301 print(" return 3 + local;") | |
302 result = ('return', 3 + local) | |
303 elif not finallyReturns and not finallyThrows: | |
304 print(" local += 2;") | |
305 local += 2 | |
306 counter += 1 | |
307 else: assert False # unreachable | |
308 print( " counter++;") | |
309 | |
310 print( " }") | |
311 print( " counter++;") | |
312 if result == None: | |
313 counter += 1 | |
314 if endReturnLocal: | |
315 print( " return 5 + local;") | |
316 if result == None: | |
317 result = ('return', 5 + local) | |
318 print( "}") | |
319 | |
320 if result == None: | |
321 print( "assertOptResultEquals(undefined, f);") | |
322 else: | |
323 tag, value = result | |
324 if tag == "return": | |
325 print( "assertOptResultEquals({}, f);".format(value)) | |
326 else: | |
327 assert tag == "throw" | |
328 print( "assertOptThrowsWith({}, f);".format(value)) | |
329 | |
330 print( "assertEquals({}, counter);".format(counter)) | |
331 print( ) | |
332 | |
333 | |
334 flagtuple = namedtuple('flagtuple', ( | |
335 "alternativeFn2", | |
336 "alternativeFn1", | |
337 "tryReturns", | |
338 "tryThrows", | |
339 "tryFirstReturns", | |
340 "tryResultToLocal", | |
341 "doCatch", | |
342 "catchReturns", | |
343 "catchWithLocal", | |
344 "catchThrows", | |
345 "doFinally", | |
346 "finallyReturns", | |
347 "finallyThrows", | |
348 "endReturnLocal", | |
349 )) | |
350 | |
351 emptyflags = flagtuple(*((False,) * len(flagtuple._fields))) | |
352 f1 = emptyflags._replace(tryReturns=True, doCatch=True) | |
353 | |
354 # You can test function printtest with f1. | |
355 | |
356 allFlagCombinations = [flagtuple(*bools) for bools in booltuples(len(flagtuple._ fields))] | |
357 | |
358 if __name__ == '__main__': | |
359 print(PREAMBLE) | |
360 print() | |
361 for flags in allFlagCombinations: | |
362 printtest(flags) | |
363 | |
364 print("// Total: {} tests.".format(NUM_TESTS_PRINTED)) | |
OLD | NEW |