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

     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 }

mercurial