JDK-8006529.js revision 421:d3f4e5dea634
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 42var forName = java.lang.Class["forName(String)"] 43 44var Parser = forName("jdk.nashorn.internal.parser.Parser").static 45var Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static 46var Context = forName("jdk.nashorn.internal.runtime.Context").static 47var ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static 48var Source = forName("jdk.nashorn.internal.runtime.Source").static 49var FunctionNode = forName("jdk.nashorn.internal.ir.FunctionNode").static 50var Block = forName("jdk.nashorn.internal.ir.Block").static 51var VarNode = forName("jdk.nashorn.internal.ir.VarNode").static 52var ExecuteNode = forName("jdk.nashorn.internal.ir.ExecuteNode").static 53var UnaryNode = forName("jdk.nashorn.internal.ir.UnaryNode").static 54var BinaryNode = forName("jdk.nashorn.internal.ir.BinaryNode").static 55var ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static 56var Debug = forName("jdk.nashorn.internal.runtime.Debug").static 57 58var parseMethod = Parser.class.getMethod("parse"); 59var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class); 60var getBodyMethod = FunctionNode.class.getMethod("getBody"); 61var getStatementsMethod = Block.class.getMethod("getStatements"); 62var getInitMethod = VarNode.class.getMethod("getInit"); 63var getExpressionMethod = ExecuteNode.class.getMethod("getExpression") 64var rhsMethod = UnaryNode.class.getMethod("rhs") 65var lhsMethod = BinaryNode.class.getMethod("lhs") 66var binaryRhsMethod = BinaryNode.class.getMethod("rhs") 67var debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class) 68 69// These are method names of methods in FunctionNode class 70var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'needsSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict'] 71 72// corresponding Method objects of FunctionNode class 73var 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) 83function getFirstFunction(functionNode) { 84 var f = findFunction(getBodyMethod.invoke(functionNode)) 85 if (f == null) { 86 throw new Error(); 87 } 88 return f; 89} 90 91function 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 113var getContextMethod = Context.class.getMethod("getContext") 114var 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. 119function 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 132var 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. 143function 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. 164function 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 172testFirstFn("function f() { }") 173testFirstFn("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) 177testFirstFn("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". 181testFirstFn("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. 185testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict') 186 187// A function defining "arguments" as a parameter will not be vararg. 188testFirstFn("function f(arguments) { arguments }") 189 190// A function defining "arguments" as a nested function will not be vararg. 191testFirstFn("function f() { function arguments() {}; arguments; }") 192 193// A function defining "arguments" as a local variable will be vararg. 194testFirstFn("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. 198testFirstFn("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. 202testFirstFn("(function f() { f() })", 'needsCallee', 'needsSelfSymbol') 203 204// A child function accessing parent's variable triggers the need for scope 205// in parent 206testFirstFn("(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 210testFirstFn("(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 214testFirstFn("(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 218testFirstFn("(function f() { var x; function g() { var x; x } })") 219 220// Using "with" on its own doesn't do much. 221testFirstFn("(function f() { var o; with(o) {} })") 222 223// "with" referencing a local variable triggers scoping. 224testFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock') 225 226// "with" referencing a non-local variable triggers parent scope. 227testFirstFn("(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. 231testFirstFn("(function f() { function g() { var o; with(o) {} } })") 232 233// Nested function using "with" referencing a local variable. 234testFirstFn("(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". 238testFirstFn("(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. 242testFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope') 243 244// Function with 250 named parameters is ordinary 245testFirstFn("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 248testFirstFn("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') 249