JDK-8006529.js revision 850:c61d579dd5a8
133965Sjdp/* 233965Sjdp * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 333965Sjdp * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4218822Sdim * 5218822Sdim * This code is free software; you can redistribute it and/or modify it 633965Sjdp * under the terms of the GNU General Public License version 2 only, as 733965Sjdp * published by the Free Software Foundation. 833965Sjdp * 933965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT 1033965Sjdp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1133965Sjdp * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1233965Sjdp * version 2 for more details (a copy is included in the LICENSE file that 1333965Sjdp * accompanied this code). 1433965Sjdp * 1533965Sjdp * You should have received a copy of the GNU General Public License version 1633965Sjdp * 2 along with this work; if not, write to the Free Software Foundation, 1733965Sjdp * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1833965Sjdp * 1933965Sjdp * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2060484Sobrien * or visit www.oracle.com if you need additional information or have any 21218822Sdim * questions. 22218822Sdim */ 2333965Sjdp 24130561Sobrien/** 25130561Sobrien * JDK-8006529 : Methods should not always get callee parameter, and they 26130561Sobrien * should not be too eager in creation of scopes. 27130561Sobrien * 28130561Sobrien * @test 2933965Sjdp * @run 30130561Sobrien */ 3133965Sjdp 3233965Sjdp/* 3333965Sjdp * This test script depends on nashorn Compiler internals. It uses reflection 34130561Sobrien * to get access to private field and many public methods of Compiler and 3533965Sjdp * FunctionNode classes. Note that this is trusted code and access to such 3633965Sjdp * internal package classes and methods is okay. But, if you modify any 37130561Sobrien * Compiler or FunctionNode class, you may have to revisit this script. 3833965Sjdp * We cannot use direct Java class (via dynalink bean linker) to Compiler 3933965Sjdp * and FunctionNode because of package-access check and so reflective calls. 4033965Sjdp */ 4133965Sjdp 4233965Sjdpvar forName = java.lang.Class["forName(String)"]; 4333965Sjdpvar Parser = forName("jdk.nashorn.internal.parser.Parser").static 4433965Sjdpvar Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static 45130561Sobrienvar Context = forName("jdk.nashorn.internal.runtime.Context").static 46218822Sdimvar ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static 47130561Sobrienvar Source = forName("jdk.nashorn.internal.runtime.Source").static 48130561Sobrienvar FunctionNode = forName("jdk.nashorn.internal.ir.FunctionNode").static 49130561Sobrienvar Block = forName("jdk.nashorn.internal.ir.Block").static 50130561Sobrienvar VarNode = forName("jdk.nashorn.internal.ir.VarNode").static 51130561Sobrienvar ExpressionStatement = forName("jdk.nashorn.internal.ir.ExpressionStatement").static 52130561Sobrienvar UnaryNode = forName("jdk.nashorn.internal.ir.UnaryNode").static 53130561Sobrienvar BinaryNode = forName("jdk.nashorn.internal.ir.BinaryNode").static 54130561Sobrienvar ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static 55130561Sobrienvar ErrorManager = forName("jdk.nashorn.internal.runtime.ErrorManager").static 56130561Sobrienvar Debug = forName("jdk.nashorn.internal.runtime.Debug").static 57130561Sobrien 58130561Sobrienvar parseMethod = Parser.class.getMethod("parse"); 59130561Sobrienvar compileMethod = Compiler.class.getMethod("compile", FunctionNode.class); 60130561Sobrienvar getBodyMethod = FunctionNode.class.getMethod("getBody"); 61130561Sobrienvar getStatementsMethod = Block.class.getMethod("getStatements"); 62130561Sobrienvar getInitMethod = VarNode.class.getMethod("getInit"); 63130561Sobrienvar getExpressionMethod = ExpressionStatement.class.getMethod("getExpression") 64130561Sobrienvar rhsMethod = UnaryNode.class.getMethod("getExpression") 65130561Sobrienvar lhsMethod = BinaryNode.class.getMethod("lhs") 66130561Sobrienvar binaryRhsMethod = BinaryNode.class.getMethod("rhs") 67130561Sobrienvar debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class) 68130561Sobrien 6933965Sjdp// These are method names of methods in FunctionNode class 70130561Sobrienvar allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'usesSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict'] 7133965Sjdp 72130561Sobrien// corresponding Method objects of FunctionNode class 73130561Sobrienvar functionNodeMethods = {}; 7433965Sjdp// initialize FunctionNode methods 7533965Sjdp(function() { 7633965Sjdp for (var f in allAssertionList) { 7733965Sjdp var method = allAssertionList[f]; 7833965Sjdp functionNodeMethods[method] = FunctionNode.class.getMethod(method); 7960484Sobrien } 8033965Sjdp})(); 8133965Sjdp 8233965Sjdp// returns functionNode.getBody().getStatements().get(0) 8333965Sjdpfunction getFirstFunction(functionNode) { 8433965Sjdp var f = findFunction(getBodyMethod.invoke(functionNode)) 8533965Sjdp 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 ExpressionStatement) { 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 116var SourceConstructor = Source.class.getConstructor(java.lang.String.class, java.lang.String.class) 117var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class) 118var CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class) 119 120// compile(script) -- compiles a script specified as a string with its 121// source code, returns a jdk.nashorn.internal.ir.FunctionNode object 122// representing it. 123function compile(source) { 124 var source = SourceConstructor.newInstance("<no name>", source); 125 126 var env = getEnvMethod.invoke(getContextMethod.invoke(null)) 127 128 var parser = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance()); 129 var func = parseMethod.invoke(parser); 130 131 var compiler = CompilerConstructor.newInstance(env); 132 133 return compileMethod.invoke(compiler, func); 134}; 135 136var allAssertions = (function() { 137 var allAssertions = {} 138 for(var assertion in allAssertionList) { 139 allAssertions[allAssertionList[assertion]] = true 140 } 141 return allAssertions; 142})(); 143 144 145// test(f[, assertions...]) tests whether all the specified assertions on the 146// passed function node are true. 147function test(f) { 148 var assertions = {} 149 for(var i = 1; i < arguments.length; ++i) { 150 var assertion = arguments[i] 151 if(!allAssertions[assertion]) { 152 throw "Unknown assertion " + assertion + " for " + f; 153 } 154 assertions[assertion] = true 155 } 156 for(var assertion in allAssertions) { 157 var expectedValue = !!assertions[assertion] 158 var actualValue = functionNodeMethods[assertion].invoke(f) 159 if(actualValue !== expectedValue) { 160 throw "Expected " + assertion + " === " + expectedValue + ", got " + actualValue + " for " + f + ":" + debugIdMethod.invoke(null, f); 161 } 162 } 163} 164 165// testFirstFn(script[, assertions...] tests whether all the specified 166// assertions are true in the first function in the given script; "script" 167// is a string with the source text of the script. 168function testFirstFn(script) { 169 arguments[0] = getFirstFunction(compile(script)) 170 test.apply(null, arguments) 171} 172 173// ---------------------------------- ACTUAL TESTS START HERE -------------- 174 175// The simplest possible functions have no attributes set 176testFirstFn("function f() { }") 177testFirstFn("function f(x) { x }") 178 179// A function referencing a global needs parent scope, and it needs callee 180// (because parent scope is passed through callee) 181testFirstFn("function f() { x }", 'needsCallee', 'needsParentScope') 182 183// A function referencing "arguments" will have to be vararg. It also needs 184// the callee, as it needs to fill out "arguments.callee". 185testFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg') 186 187// A function referencing "arguments" will have to be vararg. If it is 188// strict, it will not have to have a callee, though. 189testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict') 190 191// A function defining "arguments" as a parameter will not be vararg. 192testFirstFn("function f(arguments) { arguments }") 193 194// A function defining "arguments" as a nested function will not be vararg. 195testFirstFn("function f() { function arguments() {}; arguments; }") 196 197// A function defining "arguments" as a local variable will be vararg. 198testFirstFn("function f() { var arguments; arguments; }", 'isVarArg', 'needsCallee') 199 200// A self-referencing function defined as a statement doesn't need a self 201// symbol, as it'll rather obtain itself from the parent scope. 202testFirstFn("function f() { f() }", 'needsCallee', 'needsParentScope') 203 204// A self-referencing function defined as an expression needs a self symbol, 205// as it can't obtain itself from the parent scope. 206testFirstFn("(function f() { f() })", 'needsCallee', 'usesSelfSymbol') 207 208// A child function accessing parent's variable triggers the need for scope 209// in parent 210testFirstFn("(function f() { var x; function g() { x } })", 'hasScopeBlock') 211 212// A child function accessing parent's parameter triggers the need for scope 213// in parent 214testFirstFn("(function f(x) { function g() { x } })", 'hasScopeBlock') 215 216// A child function accessing a global variable triggers the need for parent 217// scope in parent 218testFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsCallee') 219 220// A child function redefining a local variable from its parent should not 221// affect the parent function in any way 222testFirstFn("(function f() { var x; function g() { var x; x } })") 223 224// Using "with" on its own doesn't do much. 225testFirstFn("(function f() { var o; with(o) {} })") 226 227// "with" referencing a local variable triggers scoping. 228testFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock') 229 230// "with" referencing a non-local variable triggers parent scope. 231testFirstFn("(function f() { var x; with(x) { y } })", 'needsCallee', 'needsParentScope') 232 233// Nested function using "with" is pretty much the same as the parent 234// function needing with. 235testFirstFn("(function f() { function g() { var o; with(o) {} } })") 236 237// Nested function using "with" referencing a local variable. 238testFirstFn("(function f() { var x; function g() { var o; with(o) { x } } })", 'hasScopeBlock') 239 240// Using "eval" triggers pretty much everything. The function even needs to be 241// vararg, 'cause we don't know if eval will be using "arguments". 242testFirstFn("(function f() { eval() })", 'usesSelfSymbol', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'hasEval', 'isVarArg', 'allVarsInScope') 243 244// Nested function using "eval" is almost the same as parent function using 245// eval, but at least the parent doesn't have to be vararg. 246testFirstFn("(function f() { function g() { eval() } })", 'usesSelfSymbol', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope') 247 248// Function with 250 named parameters is ordinary 249testFirstFn("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 }") 250 251// Function with 251 named parameters is variable arguments 252// NOTE: hasScopeBlock should be optimized away. Implementation of JDK-8038942 should take care of it. 253testFirstFn("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') 254