Chromium Code Reviews| 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 |