JDK-8006529.js revision 464:e4efb3ce97b2
1239671Srwatson/* 2239671Srwatson * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3264897Sbrooks * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4239671Srwatson * 5239671Srwatson * This code is free software; you can redistribute it and/or modify it 6244899Srwatson * under the terms of the GNU General Public License version 2 only, as 7244899Srwatson * published by the Free Software Foundation. 8244899Srwatson * 9244899Srwatson * This code is distributed in the hope that it will be useful, but WITHOUT 10239671Srwatson * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11239671Srwatson * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12239671Srwatson * version 2 for more details (a copy is included in the LICENSE file that 13239671Srwatson * accompanied this code). 14239671Srwatson * 15239671Srwatson * You should have received a copy of the GNU General Public License version 16239671Srwatson * 2 along with this work; if not, write to the Free Software Foundation, 17239671Srwatson * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18239671Srwatson * 19239671Srwatson * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20239671Srwatson * or visit www.oracle.com if you need additional information or have any 21239671Srwatson * questions. 22239671Srwatson */ 23239671Srwatson 24239671Srwatson/** 25239671Srwatson * JDK-8006529 : Methods should not always get callee parameter, and they 26239671Srwatson * should not be too eager in creation of scopes. 27239671Srwatson * 28239671Srwatson * @test 29239671Srwatson * @run 30239671Srwatson */ 31239671Srwatson 32239671Srwatson/* 33239671Srwatson * This test script depends on nashorn Compiler internals. It uses reflection 34239671Srwatson * to get access to private field and many public methods of Compiler and 35244899Srwatson * FunctionNode classes. Note that this is trusted code and access to such 36239671Srwatson * internal package classes and methods is okay. But, if you modify any 37239671Srwatson * Compiler or FunctionNode class, you may have to revisit this script. 38239671Srwatson * We cannot use direct Java class (via dynalink bean linker) to Compiler 39239671Srwatson * and FunctionNode because of package-access check and so reflective calls. 40239671Srwatson */ 41239671Srwatson 42239671Srwatsonvar Parser = Java.type("jdk.nashorn.internal.parser.Parser") 43239671Srwatsonvar Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") 44239671Srwatsonvar Context = Java.type("jdk.nashorn.internal.runtime.Context") 45239671Srwatsonvar ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") 46239671Srwatsonvar Source = Java.type("jdk.nashorn.internal.runtime.Source") 47239671Srwatsonvar FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") 48245330Srwatsonvar Block = Java.type("jdk.nashorn.internal.ir.Block") 49239671Srwatsonvar VarNode = Java.type("jdk.nashorn.internal.ir.VarNode") 50239671Srwatsonvar ExpressionStatement = Java.type("jdk.nashorn.internal.ir.ExpressionStatement") 51239671Srwatsonvar UnaryNode = Java.type("jdk.nashorn.internal.ir.UnaryNode") 52239671Srwatsonvar BinaryNode = Java.type("jdk.nashorn.internal.ir.BinaryNode") 53239671Srwatsonvar ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager") 54239671Srwatsonvar ErrorManager = Java.type("jdk.nashorn.internal.runtime.ErrorManager") 55239671Srwatsonvar Debug = Java.type("jdk.nashorn.internal.runtime.Debug") 56239671Srwatson 57239671Srwatsonvar parseMethod = Parser.class.getMethod("parse"); 58239671Srwatsonvar compileMethod = Compiler.class.getMethod("compile", FunctionNode.class); 59244942Srwatsonvar getBodyMethod = FunctionNode.class.getMethod("getBody"); 60244899Srwatsonvar getStatementsMethod = Block.class.getMethod("getStatements"); 61244899Srwatsonvar getInitMethod = VarNode.class.getMethod("getInit"); 62244942Srwatsonvar getExpressionMethod = ExpressionStatement.class.getMethod("getExpression") 63244899Srwatsonvar rhsMethod = UnaryNode.class.getMethod("rhs") 64239671Srwatsonvar lhsMethod = BinaryNode.class.getMethod("lhs") 65239671Srwatsonvar binaryRhsMethod = BinaryNode.class.getMethod("rhs") 66239671Srwatsonvar debugIdMethod = Debug.class.getMethod("id", java.lang.Object.class) 67239671Srwatson 68264897Sbrooks// These are method names of methods in FunctionNode class 69239671Srwatsonvar allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'needsSelfSymbol', 'isSplit', 'hasEval', 'allVarsInScope', 'isStrict'] 70239671Srwatson 71239671Srwatson// corresponding Method objects of FunctionNode class 72239671Srwatsonvar functionNodeMethods = {}; 73239671Srwatson// initialize FunctionNode methods 74245330Srwatson(function() { 75239671Srwatson for (var f in allAssertionList) { 76239671Srwatson var method = allAssertionList[f]; 77239671Srwatson functionNodeMethods[method] = FunctionNode.class.getMethod(method); 78239671Srwatson } 79239671Srwatson})(); 80239671Srwatson 81239671Srwatson// returns functionNode.getBody().getStatements().get(0) 82239671Srwatsonfunction getFirstFunction(functionNode) { 83239671Srwatson var f = findFunction(getBodyMethod.invoke(functionNode)) 84239671Srwatson if (f == null) { 85239671Srwatson throw new Error(); 86239671Srwatson } 87239671Srwatson return f; 88239671Srwatson} 89239671Srwatson 90239671Srwatsonfunction findFunction(node) { 91239671Srwatson if(node instanceof Block) { 92239671Srwatson var stmts = getStatementsMethod.invoke(node) 93239671Srwatson for(var i = 0; i < stmts.size(); ++i) { 94239671Srwatson var retval = findFunction(stmts.get(i)) 95239671Srwatson if(retval != null) { 96239671Srwatson return retval; 97239671Srwatson } 98239671Srwatson } 99239671Srwatson } else if(node instanceof VarNode) { 100239671Srwatson return findFunction(getInitMethod.invoke(node)) 101239671Srwatson } else if(node instanceof UnaryNode) { 102239671Srwatson return findFunction(rhsMethod.invoke(node)) 103239671Srwatson } else if(node instanceof BinaryNode) { 104239671Srwatson return findFunction(lhsMethod.invoke(node)) || findFunction(binaryRhsMethod.invoke(node)) 105239671Srwatson } else if(node instanceof ExpressionStatement) { 106239671Srwatson return findFunction(getExpressionMethod.invoke(node)) 107239671Srwatson } else if(node instanceof FunctionNode) { 108239671Srwatson return node 109239671Srwatson } 110239671Srwatson} 111239671Srwatson 112239671Srwatsonvar getContextMethod = Context.class.getMethod("getContext") 113239671Srwatsonvar getEnvMethod = Context.class.getMethod("getEnv") 114239671Srwatson 115239671Srwatsonvar SourceConstructor = Source.class.getConstructor(java.lang.String.class, java.lang.String.class) 116239671Srwatsonvar ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class) 117239671Srwatsonvar CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class) 118239671Srwatson 119239671Srwatson// compile(script) -- compiles a script specified as a string with its 120239671Srwatson// source code, returns a jdk.nashorn.internal.ir.FunctionNode object 121239671Srwatson// representing it. 122239671Srwatsonfunction compile(source) { 123239671Srwatson var source = SourceConstructor.newInstance("<no name>", source); 124239671Srwatson 125256745Sbrooks var env = getEnvMethod.invoke(getContextMethod.invoke(null)) 126256745Sbrooks 127256745Sbrooks var parser = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance()); 128256745Sbrooks var func = parseMethod.invoke(parser); 129256745Sbrooks 130256745Sbrooks var compiler = CompilerConstructor.newInstance(env); 131256745Sbrooks 132256745Sbrooks return compileMethod.invoke(compiler, func); 133239671Srwatson}; 134239671Srwatson 135265089Sbzvar allAssertions = (function() { 136265089Sbz var allAssertions = {} 137265089Sbz for(var assertion in allAssertionList) { 138265089Sbz allAssertions[allAssertionList[assertion]] = true 139265089Sbz } 140265089Sbz return allAssertions; 141265089Sbz})(); 142265089Sbz 143265089Sbz 144265089Sbz// test(f[, assertions...]) tests whether all the specified assertions on the 145265089Sbz// passed function node are true. 146265089Sbzfunction test(f) { 147265089Sbz var assertions = {} 148265089Sbz for(var i = 1; i < arguments.length; ++i) { 149265089Sbz var assertion = arguments[i] 150265089Sbz if(!allAssertions[assertion]) { 151265089Sbz throw "Unknown assertion " + assertion + " for " + f; 152265089Sbz } 153265089Sbz assertions[assertion] = true 154265089Sbz } 155265089Sbz for(var assertion in allAssertions) { 156265089Sbz var expectedValue = !!assertions[assertion] 157265089Sbz var actualValue = functionNodeMethods[assertion].invoke(f) 158265089Sbz if(actualValue !== expectedValue) { 159265089Sbz throw "Expected " + assertion + " === " + expectedValue + ", got " + actualValue + " for " + f + ":" + debugIdMethod.invoke(null, f); 160265089Sbz } 161265089Sbz } 162265089Sbz} 163265089Sbz 164265089Sbz// testFirstFn(script[, assertions...] tests whether all the specified 165265089Sbz// assertions are true in the first function in the given script; "script" 166265089Sbz// is a string with the source text of the script. 167273234Sdavidefunction testFirstFn(script) { 168265089Sbz arguments[0] = getFirstFunction(compile(script)) 169273234Sdavide test.apply(null, arguments) 170265089Sbz} 171265089Sbz 172265089Sbz// ---------------------------------- ACTUAL TESTS START HERE -------------- 173265089Sbz 174265089Sbz// The simplest possible functions have no attributes set 175239671SrwatsontestFirstFn("function f() { }") 176239671SrwatsontestFirstFn("function f(x) { x }") 177239671Srwatson 178239671Srwatson// A function referencing a global needs parent scope, and it needs callee 179264897Sbrooks// (because parent scope is passed through callee) 180239671SrwatsontestFirstFn("function f() { x }", 'needsCallee', 'needsParentScope') 181239671Srwatson 182239671Srwatson// A function referencing "arguments" will have to be vararg. It also needs 183239671Srwatson// the callee, as it needs to fill out "arguments.callee". 184239671SrwatsontestFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg') 185264897Sbrooks 186245330Srwatson// A function referencing "arguments" will have to be vararg. If it is 187265089Sbz// strict, it will not have to have a callee, though. 188245330SrwatsontestFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrict') 189265089Sbz 190245330Srwatson// A function defining "arguments" as a parameter will not be vararg. 191245330SrwatsontestFirstFn("function f(arguments) { arguments }") 192239671Srwatson 193239671Srwatson// A function defining "arguments" as a nested function will not be vararg. 194239671SrwatsontestFirstFn("function f() { function arguments() {}; arguments; }") 195239671Srwatson 196239671Srwatson// A function defining "arguments" as a local variable will be vararg. 197239671SrwatsontestFirstFn("function f() { var arguments; arguments; }", 'isVarArg', 'needsCallee') 198239671Srwatson 199239671Srwatson// A self-referencing function defined as a statement doesn't need a self 200239671Srwatson// symbol, as it'll rather obtain itself from the parent scope. 201239671SrwatsontestFirstFn("function f() { f() }", 'needsCallee', 'needsParentScope') 202264897Sbrooks 203264897Sbrooks// A self-referencing function defined as an expression needs a self symbol, 204264897Sbrooks// as it can't obtain itself from the parent scope. 205264897SbrookstestFirstFn("(function f() { f() })", 'needsCallee', 'needsSelfSymbol') 206264897Sbrooks 207264897Sbrooks// A child function accessing parent's variable triggers the need for scope 208264897Sbrooks// in parent 209264897SbrookstestFirstFn("(function f() { var x; function g() { x } })", 'hasScopeBlock') 210264897Sbrooks 211264897Sbrooks// A child function accessing parent's parameter triggers the need for scope 212264897Sbrooks// in parent 213264897SbrookstestFirstFn("(function f(x) { function g() { x } })", 'hasScopeBlock') 214264897Sbrooks 215264897Sbrooks// A child function accessing a global variable triggers the need for parent 216264897Sbrooks// scope in parent 217264897SbrookstestFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsCallee') 218264897Sbrooks 219264897Sbrooks// A child function redefining a local variable from its parent should not 220264897Sbrooks// affect the parent function in any way 221245329SrwatsontestFirstFn("(function f() { var x; function g() { var x; x } })") 222245330Srwatson 223245330Srwatson// Using "with" on its own doesn't do much. 224245330SrwatsontestFirstFn("(function f() { var o; with(o) {} })") 225245330Srwatson 226245330Srwatson// "with" referencing a local variable triggers scoping. 227245330SrwatsontestFirstFn("(function f() { var x; var y; with(x) { y } })", 'hasScopeBlock') 228245330Srwatson 229245330Srwatson// "with" referencing a non-local variable triggers parent scope. 230245330SrwatsontestFirstFn("(function f() { var x; with(x) { y } })", 'needsCallee', 'needsParentScope') 231245330Srwatson 232245330Srwatson// Nested function using "with" is pretty much the same as the parent 233245330Srwatson// function needing with. 234245330SrwatsontestFirstFn("(function f() { function g() { var o; with(o) {} } })") 235245330Srwatson 236245330Srwatson// Nested function using "with" referencing a local variable. 237245330SrwatsontestFirstFn("(function f() { var x; function g() { var o; with(o) { x } } })", 'hasScopeBlock') 238245330Srwatson 239245330Srwatson// Using "eval" triggers pretty much everything. The function even needs to be 240245329Srwatson// vararg, 'cause we don't know if eval will be using "arguments". 241245329SrwatsontestFirstFn("(function f() { eval() })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'hasEval', 'isVarArg', 'allVarsInScope') 242245329Srwatson 243245329Srwatson// Nested function using "eval" is almost the same as parent function using 244259265Sbz// eval, but at least the parent doesn't have to be vararg. 245245329SrwatsontestFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope') 246264605Sbz 247264605Sbz// Function with 250 named parameters is ordinary 248264897SbrookstestFirstFn("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 }") 249264605Sbz 250264897Sbrooks// Function with 251 named parameters is variable arguments 251264897SbrookstestFirstFn("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') 252245329Srwatson