test/script/trusted/JDK-8006529.js

Thu, 24 May 2018 16:39:31 +0800

author
aoqi
date
Thu, 24 May 2018 16:39:31 +0800
changeset 1959
61ffdd1b89f2
parent 1544
689cb2dfe091
parent 1205
4112748288bb
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 /**
    25  * JDK-8006529 : Methods should not always get callee parameter, and they
    26  * should not be too eager in creation of scopes.
    27  *
    28  * @test
    29  * @run
    30  */
    32 /*
    33  * This test script depends on nashorn Compiler internals. It uses reflection
    34  * to get access to private field and many public methods of Compiler and
    35  * FunctionNode classes. Note that this is trusted code and access to such
    36  * internal package classes and methods is okay. But, if you modify any
    37  * Compiler or FunctionNode class, you may have to revisit this script.
    38  * We cannot use direct Java class (via dynalink bean linker) to Compiler
    39  * and FunctionNode because of package-access check and so reflective calls.
    40  */
    42 var forName             = java.lang.Class["forName(String)"];
    43 var Parser              = forName("jdk.nashorn.internal.parser.Parser").static
    44 var Compiler            = forName("jdk.nashorn.internal.codegen.Compiler").static
    45 var CompilationPhases   = forName("jdk.nashorn.internal.codegen.Compiler$CompilationPhases").static;
    46 var Context             = forName("jdk.nashorn.internal.runtime.Context").static
    47 var CodeInstaller       = forName("jdk.nashorn.internal.runtime.CodeInstaller").static
    48 var ScriptEnvironment   = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static
    49 var Source              = forName("jdk.nashorn.internal.runtime.Source").static
    50 var FunctionNode        = forName("jdk.nashorn.internal.ir.FunctionNode").static
    51 var Block               = forName("jdk.nashorn.internal.ir.Block").static
    52 var VarNode             = forName("jdk.nashorn.internal.ir.VarNode").static
    53 var ExpressionStatement = forName("jdk.nashorn.internal.ir.ExpressionStatement").static
    54 var UnaryNode           = forName("jdk.nashorn.internal.ir.UnaryNode").static
    55 var BinaryNode          = forName("jdk.nashorn.internal.ir.BinaryNode").static
    56 var ThrowErrorManager   = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static
    57 var ErrorManager        = forName("jdk.nashorn.internal.runtime.ErrorManager").static
    58 var Debug               = forName("jdk.nashorn.internal.runtime.Debug").static
    59 var String              = forName("java.lang.String").static
    60 var boolean             = Java.type("boolean");
    62 var parseMethod = Parser.class.getMethod("parse");
    63 var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class, CompilationPhases.class);
    64 var getBodyMethod = FunctionNode.class.getMethod("getBody");
    65 var getStatementsMethod = Block.class.getMethod("getStatements");
    66 var getInitMethod = VarNode.class.getMethod("getInit");
    67 var getExpressionMethod = ExpressionStatement.class.getMethod("getExpression")
    68 var rhsMethod = UnaryNode.class.getMethod("getExpression")
    69 var lhsMethod = BinaryNode.class.getMethod("lhs")
    70 var binaryRhsMethod = BinaryNode.class.getMethod("rhs")
    71 var debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class)
    72 var compilePhases = CompilationPhases.class.getField("COMPILE_UPTO_BYTECODE").get(null);
    74 // These are method names of methods in FunctionNode class
    75 var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'usesSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict']
    77 // corresponding Method objects of FunctionNode class
    78 var functionNodeMethods = {};
    79 // initialize FunctionNode methods
    80 (function() {
    81     for (var f in allAssertionList) {
    82         var method = allAssertionList[f];
    83         functionNodeMethods[method] = FunctionNode.class.getMethod(method);
    84     }
    85 })();
    87 // returns functionNode.getBody().getStatements().get(0)
    88 function getFirstFunction(functionNode) {
    89     var f = findFunction(getBodyMethod.invoke(functionNode))
    90     if (f == null) {
    91         throw new Error();
    92     }
    93     return f;
    94 }
    96 function findFunction(node) {
    97     if(node instanceof Block) {
    98         var stmts = getStatementsMethod.invoke(node)
    99         for(var i = 0; i < stmts.size(); ++i) {
   100             var retval = findFunction(stmts.get(i))
   101             if(retval != null) {
   102                 return retval;
   103             }
   104         }
   105     } else if(node instanceof VarNode) {
   106         return findFunction(getInitMethod.invoke(node))
   107     } else if(node instanceof UnaryNode) {
   108         return findFunction(rhsMethod.invoke(node))
   109     } else if(node instanceof BinaryNode) {
   110         return findFunction(lhsMethod.invoke(node)) || findFunction(binaryRhsMethod.invoke(node))
   111     } else if(node instanceof ExpressionStatement) {
   112         return findFunction(getExpressionMethod.invoke(node))
   113     } else if(node instanceof FunctionNode) {
   114         return node
   115     }
   116 }
   118 var getContextMethod = Context.class.getMethod("getContext")
   119 var getEnvMethod = Context.class.getMethod("getEnv")
   121 var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
   122 var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
   123 var CompilerConstructor = Compiler.class.getMethod("forNoInstallerCompilation", Context.class, Source.class, boolean.class);
   125 // compile(script) -- compiles a script specified as a string with its
   126 // source code, returns a jdk.nashorn.internal.ir.FunctionNode object
   127 // representing it.
   128 function compile(source, phases) {
   129     var source = sourceForMethod.invoke(null, "<no name>", source);
   131     var ctxt = getContextMethod.invoke(null);
   132     var env = getEnvMethod.invoke(ctxt);
   134     var parser   = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
   135     var func     = parseMethod.invoke(parser);
   137     var compiler = CompilerConstructor.invoke(null, ctxt, source, false);
   139     return compileMethod.invoke(compiler, func, phases);
   140 };
   142 var allAssertions = (function() {
   143     var allAssertions = {}
   144     for(var assertion in allAssertionList) {
   145         allAssertions[allAssertionList[assertion]] = true
   146     }
   147     return allAssertions;
   148 })();
   151 // test(f[, assertions...]) tests whether all the specified assertions on the
   152 // passed function node are true.
   153 function test(f) {
   154     var assertions = {}
   155     for(var i = 1; i < arguments.length; ++i) {
   156         var assertion = arguments[i]
   157         if(!allAssertions[assertion]) {
   158             throw "Unknown assertion " + assertion + " for " + f;
   159         }
   160         assertions[assertion] = true
   161     }
   162     for(var assertion in allAssertions) {
   163         var expectedValue = !!assertions[assertion]
   164         var actualValue = functionNodeMethods[assertion].invoke(f)
   165         if(actualValue !== expectedValue) {
   166             throw "Expected " + assertion + " === " + expectedValue + ", got " + actualValue + " for " + f + ":" + debugIdMethod.invoke(null, f);
   167         }
   168     }
   169 }
   171 // testFirstFn(script[, assertions...] tests whether all the specified
   172 // assertions are true in the first function in the given script; "script"
   173 // is a string with the source text of the script.
   174 function testFirstFn(script) {
   175     arguments[0] = getFirstFunction(compile(script, compilePhases));
   176     test.apply(null, arguments);
   177 }
   179 // ---------------------------------- ACTUAL TESTS START HERE --------------
   181 // The simplest possible functions have no attributes set
   182 testFirstFn("function f() { }")
   183 testFirstFn("function f(x) { x }")
   185 // A function referencing a global needs parent scope, and it needs callee
   186 // (because parent scope is passed through callee)
   187 testFirstFn("function f() { x }", 'needsCallee', 'needsParentScope')
   189 // A function referencing "arguments" will have to be vararg. It also needs
   190 // the callee, as it needs to fill out "arguments.callee".
   191 testFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg')
   193 // A function referencing "arguments" will have to be vararg. If it is
   194 // strict, it will not have to have a callee, though.
   195 testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict')
   197 // A function defining "arguments" as a parameter will not be vararg.
   198 testFirstFn("function f(arguments) { arguments }")
   200 // A function defining "arguments" as a nested function will not be vararg.
   201 testFirstFn("function f() { function arguments() {}; arguments; }")
   203 // A function defining "arguments" as a local variable will be vararg.
   204 testFirstFn("function f() { var arguments; arguments; }", 'isVarArg', 'needsCallee')
   206 // A self-referencing function defined as a statement doesn't need a self
   207 // symbol, as it'll rather obtain itself from the parent scope.
   208 testFirstFn("function f() { f() }", 'needsCallee', 'needsParentScope')
   210 // A self-referencing function defined as an expression needs a self symbol,
   211 // as it can't obtain itself from the parent scope.
   212 testFirstFn("(function f() { f() })", 'needsCallee', 'usesSelfSymbol')
   214 // A child function accessing parent's variable triggers the need for scope
   215 // in parent
   216 testFirstFn("(function f() { var x; function g() { x } })", 'hasScopeBlock')
   218 // A child function accessing parent's parameter triggers the need for scope
   219 // in parent
   220 testFirstFn("(function f(x) { function g() { x } })", 'hasScopeBlock')
   222 // A child function accessing a global variable triggers the need for parent
   223 // scope in parent
   224 testFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsCallee')
   226 // A child function redefining a local variable from its parent should not
   227 // affect the parent function in any way
   228 testFirstFn("(function f() { var x; function g() { var x; x } })")
   230 // Using "with" on its own doesn't do much.
   231 testFirstFn("(function f() { var o; with(o) {} })")
   233 // "with" referencing a local variable triggers scoping.
   234 testFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock')
   236 // "with" referencing a non-local variable triggers parent scope.
   237 testFirstFn("(function f() { var x; with(x) { y } })", 'needsCallee', 'needsParentScope')
   239 // Nested function using "with" is pretty much the same as the parent
   240 // function needing with.
   241 testFirstFn("(function f() { function g() { var o; with(o) {} } })")
   243 // Nested function using "with" referencing a local variable.
   244 testFirstFn("(function f() { var x; function g() { var o; with(o) { x } } })", 'hasScopeBlock')
   246 // Using "eval" triggers pretty much everything. The function even needs to be
   247 // vararg, 'cause we don't know if eval will be using "arguments".
   248 testFirstFn("(function f() { eval() })", 'usesSelfSymbol', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'hasEval', 'isVarArg', 'allVarsInScope')
   250 // Nested function using "eval" is almost the same as parent function using
   251 // eval, but at least the parent doesn't have to be vararg.
   252 testFirstFn("(function f() { function g() { eval() } })", 'usesSelfSymbol', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope')
   254 // Function with 250 named parameters is ordinary
   255 testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126, p127, p128, p129, p130, p131, p132, p133, p134, p135, p136, p137, p138, p139, p140, p141, p142, p143, p144, p145, p146, p147, p148, p149, p150, p151, p152, p153, p154, p155, p156, p157, p158, p159, p160, p161, p162, p163, p164, p165, p166, p167, p168, p169, p170, p171, p172, p173, p174, p175, p176, p177, p178, p179, p180, p181, p182, p183, p184, p185, p186, p187, p188, p189, p190, p191, p192, p193, p194, p195, p196, p197, p198, p199, p200, p201, p202, p203, p204, p205, p206, p207, p208, p209, p210, p211, p212, p213, p214, p215, p216, p217, p218, p219, p220, p221, p222, p223, p224, p225, p226, p227, p228, p229, p230, p231, p232, p233, p234, p235, p236, p237, p238, p239, p240, p241, p242, p243, p244, p245, p246, p247, p248, p249, p250) { p250 = p249 }")
   257 // Function with 251 named parameters is variable arguments
   258 // NOTE: hasScopeBlock should be optimized away. Implementation of JDK-8038942 should take care of it.
   259 testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126, p127, p128, p129, p130, p131, p132, p133, p134, p135, p136, p137, p138, p139, p140, p141, p142, p143, p144, p145, p146, p147, p148, p149, p150, p151, p152, p153, p154, p155, p156, p157, p158, p159, p160, p161, p162, p163, p164, p165, p166, p167, p168, p169, p170, p171, p172, p173, p174, p175, p176, p177, p178, p179, p180, p181, p182, p183, p184, p185, p186, p187, p188, p189, p190, p191, p192, p193, p194, p195, p196, p197, p198, p199, p200, p201, p202, p203, p204, p205, p206, p207, p208, p209, p210, p211, p212, p213, p214, p215, p216, p217, p218, p219, p220, p221, p222, p223, p224, p225, p226, p227, p228, p229, p230, p231, p232, p233, p234, p235, p236, p237, p238, p239, p240, p241, p242, p243, p244, p245, p246, p247, p248, p249, p250, p251) { p250 = p251 }", 'isVarArg', 'hasScopeBlock')

mercurial