JDK-8006529.js revision 117:927fba6785b0
1118699Strhodes/* 2118699Strhodes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3118699Strhodes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4118699Strhodes * 5118699Strhodes * This code is free software; you can redistribute it and/or modify it 6118699Strhodes * under the terms of the GNU General Public License version 2 only, as 7118699Strhodes * published by the Free Software Foundation. 8118699Strhodes * 9118699Strhodes * This code is distributed in the hope that it will be useful, but WITHOUT 10118699Strhodes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11118699Strhodes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12118699Strhodes * version 2 for more details (a copy is included in the LICENSE file that 13118699Strhodes * accompanied this code). 14118699Strhodes * 15118699Strhodes * You should have received a copy of the GNU General Public License version 16118699Strhodes * 2 along with this work; if not, write to the Free Software Foundation, 17118699Strhodes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18118699Strhodes * 19118699Strhodes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20118699Strhodes * or visit www.oracle.com if you need additional information or have any 21118699Strhodes * questions. 22118699Strhodes */ 23118699Strhodes 24118699Strhodes/** 25118699Strhodes * JDK-8006529 : Methods should not always get callee parameter, and they 26118699Strhodes * should not be too eager in creation of scopes. 27118699Strhodes * 28214387Sbcr * @test 29118699Strhodes * @run 30118699Strhodes */ 31118699Strhodes 32118699Strhodes/* 33118699Strhodes * This test script depends on nashorn Compiler internals. It uses reflection 34118699Strhodes * to get access to private field and many public methods of Compiler and 35118699Strhodes * FunctionNode classes. Note that this is trusted code and access to such 36118699Strhodes * internal package classes and methods is okay. But, if you modify any 37118699Strhodes * Compiler or FunctionNode class, you may have to revisit this script. 38118699Strhodes * We cannot use direct Java class (via dynalink bean linker) to Compiler 39118699Strhodes * and FunctionNode because of package-access check and so reflective calls. 40118699Strhodes */ 41118699Strhodes 42118699Strhodesvar Parser = Java.type("jdk.nashorn.internal.parser.Parser") 43118699Strhodesvar Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") 44118699Strhodesvar Context = Java.type("jdk.nashorn.internal.runtime.Context") 45118699Strhodesvar ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") 46118699Strhodesvar Source = Java.type("jdk.nashorn.internal.runtime.Source") 47118699Strhodesvar FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") 48118699Strhodes 49118699Strhodes// Compiler class methods and fields 50118699Strhodesvar parseMethod = Parser.class.getMethod("parse"); 51118699Strhodesvar compileMethod = Compiler.class.getMethod("compile"); 52118699Strhodes 53118699Strhodes// NOTE: private field. But this is a trusted test! 54118699Strhodes// Compiler.functionNode 55118699Strhodesvar functionNodeField = Compiler.class.getDeclaredField("functionNode"); 56118699StrhodesfunctionNodeField.setAccessible(true); 57118699Strhodes 58118699Strhodes// FunctionNode methods 59118699Strhodes 60118699Strhodes// FunctionNode.getFunctions method 61118699Strhodesvar getFunctionsMethod = FunctionNode.class.getMethod("getFunctions"); 62118699Strhodes 63118699Strhodes// These are method names of methods in FunctionNode class 64118699Strhodesvar allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'needsScope', 'needsSelfSymbol', 'isSplit', 'hasEval', 'hasWith', 'hasDeepWithOrEval', 'allVarsInScope', 'isStrictMode'] 65118699Strhodes 66118699Strhodes// corresponding Method objects of FunctionNode class 67118699Strhodesvar functionNodeMethods = {}; 68118699Strhodes// initialize FunctionNode methods 69118699Strhodes(function() { 70118699Strhodes for (var f in allAssertionList) { 71118699Strhodes var method = allAssertionList[f]; 72118699Strhodes functionNodeMethods[method] = FunctionNode.class.getMethod(method); 73118699Strhodes } 74118699Strhodes})(); 75118699Strhodes 76118699Strhodes// returns "script" functionNode from Compiler instance 77118699Strhodesfunction getScriptNode(compiler) { 78118699Strhodes // compiler.functionNode 79118699Strhodes return functionNodeField.get(compiler); 80118699Strhodes} 81118699Strhodes 82118699Strhodes// returns functionNode.getFunctions().get(0) 83118699Strhodesfunction getFirstFunction(functionNode) { 84118699Strhodes // functionNode.getFunctions().get(0) 85263140Sglebius return getFunctionsMethod.invoke(functionNode).get(0); 86118699Strhodes} 87118699Strhodes 88118699Strhodes// compile(script) -- compiles a script specified as a string with its 89118699Strhodes// source code, returns a jdk.nashorn.internal.ir.FunctionNode object 90214387Sbcr// representing it. 91118699Strhodesfunction compile(source) { 92118699Strhodes var source = new Source("<no name>", source); 93118699Strhodes var parser = new Parser(Context.getContext().getEnv(), source, null); 94118699Strhodes var func = parseMethod.invoke(parser); 95118699Strhodes var compiler = new Compiler(Context.getContext().getEnv(), func); 96118699Strhodes 97118699Strhodes compileMethod.invoke(compiler); 98118699Strhodes 99214387Sbcr return getScriptNode(compiler); 100214387Sbcr}; 101118699Strhodes 102118699Strhodesvar allAssertions = (function() { 103118699Strhodes var allAssertions = {} 104118699Strhodes for(var assertion in allAssertionList) { 105118699Strhodes allAssertions[allAssertionList[assertion]] = true 106118699Strhodes } 107118699Strhodes return allAssertions; 108118699Strhodes})(); 109118699Strhodes 110118699Strhodes 111118699Strhodes// test(f[, assertions...]) tests whether all the specified assertions on the 112118699Strhodes// passed function node are true. 113214387Sbcrfunction test(f) { 114214387Sbcr var assertions = {} 115214387Sbcr for(var i = 1; i < arguments.length; ++i) { 116118699Strhodes var assertion = arguments[i] 117118699Strhodes if(!allAssertions[assertion]) { 118118699Strhodes throw "Unknown assertion " + assertion + " for " + f; 119118699Strhodes } 120118699Strhodes assertions[assertion] = true 121118699Strhodes } 122118699Strhodes for(var assertion in allAssertions) { 123118699Strhodes var expectedValue = !!assertions[assertion] 124118699Strhodes if(functionNodeMethods[assertion].invoke(f) !== expectedValue) { 125118699Strhodes throw "Expected " + assertion + " === " + expectedValue + " for " + f; 126118699Strhodes } 127118699Strhodes } 128118699Strhodes} 129118699Strhodes 130118699Strhodes// testFirstFn(script[, assertions...] tests whether all the specified 131118699Strhodes// assertions are true in the first function in the given script; "script" 132214387Sbcr// is a string with the source text of the script. 133214387Sbcrfunction testFirstFn(script) { 134214387Sbcr arguments[0] = getFirstFunction(compile(script)) 135233648Seadler test.apply(null, arguments) 136214387Sbcr} 137214387Sbcr 138214387Sbcr// ---------------------------------- ACTUAL TESTS START HERE -------------- 139214387Sbcr 140214387Sbcr// The simplest possible functions have no attributes set 141214387SbcrtestFirstFn("function f() { }") 142214387SbcrtestFirstFn("function f(x) { x }") 143233648Seadler 144118699Strhodes// A function referencing a global needs parent scope, and it needs callee 145118699Strhodes// (because parent scope is passed through callee) 146118699StrhodestestFirstFn("function f() { x }", 'needsCallee', 'needsParentScope') 147118699Strhodes 148118699Strhodes// A function referencing "arguments" will have to be vararg. It also needs 149118699Strhodes// the callee, as it needs to fill out "arguments.callee". 150267776SbapttestFirstFn("function f() { arguments }", 'needsCallee', 'isVarArg') 151118699Strhodes 152267776Sbapt// A function referencing "arguments" will have to be vararg. If it is 153// strict, it will not have to have a callee, though. 154testFirstFn("function f() {'use strict'; arguments }", 'isVarArg', 'isStrictMode') 155 156// A function defining "arguments" as a parameter will not be vararg. 157testFirstFn("function f(arguments) { arguments }") 158 159// A function defining "arguments" as a nested function will not be vararg. 160testFirstFn("function f() { function arguments() {}; arguments; }") 161 162// A function defining "arguments" as a local variable will be vararg. 163testFirstFn("function f() { var arguments; arguments; }", 'isVarArg', 'needsCallee') 164 165// A self-referencing function defined as a statement doesn't need a self 166// symbol, as it'll rather obtain itself from the parent scope. 167testFirstFn("function f() { f() }", 'needsCallee', 'needsParentScope') 168 169// A self-referencing function defined as an expression needs a self symbol, 170// as it can't obtain itself from the parent scope. 171testFirstFn("(function f() { f() })", 'needsCallee', 'needsSelfSymbol') 172 173// A child function accessing parent's variable triggers the need for scope 174// in parent 175testFirstFn("(function f() { var x; function g() { x } })", 'needsScope') 176 177// A child function accessing parent's parameter triggers the need for scope 178// in parent 179testFirstFn("(function f(x) { function g() { x } })", 'needsScope') 180 181// A child function accessing a global variable triggers the need for parent 182// scope in parent 183testFirstFn("(function f() { function g() { x } })", 'needsParentScope', 'needsCallee') 184 185// A child function redefining a local variable from its parent should not 186// affect the parent function in any way 187testFirstFn("(function f() { var x; function g() { var x; x } })") 188 189// Using "with" unleashes a lot of needs: parent scope, callee, own scope, 190// and all variables in scope. Actually, we could make "with" less wasteful, 191// and only put those variables in scope that it actually references, similar 192// to what nested functions do with variables in their parents. 193testFirstFn("(function f() { var o; with(o) {} })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasWith', 'hasDeepWithOrEval', 'allVarsInScope') 194 195// Using "eval" is as bad as using "with" with the added requirement of 196// being vararg, 'cause we don't know if eval will be using "arguments". 197testFirstFn("(function f() { eval() })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasEval', 'isVarArg', 'hasDeepWithOrEval', 'allVarsInScope') 198 199// Nested function using "with" is pretty much the same as the parent 200// function needing with. 201testFirstFn("(function f() { function g() { var o; with(o) {} } })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasDeepWithOrEval', 'allVarsInScope') 202// Nested function using "eval" is almost the same as parent function using 203// eval, but at least the parent doesn't have to be vararg. 204testFirstFn("(function f() { function g() { eval() } })", 'needsParentScope', 'needsCallee', 'needsScope', 'hasDeepWithOrEval', 'allVarsInScope') 205 206// Function with 250 named parameters is ordinary 207testFirstFn("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 }") 208 209// Function with 251 named parameters is variable arguments 210testFirstFn("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') 211