src/jdk/nashorn/internal/objects/NativeFunction.java

Wed, 03 Jul 2013 13:03:36 +0200

author
lagergren
date
Wed, 03 Jul 2013 13:03:36 +0200
changeset 405
b1980b5f00a1
parent 380
80c66d3fd872
child 414
ec84ba68ad39
permissions
-rw-r--r--

8019585: Sometimes a var declaration using itself in its init wasn't declared as canBeUndefined, causing erroneous bytecode
Reviewed-by: sundar, attila

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

mercurial