Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(593)

Side by Side Diff: tools/gen-inlining-tests.py

Issue 2245263003: [turbofan] Tests for inlining calls, constructors, property access inside try..catch..finally. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@p6-base
Patch Set: Wrap long lines. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/mjsunit/compiler/inline-exception-2.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python3
2
3 # Copyright 2016 the V8 project authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7
8 from collections import namedtuple
9 import textwrap
10 import sys
11
12 SHARD_FILENAME_TEMPLATE = "test/mjsunit/compiler/inline-exception-{shard}.js"
13 # Generates 2 files. Found by trial and error.
14 SHARD_SIZE = 94
15
16 PREAMBLE = """
17
18 // Copyright 2016 the V8 project authors. All rights reserved.
19 // Use of this source code is governed by a BSD-style license that can be
20 // found in the LICENSE file.
21
22 // Flags: --allow-natives-syntax --turbo --no-always-opt
23
24 // This test file was generated by tools/gen-inlining-tests.py .
25
26 // Global variables
27 var deopt = undefined; // either true or false
28 var counter = 0;
29
30 function resetState() {
31 counter = 0;
32 }
33
34 function warmUp(f) {
35 try {
36 f();
37 } catch (ex) {
38 // ok
39 }
40 try {
41 f();
42 } catch (ex) {
43 // ok
44 }
45 }
46
47 function resetOptAndAssertResultEquals(expected, f) {
48 warmUp(f);
49 resetState();
50 // %DebugPrint(f);
51 eval("'dont optimize this function itself please, but do optimize f'");
52 %OptimizeFunctionOnNextCall(f);
53 assertEquals(expected, f());
54 }
55
56 function resetOptAndAssertThrowsWith(expected, f) {
57 warmUp(f);
58 resetState();
59 // %DebugPrint(f);
60 eval("'dont optimize this function itself please, but do optimize f'");
61 %OptimizeFunctionOnNextCall(f);
62 try {
63 var result = f();
64 fail("resetOptAndAssertThrowsWith",
65 "exception: " + expected,
66 "result: " + result);
67 } catch (ex) {
68 assertEquals(expected, ex);
69 }
70 }
71
72 function increaseAndReturn15() {
73 if (deopt) %DeoptimizeFunction(f);
74 counter++;
75 return 15;
76 }
77
78 function increaseAndThrow42() {
79 if (deopt) %DeoptimizeFunction(f);
80 counter++;
81 throw 42;
82 }
83
84 function returnOrThrow(doReturn) {
85 if (doReturn) {
86 return increaseAndReturn15();
87 } else {
88 return increaseAndThrow42();
89 }
90 }
91
92 // When passed either {increaseAndReturn15} or {increaseAndThrow42}, it acts
93 // as the other one.
94 function invertFunctionCall(f) {
95 var result;
96 try {
97 result = f();
98 } catch (ex) {
99 return ex - 27;
100 }
101 throw result + 27;
102 }
103
104 function increaseAndStore15Constructor() {
105 if (deopt) %DeoptimizeFunction(f);
106 ++counter;
107 this.x = 15;
108 }
109
110 function increaseAndThrow42Constructor() {
111 if (deopt) %DeoptimizeFunction(f);
112 ++counter;
113 this.x = 42;
114 throw this.x;
115 }
116
117 var magic = {};
118 Object.defineProperty(magic, 'prop', {
119 get: function () {
120 if (deopt) %DeoptimizeFunction(f);
121 return 15 + 0 * ++counter;
122 },
123
124 set: function(x) {
125 // argument should be 37
126 if (deopt) %DeoptimizeFunction(f);
127 counter -= 36 - x; // increments counter
128 throw 42;
129 }
130 })
131
132 // Generate type feedback.
133
134 assertEquals(15, (new increaseAndStore15Constructor()).x);
135 assertThrowsEquals(function() {
136 return (new increaseAndThrow42Constructor()).x;
137 },
138 42);
139
140 function runThisShard() {
141
142 """.strip()
143
144 def booltuples(n):
145 """booltuples(2) yields 4 tuples: (False, False), (False, True),
146 (True, False), (True, True)."""
147
148 assert isinstance(n, int)
149 if n <= 0:
150 yield ()
151 else:
152 for initial in booltuples(n-1):
153 yield initial + (False,)
154 yield initial + (True,)
155
156 FLAGLETTERS="4321trflcrltfrtld"
157
158 def fnname(flags):
159 assert len(FLAGLETTERS) == len(flags)
160
161 return "f_" + ''.join(
162 FLAGLETTERS[i] if b else '_'
163 for (i, b) in enumerate(flags))
164
165 NUM_TESTS_PRINTED = 0
166 NUM_TESTS_IN_SHARD = 0
167
168 def printtest(flags):
169 """Print a test case. Takes a couple of boolean flags, on which the
170 printed Javascript code depends."""
171
172 assert all(isinstance(flag, bool) for flag in flags)
173
174 # The alternative flags are in reverse order so that if we take all possible
175 # tuples, ordered lexicographically from false to true, we get first the
176 # default, then alternative 1, then 2, etc.
177 (
178 alternativeFn4, # use alternative #4 for returning/throwing.
179 alternativeFn3, # use alternative #3 for returning/throwing.
180 alternativeFn2, # use alternative #2 for returning/throwing.
181 alternativeFn1, # use alternative #1 for returning/throwing.
182 tryThrows, # in try block, call throwing function
183 tryReturns, # in try block, call returning function
184 tryFirstReturns, # in try block, returning goes before throwing
185 tryResultToLocal, # in try block, result goes to local variable
186 doCatch, # include catch block
187 catchReturns, # in catch block, return
188 catchWithLocal, # in catch block, modify or return the local variable
189 catchThrows, # in catch block, throw
190 doFinally, # include finally block
191 finallyReturns, # in finally block, return local variable
192 finallyThrows, # in finally block, throw
193 endReturnLocal, # at very end, return variable local
194 deopt, # deopt inside inlined function
195 ) = flags
196
197 # BASIC RULES
198
199 # Only one alternative can be applied at any time.
200 if alternativeFn1 + alternativeFn2 + alternativeFn3 + alternativeFn4 > 1:
201 return
202
203 # In try, return or throw, or both.
204 if not (tryReturns or tryThrows): return
205
206 # Either doCatch or doFinally.
207 if not doCatch and not doFinally: return
208
209 # Catch flags only make sense when catching
210 if not doCatch and (catchReturns or catchWithLocal or catchThrows):
211 return
212
213 # Finally flags only make sense when finallying
214 if not doFinally and (finallyReturns or finallyThrows):
215 return
216
217 # tryFirstReturns is only relevant when both tryReturns and tryThrows are
218 # true.
219 if tryFirstReturns and not (tryReturns and tryThrows): return
220
221 # From the try and finally block, we can return or throw, but not both.
222 if catchReturns and catchThrows: return
223 if finallyReturns and finallyThrows: return
224
225 # If at the end we return the local, we need to have touched it.
226 if endReturnLocal and not (tryResultToLocal or catchWithLocal): return
227
228 # PRUNING
229
230 anyAlternative = any([alternativeFn1, alternativeFn2, alternativeFn3,
231 alternativeFn4])
232 rareAlternative = any([alternativeFn1, alternativeFn3, alternativeFn4])
233
234 # If try returns and throws, then don't catchWithLocal, endReturnLocal, or
235 # deopt, or do any alternative.
236 if (tryReturns and tryThrows and
237 (catchWithLocal or endReturnLocal or deopt or anyAlternative)):
238 return
239 # We don't do any alternative if we do a finally.
240 if doFinally and anyAlternative: return
241 # We only use the local variable if we do alternative #2.
242 if ((tryResultToLocal or catchWithLocal or endReturnLocal) and
243 not alternativeFn2):
244 return
245 # We don't need to test deopting into a finally.
246 if doFinally and deopt: return
247
248
249
250 # Flag check succeeded.
251
252 trueFlagNames = [name for (name, value) in flags._asdict().items() if value]
253 flagsMsgLine = " // Variant flags: [{}]".format(', '.join(trueFlagNames))
254 write(textwrap.fill(flagsMsgLine, subsequent_indent=' // '))
255 write("")
256
257 if not anyAlternative:
258 fragments = {
259 'increaseAndReturn15': 'increaseAndReturn15()',
260 'increaseAndThrow42': 'increaseAndThrow42()',
261 }
262 elif alternativeFn1:
263 fragments = {
264 'increaseAndReturn15': 'returnOrThrow(true)',
265 'increaseAndThrow42': 'returnOrThrow(false)',
266 }
267 elif alternativeFn2:
268 fragments = {
269 'increaseAndReturn15': 'invertFunctionCall(increaseAndThrow42)',
270 'increaseAndThrow42': 'invertFunctionCall(increaseAndReturn15)',
271 }
272 elif alternativeFn3:
273 fragments = {
274 'increaseAndReturn15': '(new increaseAndStore15Constructor()).x',
275 'increaseAndThrow42': '(new increaseAndThrow42Constructor()).x',
276 }
277 else:
278 assert alternativeFn4
279 fragments = {
280 'increaseAndReturn15': 'magic.prop /* returns 15 */',
281 'increaseAndThrow42': '(magic.prop = 37 /* throws 42 */)',
282 }
283
284 # As we print code, we also maintain what the result should be. Variable
285 # {result} can be one of three things:
286 #
287 # - None, indicating returning JS null
288 # - ("return", n) with n an integer
289 # - ("throw", n), with n an integer
290
291 result = None
292 # We also maintain what the counter should be at the end.
293 # The counter is reset just before f is called.
294 counter = 0
295
296 write( " f = function {} () {{".format(fnname(flags)))
297 write( " var local = 3;")
298 write( " deopt = {};".format("true" if deopt else "false"))
299 local = 3
300 write( " try {")
301 write( " counter++;")
302 counter += 1
303 resultTo = "local +=" if tryResultToLocal else "return"
304 if tryReturns and not (tryThrows and not tryFirstReturns):
305 write( " {} {increaseAndReturn15};".format(resultTo, **fragments))
306 if result == None:
307 counter += 1
308 if tryResultToLocal:
309 local += 15
310 else:
311 result = ("return", 15)
312 if tryThrows:
313 write( " {} {increaseAndThrow42};".format(resultTo, **fragments))
314 if result == None:
315 counter += 1
316 result = ("throw", 42)
317 if tryReturns and tryThrows and not tryFirstReturns:
318 write( " {} {increaseAndReturn15};".format(resultTo, **fragments))
319 if result == None:
320 counter += 1
321 if tryResultToLocal:
322 local += 15
323 else:
324 result = ("return", 15)
325 write( " counter++;")
326 if result == None:
327 counter += 1
328
329 if doCatch:
330 write( " } catch (ex) {")
331 write( " counter++;")
332 if isinstance(result, tuple) and result[0] == 'throw':
333 counter += 1
334 if catchThrows:
335 write(" throw 2 + ex;")
336 if isinstance(result, tuple) and result[0] == "throw":
337 result = ('throw', 2 + result[1])
338 elif catchReturns and catchWithLocal:
339 write(" return 2 + local;")
340 if isinstance(result, tuple) and result[0] == "throw":
341 result = ('return', 2 + local)
342 elif catchReturns and not catchWithLocal:
343 write(" return 2 + ex;");
344 if isinstance(result, tuple) and result[0] == "throw":
345 result = ('return', 2 + result[1])
346 elif catchWithLocal:
347 write(" local += ex;");
348 if isinstance(result, tuple) and result[0] == "throw":
349 local += result[1]
350 result = None
351 counter += 1
352 else:
353 if isinstance(result, tuple) and result[0] == "throw":
354 result = None
355 counter += 1
356 write( " counter++;")
357
358 if doFinally:
359 write( " } finally {")
360 write( " counter++;")
361 counter += 1
362 if finallyThrows:
363 write(" throw 25;")
364 result = ('throw', 25)
365 elif finallyReturns:
366 write(" return 3 + local;")
367 result = ('return', 3 + local)
368 elif not finallyReturns and not finallyThrows:
369 write(" local += 2;")
370 local += 2
371 counter += 1
372 else: assert False # unreachable
373 write( " counter++;")
374
375 write( " }")
376 write( " counter++;")
377 if result == None:
378 counter += 1
379 if endReturnLocal:
380 write( " return 5 + local;")
381 if result == None:
382 result = ('return', 5 + local)
383 write( " }")
384
385 if result == None:
386 write( " resetOptAndAssertResultEquals(undefined, f);")
387 else:
388 tag, value = result
389 if tag == "return":
390 write( " resetOptAndAssertResultEquals({}, f);".format(value))
391 else:
392 assert tag == "throw"
393 write( " resetOptAndAssertThrowsWith({}, f);".format(value))
394
395 write( " assertEquals({}, counter);".format(counter))
396 write( "")
397
398 global NUM_TESTS_PRINTED, NUM_TESTS_IN_SHARD
399 NUM_TESTS_PRINTED += 1
400 NUM_TESTS_IN_SHARD += 1
401
402 FILE = None # to be initialised to an open file
403 SHARD_NUM = 1
404
405 def write(*args):
406 return print(*args, file=FILE)
407
408
409
410 def rotateshard():
411 global FILE, NUM_TESTS_IN_SHARD, SHARD_SIZE
412 if MODE != 'shard':
413 return
414 if FILE != None and NUM_TESTS_IN_SHARD < SHARD_SIZE:
415 return
416 if FILE != None:
417 finishshard()
418 assert FILE == None
419 FILE = open(SHARD_FILENAME_TEMPLATE.format(shard=SHARD_NUM), 'w')
420 write_shard_header()
421 NUM_TESTS_IN_SHARD = 0
422
423 def finishshard():
424 global FILE, SHARD_NUM, MODE
425 assert FILE
426 write_shard_footer()
427 if MODE == 'shard':
428 print("Wrote shard {}.".format(SHARD_NUM))
429 FILE.close()
430 FILE = None
431 SHARD_NUM += 1
432
433
434 def write_shard_header():
435 if MODE == 'shard':
436 write("// Shard {}.".format(SHARD_NUM))
437 write("")
438 write(PREAMBLE)
439 write("")
440
441 def write_shard_footer():
442 write("}")
443 write("%NeverOptimizeFunction(runThisShard);")
444 write("")
445 write("// {} tests in this shard.".format(NUM_TESTS_IN_SHARD))
446 write("// {} tests up to here.".format(NUM_TESTS_PRINTED))
447 write("")
448 write("runThisShard();")
449
450
451 flagtuple = namedtuple('flagtuple', (
452 "alternativeFn4",
453 "alternativeFn3",
454 "alternativeFn2",
455 "alternativeFn1",
456 "tryThrows",
457 "tryReturns",
458 "tryFirstReturns",
459 "tryResultToLocal",
460 "doCatch",
461 "catchReturns",
462 "catchWithLocal",
463 "catchThrows",
464 "doFinally",
465 "finallyReturns",
466 "finallyThrows",
467 "endReturnLocal",
468 "deopt"
469 ))
470
471 emptyflags = flagtuple(*((False,) * len(flagtuple._fields)))
472 f1 = emptyflags._replace(tryReturns=True, doCatch=True)
473
474 # You can test function printtest with f1.
475
476 allFlagCombinations = [
477 flagtuple(*bools)
478 for bools in booltuples(len(flagtuple._fields))
479 ]
480
481 if __name__ == '__main__':
482 global MODE
483 if sys.argv[1:] == []:
484 MODE = 'stdout'
485 print("// Printing all shards together to stdout.")
486 print("")
487 write_shard_header()
488 FILE = sys.stdout
489 elif sys.argv[1:] == ['--shard-and-overwrite']:
490 MODE = 'shard'
491 else:
492 print("Usage:")
493 print("")
494 print(" python {}".format(sys.argv[0]))
495 print(" print all tests to standard output")
496 print(" python {} --shard-and-overwrite".format(sys.argv[0]))
497 print(" print all tests to {}".format(SHARD_FILENAME_TEMPLATE))
498
499 print("")
500 print(sys.argv[1:])
501 print("")
502 sys.exit(1)
503
504 rotateshard()
505
506 for flags in allFlagCombinations:
507 printtest(flags)
508 rotateshard()
509
510 finishshard()
OLDNEW
« no previous file with comments | « test/mjsunit/compiler/inline-exception-2.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698