Wed, 03 Jul 2013 13:03:36 +0200
8019585: Sometimes a var declaration using itself in its init wasn't declared as canBeUndefined, causing erroneous bytecode
Reviewed-by: sundar, attila
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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package jdk.nashorn.internal.objects;
28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31 import java.util.List;
33 import jdk.nashorn.api.scripting.ScriptObjectMirror;
34 import jdk.nashorn.internal.objects.annotations.Attribute;
35 import jdk.nashorn.internal.objects.annotations.Constructor;
36 import jdk.nashorn.internal.objects.annotations.Function;
37 import jdk.nashorn.internal.objects.annotations.ScriptClass;
38 import jdk.nashorn.internal.parser.Parser;
39 import jdk.nashorn.internal.runtime.Context;
40 import jdk.nashorn.internal.runtime.JSType;
41 import jdk.nashorn.internal.runtime.ParserException;
42 import jdk.nashorn.internal.runtime.PropertyMap;
43 import jdk.nashorn.internal.runtime.ScriptFunction;
44 import jdk.nashorn.internal.runtime.ScriptObject;
45 import jdk.nashorn.internal.runtime.ScriptRuntime;
46 import jdk.nashorn.internal.runtime.Source;
48 /**
49 * ECMA 15.3 Function Objects
50 *
51 * Note: instances of this class are never created. This class is not even a
52 * subclass of ScriptObject. But, we use this class to generate prototype and
53 * constructor for "Function".
54 */
55 @ScriptClass("Function")
56 public final class NativeFunction {
58 // initialized by nasgen
59 @SuppressWarnings("unused")
60 private static PropertyMap $nasgenmap$;
62 // do *not* create me!
63 private NativeFunction() {
64 }
66 /**
67 * ECMA 15.3.4.2 Function.prototype.toString ( )
68 *
69 * @param self self reference
70 * @return string representation of Function
71 */
72 @Function(attributes = Attribute.NOT_ENUMERABLE)
73 public static Object toString(final Object self) {
74 if (!(self instanceof ScriptFunction)) {
75 throw typeError("not.a.function", ScriptRuntime.safeToString(self));
76 }
77 return ((ScriptFunction)self).toSource();
78 }
80 /**
81 * ECMA 15.3.4.3 Function.prototype.apply (thisArg, argArray)
82 *
83 * @param self self reference
84 * @param thiz {@code this} arg for apply
85 * @param array array of argument for apply
86 * @return result of apply
87 */
88 @Function(attributes = Attribute.NOT_ENUMERABLE)
89 public static Object apply(final Object self, final Object thiz, final Object array) {
90 if (!(self instanceof ScriptFunction)) {
91 throw typeError("not.a.function", ScriptRuntime.safeToString(self));
92 }
94 Object[] args = null;
96 if (array instanceof ScriptObject) {
97 // look for array-like object
98 final ScriptObject sobj = (ScriptObject)array;
99 final Object len = sobj.getLength();
100 final int n = (int)JSType.toUint32(len);
102 args = new Object[n];
103 for (int i = 0; i < args.length; i++) {
104 args[i] = sobj.get(i);
105 }
106 } else if (array instanceof Object[]) {
107 args = (Object[])array;
108 } else if (array instanceof List) {
109 final List<?> list = (List<?>)array;
110 list.toArray(args = new Object[list.size()]);
111 } else if (array == null || array == UNDEFINED) {
112 args = ScriptRuntime.EMPTY_ARRAY;
113 } else if (array instanceof ScriptObjectMirror) {
114 // look for array-like ScriptObjectMirror object
115 final ScriptObjectMirror mirror = (ScriptObjectMirror)array;
116 final Object len = mirror.containsKey("length")? mirror.getMember("length") : Integer.valueOf(0);
117 final int n = (int)JSType.toUint32(len);
119 args = new Object[n];
120 for (int i = 0; i < args.length; i++) {
121 args[i] = mirror.containsKey(i)? mirror.getSlot(i) : UNDEFINED;
122 }
123 } else {
124 throw typeError("function.apply.expects.array");
125 }
127 return ScriptRuntime.apply((ScriptFunction)self, thiz, args);
128 }
130 /**
131 * ECMA 15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] )
132 *
133 * @param self self reference
134 * @param args arguments for call
135 * @return result of call
136 */
137 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
138 public static Object call(final Object self, final Object... args) {
139 if (!(self instanceof ScriptFunction)) {
140 throw typeError("not.a.function", ScriptRuntime.safeToString(self));
141 }
143 Object thiz = (args.length == 0) ? UNDEFINED : args[0];
144 Object[] arguments;
146 if (args.length > 1) {
147 arguments = new Object[args.length - 1];
148 System.arraycopy(args, 1, arguments, 0, arguments.length);
149 } else {
150 arguments = ScriptRuntime.EMPTY_ARRAY;
151 }
153 return ScriptRuntime.apply((ScriptFunction)self, thiz, arguments);
154 }
156 /**
157 * ECMA 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
158 *
159 * @param self self reference
160 * @param args arguments for bind
161 * @return function with bound arguments
162 */
163 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
164 public static Object bind(final Object self, final Object... args) {
165 if (!(self instanceof ScriptFunction)) {
166 throw typeError("not.a.function", ScriptRuntime.safeToString(self));
167 }
169 final Object thiz = (args.length == 0) ? UNDEFINED : args[0];
171 Object[] arguments;
172 if (args.length > 1) {
173 arguments = new Object[args.length - 1];
174 System.arraycopy(args, 1, arguments, 0, arguments.length);
175 } else {
176 arguments = ScriptRuntime.EMPTY_ARRAY;
177 }
179 return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments);
180 }
182 /**
183 * Nashorn extension: Function.prototype.toSource
184 *
185 * @param self self reference
186 * @return source for function
187 */
188 @Function(attributes = Attribute.NOT_ENUMERABLE)
189 public static Object toSource(final Object self) {
190 if (!(self instanceof ScriptFunction)) {
191 throw typeError("not.a.function", ScriptRuntime.safeToString(self));
192 }
193 return ((ScriptFunction)self).toSource();
194 }
196 /**
197 * ECMA 15.3.2.1 new Function (p1, p2, ... , pn, body)
198 *
199 * Constructor
200 *
201 * @param newObj is the new operator used for constructing this function
202 * @param self self reference
203 * @param args arguments
204 * @return new NativeFunction
205 */
206 @Constructor(arity = 1)
207 public static Object function(final boolean newObj, final Object self, final Object... args) {
208 final StringBuilder sb = new StringBuilder();
210 sb.append("(function (");
211 if (args.length > 0) {
212 final StringBuilder paramListBuf = new StringBuilder();
213 for (int i = 0; i < args.length - 1; i++) {
214 paramListBuf.append(JSType.toString(args[i]));
215 if (i < args.length - 2) {
216 paramListBuf.append(",");
217 }
218 }
220 final String paramList = paramListBuf.toString();
221 if (! paramList.isEmpty()) {
222 checkFunctionParameters(paramList);
223 sb.append(paramList);
224 }
225 }
226 sb.append(") {\n");
227 if (args.length > 0) {
228 final String funcBody = JSType.toString(args[args.length - 1]);
229 checkFunctionBody(funcBody);
230 sb.append(funcBody);
231 sb.append('\n');
232 }
233 sb.append("})");
235 final Global global = Global.instance();
237 return Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext());
238 }
240 private static void checkFunctionParameters(final String params) {
241 final Source src = new Source("<function>", params);
242 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager());
243 try {
244 parser.parseFormalParameterList();
245 } catch (final ParserException pe) {
246 pe.throwAsEcmaException();
247 }
248 }
250 private static void checkFunctionBody(final String funcBody) {
251 final Source src = new Source("<function>", funcBody);
252 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager());
253 try {
254 parser.parseFunctionBody();
255 } catch (final ParserException pe) {
256 pe.throwAsEcmaException();
257 }
258 }
259 }