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