diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-12-23 16:30:57 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-01-26 22:46:17 +0100 |
commit | 2739185b790e040c3b044c577327f5d44bffad4a (patch) | |
tree | 29a466999212f4c85958379d9d400eec8a185ba5 /deps/v8/tools/gen-inlining-tests.py | |
parent | a67a04d7654faaa04c8da00e42981ebc9fd0911c (diff) | |
download | node-new-2739185b790e040c3b044c577327f5d44bffad4a.tar.gz |
deps: update V8 to 5.5.372.40
PR-URL: https://github.com/nodejs/node/pull/9618
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/tools/gen-inlining-tests.py')
-rw-r--r-- | deps/v8/tools/gen-inlining-tests.py | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/deps/v8/tools/gen-inlining-tests.py b/deps/v8/tools/gen-inlining-tests.py new file mode 100644 index 0000000000..1a377e61ed --- /dev/null +++ b/deps/v8/tools/gen-inlining-tests.py @@ -0,0 +1,566 @@ +#!/usr/bin/env python3 + +# Copyright 2016 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +from collections import namedtuple +import textwrap +import sys + +SHARD_FILENAME_TEMPLATE = "test/mjsunit/compiler/inline-exception-{shard}.js" +# Generates 2 files. Found by trial and error. +SHARD_SIZE = 97 + +PREAMBLE = """ + +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbo --no-always-opt + +// This test file was generated by tools/gen-inlining-tests.py . + +// Global variables +var deopt = undefined; // either true or false +var counter = 0; + +function resetState() { + counter = 0; +} + +function warmUp(f) { + try { + f(); + } catch (ex) { + // ok + } + try { + f(); + } catch (ex) { + // ok + } +} + +function resetOptAndAssertResultEquals(expected, f) { + warmUp(f); + resetState(); + // %DebugPrint(f); + eval("'dont optimize this function itself please, but do optimize f'"); + %OptimizeFunctionOnNextCall(f); + assertEquals(expected, f()); +} + +function resetOptAndAssertThrowsWith(expected, f) { + warmUp(f); + resetState(); + // %DebugPrint(f); + eval("'dont optimize this function itself please, but do optimize f'"); + %OptimizeFunctionOnNextCall(f); + try { + var result = f(); + fail("resetOptAndAssertThrowsWith", + "exception: " + expected, + "result: " + result); + } catch (ex) { + assertEquals(expected, ex); + } +} + +function increaseAndReturn15() { + if (deopt) %DeoptimizeFunction(f); + counter++; + return 15; +} + +function increaseAndThrow42() { + if (deopt) %DeoptimizeFunction(f); + counter++; + throw 42; +} + +function increaseAndReturn15_noopt_inner() { + if (deopt) %DeoptimizeFunction(f); + counter++; + return 15; +} + +%NeverOptimizeFunction(increaseAndReturn15_noopt_inner); + +function increaseAndThrow42_noopt_inner() { + if (deopt) %DeoptimizeFunction(f); + counter++; + throw 42; +} + +%NeverOptimizeFunction(increaseAndThrow42_noopt_inner); + +// Alternative 1 + +function returnOrThrow(doReturn) { + if (doReturn) { + return increaseAndReturn15(); + } else { + return increaseAndThrow42(); + } +} + +// Alternative 2 + +function increaseAndReturn15_calls_noopt() { + return increaseAndReturn15_noopt_inner(); +} + +function increaseAndThrow42_calls_noopt() { + return increaseAndThrow42_noopt_inner(); +} + +// Alternative 3. +// When passed either {increaseAndReturn15} or {increaseAndThrow42}, it acts +// as the other one. +function invertFunctionCall(f) { + var result; + try { + result = f(); + } catch (ex) { + return ex - 27; + } + throw result + 27; +} + +// Alternative 4: constructor +function increaseAndStore15Constructor() { + if (deopt) %DeoptimizeFunction(f); + ++counter; + this.x = 15; +} + +function increaseAndThrow42Constructor() { + if (deopt) %DeoptimizeFunction(f); + ++counter; + this.x = 42; + throw this.x; +} + +// Alternative 5: property +var magic = {}; +Object.defineProperty(magic, 'prop', { + get: function () { + if (deopt) %DeoptimizeFunction(f); + return 15 + 0 * ++counter; + }, + + set: function(x) { + // argument should be 37 + if (deopt) %DeoptimizeFunction(f); + counter -= 36 - x; // increments counter + throw 42; + } +}) + +// Generate type feedback. + +assertEquals(15, increaseAndReturn15_calls_noopt()); +assertThrowsEquals(function() { return increaseAndThrow42_noopt_inner() }, 42); + +assertEquals(15, (new increaseAndStore15Constructor()).x); +assertThrowsEquals(function() { + return (new increaseAndThrow42Constructor()).x; + }, + 42); + +function runThisShard() { + +""".strip() + +def booltuples(n): + """booltuples(2) yields 4 tuples: (False, False), (False, True), + (True, False), (True, True).""" + + assert isinstance(n, int) + if n <= 0: + yield () + else: + for initial in booltuples(n-1): + yield initial + (False,) + yield initial + (True,) + +def fnname(flags): + assert len(FLAGLETTERS) == len(flags) + + return "f_" + ''.join( + FLAGLETTERS[i] if b else '_' + for (i, b) in enumerate(flags)) + +NUM_TESTS_PRINTED = 0 +NUM_TESTS_IN_SHARD = 0 + +def printtest(flags): + """Print a test case. Takes a couple of boolean flags, on which the + printed Javascript code depends.""" + + assert all(isinstance(flag, bool) for flag in flags) + + # The alternative flags are in reverse order so that if we take all possible + # tuples, ordered lexicographically from false to true, we get first the + # default, then alternative 1, then 2, etc. + ( + alternativeFn5, # use alternative #5 for returning/throwing: + # return/throw using property + alternativeFn4, # use alternative #4 for returning/throwing: + # return/throw using constructor + alternativeFn3, # use alternative #3 for returning/throwing: + # return/throw indirectly, based on function argument + alternativeFn2, # use alternative #2 for returning/throwing: + # return/throw indirectly in unoptimized code, + # no branching + alternativeFn1, # use alternative #1 for returning/throwing: + # return/throw indirectly, based on boolean arg + tryThrows, # in try block, call throwing function + tryReturns, # in try block, call returning function + tryFirstReturns, # in try block, returning goes before throwing + tryResultToLocal, # in try block, result goes to local variable + doCatch, # include catch block + catchReturns, # in catch block, return + catchWithLocal, # in catch block, modify or return the local variable + catchThrows, # in catch block, throw + doFinally, # include finally block + finallyReturns, # in finally block, return local variable + finallyThrows, # in finally block, throw + endReturnLocal, # at very end, return variable local + deopt, # deopt inside inlined function + ) = flags + + # BASIC RULES + + # Only one alternative can be applied at any time. + if (alternativeFn1 + alternativeFn2 + alternativeFn3 + alternativeFn4 + + alternativeFn5 > 1): + return + + # In try, return or throw, or both. + if not (tryReturns or tryThrows): return + + # Either doCatch or doFinally. + if not doCatch and not doFinally: return + + # Catch flags only make sense when catching + if not doCatch and (catchReturns or catchWithLocal or catchThrows): + return + + # Finally flags only make sense when finallying + if not doFinally and (finallyReturns or finallyThrows): + return + + # tryFirstReturns is only relevant when both tryReturns and tryThrows are + # true. + if tryFirstReturns and not (tryReturns and tryThrows): return + + # From the try and finally block, we can return or throw, but not both. + if catchReturns and catchThrows: return + if finallyReturns and finallyThrows: return + + # If at the end we return the local, we need to have touched it. + if endReturnLocal and not (tryResultToLocal or catchWithLocal): return + + # PRUNING + + anyAlternative = any([alternativeFn1, alternativeFn2, alternativeFn3, + alternativeFn4, alternativeFn5]) + specificAlternative = any([alternativeFn2, alternativeFn3]) + rareAlternative = not specificAlternative + + # If try returns and throws, then don't catchWithLocal, endReturnLocal, or + # deopt, or do any alternative. + if (tryReturns and tryThrows and + (catchWithLocal or endReturnLocal or deopt or anyAlternative)): + return + # We don't do any alternative if we do a finally. + if doFinally and anyAlternative: return + # We only use the local variable if we do alternative #2 or #3. + if ((tryResultToLocal or catchWithLocal or endReturnLocal) and + not specificAlternative): + return + # We don't need to test deopting into a finally. + if doFinally and deopt: return + + # We're only interested in alternative #2 if we have endReturnLocal, no + # catchReturns, and no catchThrows, and deopt. + if (alternativeFn2 and + (not endReturnLocal or catchReturns or catchThrows or not deopt)): + return + + + # Flag check succeeded. + + trueFlagNames = [name for (name, value) in flags._asdict().items() if value] + flagsMsgLine = " // Variant flags: [{}]".format(', '.join(trueFlagNames)) + write(textwrap.fill(flagsMsgLine, subsequent_indent=' // ')) + write("") + + if not anyAlternative: + fragments = { + 'increaseAndReturn15': 'increaseAndReturn15()', + 'increaseAndThrow42': 'increaseAndThrow42()', + } + elif alternativeFn1: + fragments = { + 'increaseAndReturn15': 'returnOrThrow(true)', + 'increaseAndThrow42': 'returnOrThrow(false)', + } + elif alternativeFn2: + fragments = { + 'increaseAndReturn15': 'increaseAndReturn15_calls_noopt()', + 'increaseAndThrow42': 'increaseAndThrow42_calls_noopt()', + } + elif alternativeFn3: + fragments = { + 'increaseAndReturn15': 'invertFunctionCall(increaseAndThrow42)', + 'increaseAndThrow42': 'invertFunctionCall(increaseAndReturn15)', + } + elif alternativeFn4: + fragments = { + 'increaseAndReturn15': '(new increaseAndStore15Constructor()).x', + 'increaseAndThrow42': '(new increaseAndThrow42Constructor()).x', + } + else: + assert alternativeFn5 + fragments = { + 'increaseAndReturn15': 'magic.prop /* returns 15 */', + 'increaseAndThrow42': '(magic.prop = 37 /* throws 42 */)', + } + + # As we print code, we also maintain what the result should be. Variable + # {result} can be one of three things: + # + # - None, indicating returning JS null + # - ("return", n) with n an integer + # - ("throw", n), with n an integer + + result = None + # We also maintain what the counter should be at the end. + # The counter is reset just before f is called. + counter = 0 + + write( " f = function {} () {{".format(fnname(flags))) + write( " var local = 888;") + write( " deopt = {};".format("true" if deopt else "false")) + local = 888 + write( " try {") + write( " counter++;") + counter += 1 + resultTo = "local +=" if tryResultToLocal else "return" + if tryReturns and not (tryThrows and not tryFirstReturns): + write( " {} 4 + {increaseAndReturn15};".format(resultTo, **fragments)) + if result == None: + counter += 1 + if tryResultToLocal: + local += 19 + else: + result = ("return", 19) + if tryThrows: + write( " {} 4 + {increaseAndThrow42};".format(resultTo, **fragments)) + if result == None: + counter += 1 + result = ("throw", 42) + if tryReturns and tryThrows and not tryFirstReturns: + write( " {} 4 + {increaseAndReturn15};".format(resultTo, **fragments)) + if result == None: + counter += 1 + if tryResultToLocal: + local += 19 + else: + result = ("return", 19) + write( " counter++;") + if result == None: + counter += 1 + + if doCatch: + write( " } catch (ex) {") + write( " counter++;") + if isinstance(result, tuple) and result[0] == 'throw': + counter += 1 + if catchThrows: + write(" throw 2 + ex;") + if isinstance(result, tuple) and result[0] == "throw": + result = ('throw', 2 + result[1]) + elif catchReturns and catchWithLocal: + write(" return 2 + local;") + if isinstance(result, tuple) and result[0] == "throw": + result = ('return', 2 + local) + elif catchReturns and not catchWithLocal: + write(" return 2 + ex;"); + if isinstance(result, tuple) and result[0] == "throw": + result = ('return', 2 + result[1]) + elif catchWithLocal: + write(" local += ex;"); + if isinstance(result, tuple) and result[0] == "throw": + local += result[1] + result = None + counter += 1 + else: + if isinstance(result, tuple) and result[0] == "throw": + result = None + counter += 1 + write( " counter++;") + + if doFinally: + write( " } finally {") + write( " counter++;") + counter += 1 + if finallyThrows: + write(" throw 25;") + result = ('throw', 25) + elif finallyReturns: + write(" return 3 + local;") + result = ('return', 3 + local) + elif not finallyReturns and not finallyThrows: + write(" local += 2;") + local += 2 + counter += 1 + else: assert False # unreachable + write( " counter++;") + + write( " }") + write( " counter++;") + if result == None: + counter += 1 + if endReturnLocal: + write( " return 5 + local;") + if result == None: + result = ('return', 5 + local) + write( " }") + + if result == None: + write( " resetOptAndAssertResultEquals(undefined, f);") + else: + tag, value = result + if tag == "return": + write( " resetOptAndAssertResultEquals({}, f);".format(value)) + else: + assert tag == "throw" + write( " resetOptAndAssertThrowsWith({}, f);".format(value)) + + write( " assertEquals({}, counter);".format(counter)) + write( "") + + global NUM_TESTS_PRINTED, NUM_TESTS_IN_SHARD + NUM_TESTS_PRINTED += 1 + NUM_TESTS_IN_SHARD += 1 + +FILE = None # to be initialised to an open file +SHARD_NUM = 1 + +def write(*args): + return print(*args, file=FILE) + + + +def rotateshard(): + global FILE, NUM_TESTS_IN_SHARD, SHARD_SIZE + if MODE != 'shard': + return + if FILE != None and NUM_TESTS_IN_SHARD < SHARD_SIZE: + return + if FILE != None: + finishshard() + assert FILE == None + FILE = open(SHARD_FILENAME_TEMPLATE.format(shard=SHARD_NUM), 'w') + write_shard_header() + NUM_TESTS_IN_SHARD = 0 + +def finishshard(): + global FILE, SHARD_NUM, MODE + assert FILE + write_shard_footer() + if MODE == 'shard': + print("Wrote shard {}.".format(SHARD_NUM)) + FILE.close() + FILE = None + SHARD_NUM += 1 + + +def write_shard_header(): + if MODE == 'shard': + write("// Shard {}.".format(SHARD_NUM)) + write("") + write(PREAMBLE) + write("") + +def write_shard_footer(): + write("}") + write("%NeverOptimizeFunction(runThisShard);") + write("") + write("// {} tests in this shard.".format(NUM_TESTS_IN_SHARD)) + write("// {} tests up to here.".format(NUM_TESTS_PRINTED)) + write("") + write("runThisShard();") + +FLAGLETTERS="54321trflcrltfrtld" + +flagtuple = namedtuple('flagtuple', ( + "alternativeFn5", + "alternativeFn4", + "alternativeFn3", + "alternativeFn2", + "alternativeFn1", + "tryThrows", + "tryReturns", + "tryFirstReturns", + "tryResultToLocal", + "doCatch", + "catchReturns", + "catchWithLocal", + "catchThrows", + "doFinally", + "finallyReturns", + "finallyThrows", + "endReturnLocal", + "deopt" + )) + +emptyflags = flagtuple(*((False,) * len(flagtuple._fields))) +f1 = emptyflags._replace(tryReturns=True, doCatch=True) + +# You can test function printtest with f1. + +allFlagCombinations = [ + flagtuple(*bools) + for bools in booltuples(len(flagtuple._fields)) +] + +if __name__ == '__main__': + global MODE + if sys.argv[1:] == []: + MODE = 'stdout' + print("// Printing all shards together to stdout.") + print("") + write_shard_header() + FILE = sys.stdout + elif sys.argv[1:] == ['--shard-and-overwrite']: + MODE = 'shard' + else: + print("Usage:") + print("") + print(" python {}".format(sys.argv[0])) + print(" print all tests to standard output") + print(" python {} --shard-and-overwrite".format(sys.argv[0])) + print(" print all tests to {}".format(SHARD_FILENAME_TEMPLATE)) + + print("") + print(sys.argv[1:]) + print("") + sys.exit(1) + + rotateshard() + + for flags in allFlagCombinations: + printtest(flags) + rotateshard() + + finishshard() + + if MODE == 'shard': + print("Total: {} tests.".format(NUM_TESTS_PRINTED)) |