nashorn/test/script/trusted/JDK-8006529.js
changeset 18859 7c4d0146ccd5
parent 16523 af8b30edebce
child 18865 8844964e5fc5
equal deleted inserted replaced
18858:802ac572529a 18859:7c4d0146ccd5
       
     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  */
       
    23 
       
    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  */
       
    31 
       
    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  */
       
    41 
       
    42 var forName = java.lang.Class["forName(String)"]
       
    43 
       
    44 var Parser            = forName("jdk.nashorn.internal.parser.Parser").static
       
    45 var Compiler          = forName("jdk.nashorn.internal.codegen.Compiler").static
       
    46 var Context           = forName("jdk.nashorn.internal.runtime.Context").static
       
    47 var ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static
       
    48 var Source            = forName("jdk.nashorn.internal.runtime.Source").static
       
    49 var FunctionNode      = forName("jdk.nashorn.internal.ir.FunctionNode").static
       
    50 var Block             = forName("jdk.nashorn.internal.ir.Block").static
       
    51 var VarNode           = forName("jdk.nashorn.internal.ir.VarNode").static
       
    52 var ExecuteNode       = forName("jdk.nashorn.internal.ir.ExecuteNode").static
       
    53 var UnaryNode         = forName("jdk.nashorn.internal.ir.UnaryNode").static
       
    54 var BinaryNode        = forName("jdk.nashorn.internal.ir.BinaryNode").static
       
    55 var ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static
       
    56 var Debug             = forName("jdk.nashorn.internal.runtime.Debug").static
       
    57 
       
    58 var parseMethod = Parser.class.getMethod("parse");
       
    59 var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class);
       
    60 var getBodyMethod = FunctionNode.class.getMethod("getBody");
       
    61 var getStatementsMethod = Block.class.getMethod("getStatements");
       
    62 var getInitMethod = VarNode.class.getMethod("getInit");
       
    63 var getExpressionMethod = ExecuteNode.class.getMethod("getExpression")
       
    64 var rhsMethod = UnaryNode.class.getMethod("rhs")
       
    65 var lhsMethod = BinaryNode.class.getMethod("lhs")
       
    66 var binaryRhsMethod = BinaryNode.class.getMethod("rhs")
       
    67 var debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class)
       
    68 
       
    69 // These are method names of methods in FunctionNode class
       
    70 var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'needsSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict']
       
    71 
       
    72 // corresponding Method objects of FunctionNode class
       
    73 var functionNodeMethods = {};
       
    74 // initialize FunctionNode methods
       
    75 (function() {
       
    76     for (var f in allAssertionList) {
       
    77         var method = allAssertionList[f];
       
    78         functionNodeMethods[method] = FunctionNode.class.getMethod(method);
       
    79     }
       
    80 })();
       
    81 
       
    82 // returns functionNode.getBody().getStatements().get(0)
       
    83 function getFirstFunction(functionNode) {
       
    84     var f = findFunction(getBodyMethod.invoke(functionNode))
       
    85     if (f == null) {
       
    86         throw new Error();
       
    87     }
       
    88     return f;
       
    89 }
       
    90 
       
    91 function findFunction(node) {
       
    92     if(node instanceof Block) {
       
    93         var stmts = getStatementsMethod.invoke(node)
       
    94         for(var i = 0; i < stmts.size(); ++i) {
       
    95             var retval = findFunction(stmts.get(i))
       
    96             if(retval != null) {
       
    97                 return retval;
       
    98             }
       
    99         }
       
   100     } else if(node instanceof VarNode) {
       
   101         return findFunction(getInitMethod.invoke(node))
       
   102     } else if(node instanceof UnaryNode) {
       
   103         return findFunction(rhsMethod.invoke(node))
       
   104     } else if(node instanceof BinaryNode) {
       
   105         return findFunction(lhsMethod.invoke(node)) || findFunction(binaryRhsMethod.invoke(node))
       
   106 	} else if(node instanceof ExecuteNode) {
       
   107 		return findFunction(getExpressionMethod.invoke(node))
       
   108     } else if(node instanceof FunctionNode) {
       
   109         return node
       
   110     }
       
   111 }
       
   112 
       
   113 var getContextMethod = Context.class.getMethod("getContext")
       
   114 var getEnvMethod = Context.class.getMethod("getEnv")
       
   115 
       
   116 // compile(script) -- compiles a script specified as a string with its 
       
   117 // source code, returns a jdk.nashorn.internal.ir.FunctionNode object 
       
   118 // representing it.
       
   119 function compile(source) {
       
   120     var source   = new Source("<no name>", source);
       
   121 
       
   122     var env = getEnvMethod.invoke(getContextMethod.invoke(null))
       
   123 
       
   124     var parser   = new Parser(env, source, new ThrowErrorManager());
       
   125     var func     = parseMethod.invoke(parser);
       
   126 
       
   127     var compiler = new Compiler(env);
       
   128 
       
   129     return compileMethod.invoke(compiler, func);
       
   130 };
       
   131 
       
   132 var allAssertions = (function() {
       
   133     var allAssertions = {}
       
   134     for(var assertion in allAssertionList) {
       
   135         allAssertions[allAssertionList[assertion]] = true
       
   136     }
       
   137     return allAssertions;
       
   138 })();
       
   139 
       
   140 
       
   141 // test(f[, assertions...]) tests whether all the specified assertions on the
       
   142 // passed function node are true.
       
   143 function test(f) {
       
   144     var assertions = {}
       
   145     for(var i = 1; i < arguments.length; ++i) {
       
   146         var assertion = arguments[i]
       
   147         if(!allAssertions[assertion]) {
       
   148             throw "Unknown assertion " + assertion + " for " + f;
       
   149         }
       
   150         assertions[assertion] = true
       
   151     }
       
   152     for(var assertion in allAssertions) {
       
   153         var expectedValue = !!assertions[assertion]
       
   154         var actualValue = functionNodeMethods[assertion].invoke(f)
       
   155         if(actualValue !== expectedValue) {
       
   156             throw "Expected " + assertion + " === " + expectedValue + ", got " + actualValue + " for " + f + ":" + debugIdMethod.invoke(null, f);
       
   157         }
       
   158     }
       
   159 }
       
   160 
       
   161 // testFirstFn(script[, assertions...] tests whether all the specified
       
   162 // assertions are true in the first function in the given script; "script"
       
   163 // is a string with the source text of the script.
       
   164 function testFirstFn(script) {
       
   165     arguments[0] = getFirstFunction(compile(script))
       
   166     test.apply(null, arguments)
       
   167 }
       
   168 
       
   169 // ---------------------------------- ACTUAL TESTS START HERE --------------
       
   170 
       
   171 // The simplest possible functions have no attributes set
       
   172 testFirstFn("function f() { }")
       
   173 testFirstFn("function f(x) { x }")
       
   174 
       
   175 // A function referencing a global needs parent scope, and it needs callee
       
   176 // (because parent scope is passed through callee)
       
   177 testFirstFn("function f() { x }", 'needsCallee', 'needsParentScope')
       
   178 
       
   179 // A function referencing "arguments" will have to be vararg. It also needs
       
   180 // the callee, as it needs to fill out "arguments.callee".
       
   181 testFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg')
       
   182 
       
   183 // A function referencing "arguments" will have to be vararg. If it is
       
   184 // strict, it will not have to have a callee, though.
       
   185 testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict')
       
   186 
       
   187 // A function defining "arguments" as a parameter will not be vararg.
       
   188 testFirstFn("function f(arguments) { arguments }")
       
   189 
       
   190 // A function defining "arguments" as a nested function will not be vararg.
       
   191 testFirstFn("function f() { function arguments() {}; arguments; }")
       
   192 
       
   193 // A function defining "arguments" as a local variable will be vararg.
       
   194 testFirstFn("function f() { var arguments; arguments; }", 'isVarArg', 'needsCallee')
       
   195 
       
   196 // A self-referencing function defined as a statement doesn't need a self 
       
   197 // symbol, as it'll rather obtain itself from the parent scope.
       
   198 testFirstFn("function f() { f() }", 'needsCallee', 'needsParentScope')
       
   199 
       
   200 // A self-referencing function defined as an expression needs a self symbol,
       
   201 // as it can't obtain itself from the parent scope.
       
   202 testFirstFn("(function f() { f() })", 'needsCallee', 'needsSelfSymbol')
       
   203 
       
   204 // A child function accessing parent's variable triggers the need for scope
       
   205 // in parent
       
   206 testFirstFn("(function f() { var x; function g() { x } })", 'hasScopeBlock')
       
   207 
       
   208 // A child function accessing parent's parameter triggers the need for scope
       
   209 // in parent
       
   210 testFirstFn("(function f(x) { function g() { x } })", 'hasScopeBlock')
       
   211 
       
   212 // A child function accessing a global variable triggers the need for parent
       
   213 // scope in parent
       
   214 testFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsCallee')
       
   215 
       
   216 // A child function redefining a local variable from its parent should not 
       
   217 // affect the parent function in any way
       
   218 testFirstFn("(function f() { var x; function g() { var x; x } })")
       
   219 
       
   220 // Using "with" on its own doesn't do much.
       
   221 testFirstFn("(function f() { var o; with(o) {} })")
       
   222 
       
   223 // "with" referencing a local variable triggers scoping.
       
   224 testFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock')
       
   225 
       
   226 // "with" referencing a non-local variable triggers parent scope.
       
   227 testFirstFn("(function f() { var x; with(x) { y } })", 'needsCallee', 'needsParentScope')
       
   228 
       
   229 // Nested function using "with" is pretty much the same as the parent
       
   230 // function needing with.
       
   231 testFirstFn("(function f() { function g() { var o; with(o) {} } })")
       
   232 
       
   233 // Nested function using "with" referencing a local variable.
       
   234 testFirstFn("(function f() { var x; function g() { var o; with(o) { x } } })", 'hasScopeBlock')
       
   235 
       
   236 // Using "eval" triggers pretty much everything. The function even needs to be
       
   237 // vararg, 'cause we don't know if eval will be using "arguments".
       
   238 testFirstFn("(function f() { eval() })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'hasEval', 'isVarArg', 'allVarsInScope')
       
   239 
       
   240 // Nested function using "eval" is almost the same as parent function using
       
   241 // eval, but at least the parent doesn't have to be vararg.
       
   242 testFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope')
       
   243 
       
   244 // Function with 250 named parameters is ordinary
       
   245 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 }")
       
   246 
       
   247 // Function with 251 named parameters is variable arguments
       
   248 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')