OLD | NEW |
1 #!/usr/bin/env python3 | 1 #!/usr/bin/env python3 |
2 | 2 |
3 # Copyright 2016 the V8 project authors. All rights reserved. | 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 | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 | 7 |
8 from collections import namedtuple | 8 from collections import namedtuple |
9 import textwrap | 9 import textwrap |
10 import sys | 10 import sys |
11 | 11 |
12 SHARD_FILENAME_TEMPLATE = "test/mjsunit/compiler/inline-exception-{shard}.js" | 12 SHARD_FILENAME_TEMPLATE = "test/mjsunit/compiler/inline-exception-{shard}.js" |
13 # Generates 2 files. Found by trial and error. | 13 # Generates 2 files. Found by trial and error. |
14 SHARD_SIZE = 94 | 14 SHARD_SIZE = 97 |
15 | 15 |
16 PREAMBLE = """ | 16 PREAMBLE = """ |
17 | 17 |
18 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 19 // Use of this source code is governed by a BSD-style license that can be |
20 // found in the LICENSE file. | 20 // found in the LICENSE file. |
21 | 21 |
22 // Flags: --allow-natives-syntax --turbo --no-always-opt | 22 // Flags: --allow-natives-syntax --turbo --no-always-opt |
23 | 23 |
24 // This test file was generated by tools/gen-inlining-tests.py . | 24 // This test file was generated by tools/gen-inlining-tests.py . |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 counter++; | 74 counter++; |
75 return 15; | 75 return 15; |
76 } | 76 } |
77 | 77 |
78 function increaseAndThrow42() { | 78 function increaseAndThrow42() { |
79 if (deopt) %DeoptimizeFunction(f); | 79 if (deopt) %DeoptimizeFunction(f); |
80 counter++; | 80 counter++; |
81 throw 42; | 81 throw 42; |
82 } | 82 } |
83 | 83 |
| 84 function increaseAndReturn15_noopt_inner() { |
| 85 if (deopt) %DeoptimizeFunction(f); |
| 86 counter++; |
| 87 return 15; |
| 88 } |
| 89 |
| 90 %NeverOptimizeFunction(increaseAndReturn15_noopt_inner); |
| 91 |
| 92 function increaseAndThrow42_noopt_inner() { |
| 93 if (deopt) %DeoptimizeFunction(f); |
| 94 counter++; |
| 95 throw 42; |
| 96 } |
| 97 |
| 98 %NeverOptimizeFunction(increaseAndThrow42_noopt_inner); |
| 99 |
| 100 // Alternative 1 |
| 101 |
84 function returnOrThrow(doReturn) { | 102 function returnOrThrow(doReturn) { |
85 if (doReturn) { | 103 if (doReturn) { |
86 return increaseAndReturn15(); | 104 return increaseAndReturn15(); |
87 } else { | 105 } else { |
88 return increaseAndThrow42(); | 106 return increaseAndThrow42(); |
89 } | 107 } |
90 } | 108 } |
91 | 109 |
| 110 // Alternative 2 |
| 111 |
| 112 function increaseAndReturn15_noopt_outer() { |
| 113 return increaseAndReturn15_noopt_inner(); |
| 114 } |
| 115 |
| 116 function increaseAndThrow42_noopt_outer() { |
| 117 return increaseAndThrow42_noopt_inner(); |
| 118 } |
| 119 |
| 120 // Alternative 3. |
92 // When passed either {increaseAndReturn15} or {increaseAndThrow42}, it acts | 121 // When passed either {increaseAndReturn15} or {increaseAndThrow42}, it acts |
93 // as the other one. | 122 // as the other one. |
94 function invertFunctionCall(f) { | 123 function invertFunctionCall(f) { |
95 var result; | 124 var result; |
96 try { | 125 try { |
97 result = f(); | 126 result = f(); |
98 } catch (ex) { | 127 } catch (ex) { |
99 return ex - 27; | 128 return ex - 27; |
100 } | 129 } |
101 throw result + 27; | 130 throw result + 27; |
102 } | 131 } |
103 | 132 |
| 133 // Alternative 4: constructor |
104 function increaseAndStore15Constructor() { | 134 function increaseAndStore15Constructor() { |
105 if (deopt) %DeoptimizeFunction(f); | 135 if (deopt) %DeoptimizeFunction(f); |
106 ++counter; | 136 ++counter; |
107 this.x = 15; | 137 this.x = 15; |
108 } | 138 } |
109 | 139 |
110 function increaseAndThrow42Constructor() { | 140 function increaseAndThrow42Constructor() { |
111 if (deopt) %DeoptimizeFunction(f); | 141 if (deopt) %DeoptimizeFunction(f); |
112 ++counter; | 142 ++counter; |
113 this.x = 42; | 143 this.x = 42; |
114 throw this.x; | 144 throw this.x; |
115 } | 145 } |
116 | 146 |
| 147 // Alternative 5: property |
117 var magic = {}; | 148 var magic = {}; |
118 Object.defineProperty(magic, 'prop', { | 149 Object.defineProperty(magic, 'prop', { |
119 get: function () { | 150 get: function () { |
120 if (deopt) %DeoptimizeFunction(f); | 151 if (deopt) %DeoptimizeFunction(f); |
121 return 15 + 0 * ++counter; | 152 return 15 + 0 * ++counter; |
122 }, | 153 }, |
123 | 154 |
124 set: function(x) { | 155 set: function(x) { |
125 // argument should be 37 | 156 // argument should be 37 |
126 if (deopt) %DeoptimizeFunction(f); | 157 if (deopt) %DeoptimizeFunction(f); |
127 counter -= 36 - x; // increments counter | 158 counter -= 36 - x; // increments counter |
128 throw 42; | 159 throw 42; |
129 } | 160 } |
130 }) | 161 }) |
131 | 162 |
132 // Generate type feedback. | 163 // Generate type feedback. |
133 | 164 |
| 165 assertEquals(15, increaseAndReturn15_noopt_outer()); |
134 assertEquals(15, (new increaseAndStore15Constructor()).x); | 166 assertEquals(15, (new increaseAndStore15Constructor()).x); |
135 assertThrowsEquals(function() { | 167 assertThrowsEquals(function() { |
136 return (new increaseAndThrow42Constructor()).x; | 168 return (new increaseAndThrow42Constructor()).x; |
137 }, | 169 }, |
138 42); | 170 42); |
139 | 171 |
140 function runThisShard() { | 172 function runThisShard() { |
141 | 173 |
142 """.strip() | 174 """.strip() |
143 | 175 |
144 def booltuples(n): | 176 def booltuples(n): |
145 """booltuples(2) yields 4 tuples: (False, False), (False, True), | 177 """booltuples(2) yields 4 tuples: (False, False), (False, True), |
146 (True, False), (True, True).""" | 178 (True, False), (True, True).""" |
147 | 179 |
148 assert isinstance(n, int) | 180 assert isinstance(n, int) |
149 if n <= 0: | 181 if n <= 0: |
150 yield () | 182 yield () |
151 else: | 183 else: |
152 for initial in booltuples(n-1): | 184 for initial in booltuples(n-1): |
153 yield initial + (False,) | 185 yield initial + (False,) |
154 yield initial + (True,) | 186 yield initial + (True,) |
155 | 187 |
156 FLAGLETTERS="4321trflcrltfrtld" | |
157 | |
158 def fnname(flags): | 188 def fnname(flags): |
159 assert len(FLAGLETTERS) == len(flags) | 189 assert len(FLAGLETTERS) == len(flags) |
160 | 190 |
161 return "f_" + ''.join( | 191 return "f_" + ''.join( |
162 FLAGLETTERS[i] if b else '_' | 192 FLAGLETTERS[i] if b else '_' |
163 for (i, b) in enumerate(flags)) | 193 for (i, b) in enumerate(flags)) |
164 | 194 |
165 NUM_TESTS_PRINTED = 0 | 195 NUM_TESTS_PRINTED = 0 |
166 NUM_TESTS_IN_SHARD = 0 | 196 NUM_TESTS_IN_SHARD = 0 |
167 | 197 |
168 def printtest(flags): | 198 def printtest(flags): |
169 """Print a test case. Takes a couple of boolean flags, on which the | 199 """Print a test case. Takes a couple of boolean flags, on which the |
170 printed Javascript code depends.""" | 200 printed Javascript code depends.""" |
171 | 201 |
172 assert all(isinstance(flag, bool) for flag in flags) | 202 assert all(isinstance(flag, bool) for flag in flags) |
173 | 203 |
174 # The alternative flags are in reverse order so that if we take all possible | 204 # 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 | 205 # tuples, ordered lexicographically from false to true, we get first the |
176 # default, then alternative 1, then 2, etc. | 206 # default, then alternative 1, then 2, etc. |
177 ( | 207 ( |
178 alternativeFn4, # use alternative #4 for returning/throwing. | 208 alternativeFn5, # use alternative #5 for returning/throwing: |
179 alternativeFn3, # use alternative #3 for returning/throwing. | 209 # return/throw using property |
180 alternativeFn2, # use alternative #2 for returning/throwing. | 210 alternativeFn4, # use alternative #4 for returning/throwing: |
181 alternativeFn1, # use alternative #1 for returning/throwing. | 211 # return/throw using constructor |
| 212 alternativeFn3, # use alternative #3 for returning/throwing: |
| 213 # return/throw indirectly, based on function argument |
| 214 alternativeFn2, # use alternative #2 for returning/throwing: |
| 215 # return/throw indirectly in unoptimized code, |
| 216 # no branching |
| 217 alternativeFn1, # use alternative #1 for returning/throwing: |
| 218 # return/throw indirectly, based on boolean arg |
182 tryThrows, # in try block, call throwing function | 219 tryThrows, # in try block, call throwing function |
183 tryReturns, # in try block, call returning function | 220 tryReturns, # in try block, call returning function |
184 tryFirstReturns, # in try block, returning goes before throwing | 221 tryFirstReturns, # in try block, returning goes before throwing |
185 tryResultToLocal, # in try block, result goes to local variable | 222 tryResultToLocal, # in try block, result goes to local variable |
186 doCatch, # include catch block | 223 doCatch, # include catch block |
187 catchReturns, # in catch block, return | 224 catchReturns, # in catch block, return |
188 catchWithLocal, # in catch block, modify or return the local variable | 225 catchWithLocal, # in catch block, modify or return the local variable |
189 catchThrows, # in catch block, throw | 226 catchThrows, # in catch block, throw |
190 doFinally, # include finally block | 227 doFinally, # include finally block |
191 finallyReturns, # in finally block, return local variable | 228 finallyReturns, # in finally block, return local variable |
192 finallyThrows, # in finally block, throw | 229 finallyThrows, # in finally block, throw |
193 endReturnLocal, # at very end, return variable local | 230 endReturnLocal, # at very end, return variable local |
194 deopt, # deopt inside inlined function | 231 deopt, # deopt inside inlined function |
195 ) = flags | 232 ) = flags |
196 | 233 |
197 # BASIC RULES | 234 # BASIC RULES |
198 | 235 |
199 # Only one alternative can be applied at any time. | 236 # Only one alternative can be applied at any time. |
200 if alternativeFn1 + alternativeFn2 + alternativeFn3 + alternativeFn4 > 1: | 237 if (alternativeFn1 + alternativeFn2 + alternativeFn3 + alternativeFn4 |
| 238 + alternativeFn5 > 1): |
201 return | 239 return |
202 | 240 |
203 # In try, return or throw, or both. | 241 # In try, return or throw, or both. |
204 if not (tryReturns or tryThrows): return | 242 if not (tryReturns or tryThrows): return |
205 | 243 |
206 # Either doCatch or doFinally. | 244 # Either doCatch or doFinally. |
207 if not doCatch and not doFinally: return | 245 if not doCatch and not doFinally: return |
208 | 246 |
209 # Catch flags only make sense when catching | 247 # Catch flags only make sense when catching |
210 if not doCatch and (catchReturns or catchWithLocal or catchThrows): | 248 if not doCatch and (catchReturns or catchWithLocal or catchThrows): |
(...skipping 10 matching lines...) Expand all Loading... |
221 # From the try and finally block, we can return or throw, but not both. | 259 # From the try and finally block, we can return or throw, but not both. |
222 if catchReturns and catchThrows: return | 260 if catchReturns and catchThrows: return |
223 if finallyReturns and finallyThrows: return | 261 if finallyReturns and finallyThrows: return |
224 | 262 |
225 # If at the end we return the local, we need to have touched it. | 263 # If at the end we return the local, we need to have touched it. |
226 if endReturnLocal and not (tryResultToLocal or catchWithLocal): return | 264 if endReturnLocal and not (tryResultToLocal or catchWithLocal): return |
227 | 265 |
228 # PRUNING | 266 # PRUNING |
229 | 267 |
230 anyAlternative = any([alternativeFn1, alternativeFn2, alternativeFn3, | 268 anyAlternative = any([alternativeFn1, alternativeFn2, alternativeFn3, |
231 alternativeFn4]) | 269 alternativeFn4, alternativeFn5]) |
232 rareAlternative = any([alternativeFn1, alternativeFn3, alternativeFn4]) | 270 specificAlternative = any([alternativeFn2, alternativeFn3]) |
| 271 rareAlternative = not specificAlternative |
233 | 272 |
234 # If try returns and throws, then don't catchWithLocal, endReturnLocal, or | 273 # If try returns and throws, then don't catchWithLocal, endReturnLocal, or |
235 # deopt, or do any alternative. | 274 # deopt, or do any alternative. |
236 if (tryReturns and tryThrows and | 275 if (tryReturns and tryThrows and |
237 (catchWithLocal or endReturnLocal or deopt or anyAlternative)): | 276 (catchWithLocal or endReturnLocal or deopt or anyAlternative)): |
238 return | 277 return |
239 # We don't do any alternative if we do a finally. | 278 # We don't do any alternative if we do a finally. |
240 if doFinally and anyAlternative: return | 279 if doFinally and anyAlternative: return |
241 # We only use the local variable if we do alternative #2. | 280 # We only use the local variable if we do alternative #2 or #3. |
242 if ((tryResultToLocal or catchWithLocal or endReturnLocal) and | 281 if ((tryResultToLocal or catchWithLocal or endReturnLocal) and |
243 not alternativeFn2): | 282 not specificAlternative): |
244 return | 283 return |
245 # We don't need to test deopting into a finally. | 284 # We don't need to test deopting into a finally. |
246 if doFinally and deopt: return | 285 if doFinally and deopt: return |
247 | 286 |
| 287 # We're only interested in alternative #2 if we have endReturnLocal, no |
| 288 # catchReturns, and no catchThrows, and deopt. |
| 289 if (alternativeFn2 and |
| 290 (not endReturnLocal or catchReturns or catchThrows or not deopt)): |
| 291 return |
248 | 292 |
249 | 293 |
250 # Flag check succeeded. | 294 # Flag check succeeded. |
251 | 295 |
252 trueFlagNames = [name for (name, value) in flags._asdict().items() if value] | 296 trueFlagNames = [name for (name, value) in flags._asdict().items() if value] |
253 flagsMsgLine = " // Variant flags: [{}]".format(', '.join(trueFlagNames)) | 297 flagsMsgLine = " // Variant flags: [{}]".format(', '.join(trueFlagNames)) |
254 write(textwrap.fill(flagsMsgLine, subsequent_indent=' // ')) | 298 write(textwrap.fill(flagsMsgLine, subsequent_indent=' // ')) |
255 write("") | 299 write("") |
256 | 300 |
257 if not anyAlternative: | 301 if not anyAlternative: |
258 fragments = { | 302 fragments = { |
259 'increaseAndReturn15': 'increaseAndReturn15()', | 303 'increaseAndReturn15': 'increaseAndReturn15()', |
260 'increaseAndThrow42': 'increaseAndThrow42()', | 304 'increaseAndThrow42': 'increaseAndThrow42()', |
261 } | 305 } |
262 elif alternativeFn1: | 306 elif alternativeFn1: |
263 fragments = { | 307 fragments = { |
264 'increaseAndReturn15': 'returnOrThrow(true)', | 308 'increaseAndReturn15': 'returnOrThrow(true)', |
265 'increaseAndThrow42': 'returnOrThrow(false)', | 309 'increaseAndThrow42': 'returnOrThrow(false)', |
266 } | 310 } |
267 elif alternativeFn2: | 311 elif alternativeFn2: |
268 fragments = { | 312 fragments = { |
| 313 'increaseAndReturn15': 'increaseAndReturn15_noopt_outer()', |
| 314 'increaseAndThrow42': 'increaseAndThrow42_noopt_outer()', |
| 315 } |
| 316 elif alternativeFn3: |
| 317 fragments = { |
269 'increaseAndReturn15': 'invertFunctionCall(increaseAndThrow42)', | 318 'increaseAndReturn15': 'invertFunctionCall(increaseAndThrow42)', |
270 'increaseAndThrow42': 'invertFunctionCall(increaseAndReturn15)', | 319 'increaseAndThrow42': 'invertFunctionCall(increaseAndReturn15)', |
271 } | 320 } |
272 elif alternativeFn3: | 321 elif alternativeFn4: |
273 fragments = { | 322 fragments = { |
274 'increaseAndReturn15': '(new increaseAndStore15Constructor()).x', | 323 'increaseAndReturn15': '(new increaseAndStore15Constructor()).x', |
275 'increaseAndThrow42': '(new increaseAndThrow42Constructor()).x', | 324 'increaseAndThrow42': '(new increaseAndThrow42Constructor()).x', |
276 } | 325 } |
277 else: | 326 else: |
278 assert alternativeFn4 | 327 assert alternativeFn5 |
279 fragments = { | 328 fragments = { |
280 'increaseAndReturn15': 'magic.prop /* returns 15 */', | 329 'increaseAndReturn15': 'magic.prop /* returns 15 */', |
281 'increaseAndThrow42': '(magic.prop = 37 /* throws 42 */)', | 330 'increaseAndThrow42': '(magic.prop = 37 /* throws 42 */)', |
282 } | 331 } |
283 | 332 |
284 # As we print code, we also maintain what the result should be. Variable | 333 # As we print code, we also maintain what the result should be. Variable |
285 # {result} can be one of three things: | 334 # {result} can be one of three things: |
286 # | 335 # |
287 # - None, indicating returning JS null | 336 # - None, indicating returning JS null |
288 # - ("return", n) with n an integer | 337 # - ("return", n) with n an integer |
289 # - ("throw", n), with n an integer | 338 # - ("throw", n), with n an integer |
290 | 339 |
291 result = None | 340 result = None |
292 # We also maintain what the counter should be at the end. | 341 # We also maintain what the counter should be at the end. |
293 # The counter is reset just before f is called. | 342 # The counter is reset just before f is called. |
294 counter = 0 | 343 counter = 0 |
295 | 344 |
296 write( " f = function {} () {{".format(fnname(flags))) | 345 write( " f = function {} () {{".format(fnname(flags))) |
297 write( " var local = 3;") | 346 write( " var local = 888;") |
298 write( " deopt = {};".format("true" if deopt else "false")) | 347 write( " deopt = {};".format("true" if deopt else "false")) |
299 local = 3 | 348 local = 888 |
300 write( " try {") | 349 write( " try {") |
301 write( " counter++;") | 350 write( " counter++;") |
302 counter += 1 | 351 counter += 1 |
303 resultTo = "local +=" if tryResultToLocal else "return" | 352 resultTo = "local +=" if tryResultToLocal else "return" |
304 if tryReturns and not (tryThrows and not tryFirstReturns): | 353 if tryReturns and not (tryThrows and not tryFirstReturns): |
305 write( " {} {increaseAndReturn15};".format(resultTo, **fragments)) | 354 write( " {} 4 + {increaseAndReturn15};".format(resultTo, **fragments)) |
306 if result == None: | 355 if result == None: |
307 counter += 1 | 356 counter += 1 |
308 if tryResultToLocal: | 357 if tryResultToLocal: |
309 local += 15 | 358 local += 19 |
310 else: | 359 else: |
311 result = ("return", 15) | 360 result = ("return", 19) |
312 if tryThrows: | 361 if tryThrows: |
313 write( " {} {increaseAndThrow42};".format(resultTo, **fragments)) | 362 write( " {} 4 + {increaseAndThrow42};".format(resultTo, **fragments)) |
314 if result == None: | 363 if result == None: |
315 counter += 1 | 364 counter += 1 |
316 result = ("throw", 42) | 365 result = ("throw", 42) |
317 if tryReturns and tryThrows and not tryFirstReturns: | 366 if tryReturns and tryThrows and not tryFirstReturns: |
318 write( " {} {increaseAndReturn15};".format(resultTo, **fragments)) | 367 write( " {} 4 + {increaseAndReturn15};".format(resultTo, **fragments)) |
319 if result == None: | 368 if result == None: |
320 counter += 1 | 369 counter += 1 |
321 if tryResultToLocal: | 370 if tryResultToLocal: |
322 local += 15 | 371 local += 19 |
323 else: | 372 else: |
324 result = ("return", 15) | 373 result = ("return", 19) |
325 write( " counter++;") | 374 write( " counter++;") |
326 if result == None: | 375 if result == None: |
327 counter += 1 | 376 counter += 1 |
328 | 377 |
329 if doCatch: | 378 if doCatch: |
330 write( " } catch (ex) {") | 379 write( " } catch (ex) {") |
331 write( " counter++;") | 380 write( " counter++;") |
332 if isinstance(result, tuple) and result[0] == 'throw': | 381 if isinstance(result, tuple) and result[0] == 'throw': |
333 counter += 1 | 382 counter += 1 |
334 if catchThrows: | 383 if catchThrows: |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 | 489 |
441 def write_shard_footer(): | 490 def write_shard_footer(): |
442 write("}") | 491 write("}") |
443 write("%NeverOptimizeFunction(runThisShard);") | 492 write("%NeverOptimizeFunction(runThisShard);") |
444 write("") | 493 write("") |
445 write("// {} tests in this shard.".format(NUM_TESTS_IN_SHARD)) | 494 write("// {} tests in this shard.".format(NUM_TESTS_IN_SHARD)) |
446 write("// {} tests up to here.".format(NUM_TESTS_PRINTED)) | 495 write("// {} tests up to here.".format(NUM_TESTS_PRINTED)) |
447 write("") | 496 write("") |
448 write("runThisShard();") | 497 write("runThisShard();") |
449 | 498 |
| 499 FLAGLETTERS="54321trflcrltfrtld" |
450 | 500 |
451 flagtuple = namedtuple('flagtuple', ( | 501 flagtuple = namedtuple('flagtuple', ( |
| 502 "alternativeFn5", |
452 "alternativeFn4", | 503 "alternativeFn4", |
453 "alternativeFn3", | 504 "alternativeFn3", |
454 "alternativeFn2", | 505 "alternativeFn2", |
455 "alternativeFn1", | 506 "alternativeFn1", |
456 "tryThrows", | 507 "tryThrows", |
457 "tryReturns", | 508 "tryReturns", |
458 "tryFirstReturns", | 509 "tryFirstReturns", |
459 "tryResultToLocal", | 510 "tryResultToLocal", |
460 "doCatch", | 511 "doCatch", |
461 "catchReturns", | 512 "catchReturns", |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 print("") | 552 print("") |
502 sys.exit(1) | 553 sys.exit(1) |
503 | 554 |
504 rotateshard() | 555 rotateshard() |
505 | 556 |
506 for flags in allFlagCombinations: | 557 for flags in allFlagCombinations: |
507 printtest(flags) | 558 printtest(flags) |
508 rotateshard() | 559 rotateshard() |
509 | 560 |
510 finishshard() | 561 finishshard() |
| 562 |
| 563 if MODE == 'shard': |
| 564 print("Total: {} tests.".format(NUM_TESTS_PRINTED)) |
OLD | NEW |