OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python3 |
| 2 |
| 3 # Copyright 2016 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 |
| 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__) |
| 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 |
| 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 |