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 */ 25 26 package jdk.nashorn.internal.objects; 27 28 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 29 import static jdk.nashorn.internal.runtime.linker.Lookup.MH; 30 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodHandles; 33 34 import jdk.nashorn.internal.runtime.ScriptFunctionData; 35 import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; 36 import jdk.nashorn.internal.runtime.GlobalFunctions; 37 import jdk.nashorn.internal.runtime.Property; 38 import jdk.nashorn.internal.runtime.PropertyMap; 39 import jdk.nashorn.internal.runtime.ScriptFunction; 40 import jdk.nashorn.internal.runtime.ScriptObject; 41 import jdk.nashorn.internal.runtime.ScriptRuntime; 42 import jdk.nashorn.internal.runtime.linker.Lookup; 43 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; 44 45 /** 46 * Concrete implementation of ScriptFunction. This sets correct map for the 47 * function objects -- to expose properties like "prototype", "length" etc. 48 */ 49 public class ScriptFunctionImpl extends ScriptFunction { 50 51 private static final MethodHandle BOUND_FUNCTION = findOwnMH("boundFunction", Object.class, ScriptFunction.class, Object.class, Object[].class, Object.class, Object[].class); 52 private static final MethodHandle BOUND_CONSTRUCTOR = findOwnMH("boundConstructor", Object.class, ScriptFunction.class, Object[].class, Object.class, Object[].class); 53 54 private static final PropertyMap nasgenmap$; 55 56 /** 57 * Constructor called by Nasgen generated code, no membercount, use the default map. 58 * Creates builtin functions only. 59 * 60 * @param name name of function 61 * @param invokeHandle handle for invocation 62 * @param specs specialized versions of this method, if available, null otherwise 63 */ 64 ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) { 65 super(name, invokeHandle, nasgenmap$, null, specs, false, true); 66 init(); 67 } 68 69 /** 70 * Constructor called by Nasgen generated code, no membercount, use the map passed as argument. 71 * Creates builtin functions only. 72 * 73 * @param name name of function 74 * @param invokeHandle handle for invocation 75 * @param map initial property map 76 * @param specs specialized versions of this method, if available, null otherwise 77 */ 78 ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) { 79 super(name, invokeHandle, map.addAll(nasgenmap$), null, specs, false, true); 80 init(); 81 } 82 83 /** 84 * Constructor called by Global.newScriptFunction (runtime). 85 * 86 * @param name name of function 87 * @param methodHandle handle for invocation 88 * @param scope scope object 89 * @param specs specialized versions of this method, if available, null otherwise 90 * @param strict are we in strict mode 91 * @param builtin is this a built-in function 92 */ 93 ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin) { 94 super(name, methodHandle, getMap(strict), scope, specs, strict, builtin); 95 init(); 96 } 97 98 /** 99 * Constructor called by (compiler) generated code for {@link ScriptObject}s. 100 * Code is generated by {@link FunctionObjectCreator} 101 * 102 * @param data static function data 103 * @param methodHandle handle for invocation 104 * @param scope scope object 105 * @param allocator instance constructor for function 106 */ 107 public ScriptFunctionImpl(final ScriptFunctionData data, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle allocator) { 108 super(data, getMap(data.isStrict()), scope); 109 // Set method handles in script data 110 if (data.getInvoker() == null) { 111 data.setMethodHandles(methodHandle, allocator); 112 } 113 init(); 114 } 115 116 static { 117 PropertyMap map = PropertyMap.newMap(ScriptFunctionImpl.class); 118 map = Lookup.newProperty(map, "prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE); 119 map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null); 120 map = Lookup.newProperty(map, "name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null); 121 nasgenmap$ = map; 122 } 123 124 // function object representing TypeErrorThrower 125 private static ScriptFunction typeErrorThrower; 126 127 static synchronized ScriptFunction getTypeErrorThrower() { 128 if (typeErrorThrower == null) { 129 //name handle 130 final ScriptFunctionImpl func = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_SETTER, null, null, false, false); 131 // clear constructor handle... 132 func.setConstructHandle(null); 133 func.setPrototype(UNDEFINED); 134 typeErrorThrower = func; 135 } 136 137 return typeErrorThrower; 138 } 139 140 // add a new property that throws TypeError on get as well as set 141 static synchronized PropertyMap newThrowerProperty(final PropertyMap map, final String name, final int flags) { 142 return map.newProperty(name, flags, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER); 143 } 144 145 // property map for strict mode functions - lazily initialized 146 private static PropertyMap strictmodemap$; 147 148 // Choose the map based on strict mode! 149 private static PropertyMap getMap(final boolean strict) { 150 if (strict) { 151 synchronized (ScriptFunctionImpl.class) { 152 if (strictmodemap$ == null) { 153 // In strict mode, the following properties should throw TypeError 154 strictmodemap$ = nasgenmap$; 155 strictmodemap$ = newThrowerProperty(strictmodemap$, "arguments", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); 156 strictmodemap$ = newThrowerProperty(strictmodemap$, "caller", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); 157 } 158 } 159 return strictmodemap$; 160 } 161 162 return nasgenmap$; 163 } 164 165 // Instance of this class is used as global anonymous function which 166 // serves as Function.prototype object. 167 private static class AnonymousFunction extends ScriptFunctionImpl { 168 private static final PropertyMap nasgenmap$$ = PropertyMap.newMap(AnonymousFunction.class); 169 170 AnonymousFunction() { 171 super("", GlobalFunctions.ANONYMOUS, nasgenmap$$, null); 172 } 173 } 174 175 static ScriptFunctionImpl newAnonymousFunction() { 176 return new AnonymousFunction(); 177 } 178 179 /** 180 * Factory method for non-constructor built-in functions 181 * 182 * @param name function name 183 * @param methodHandle handle for invocation 184 * @param specs specialized versions of function if available, null otherwise 185 * @param strict are we in strict mode 186 * @return new ScriptFunction 187 */ 188 public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict) { 189 final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, strict, true); 190 func.setConstructHandle(null); 191 func.setPrototype(UNDEFINED); 192 193 return func; 194 } 195 196 /** 197 * Factory method for non-constructor built-in functions 198 * 199 * @param name function name 200 * @param methodHandle handle for invocation 201 * @param specs specialized versions of function if available, null otherwise 202 * @return new ScriptFunction 203 */ 204 public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) { 205 return makeFunction(name, methodHandle, specs, false); 206 } 207 208 /** 209 * Factory method for non-constructor built-in functions 210 * 211 * @param name function name 212 * @param methodHandle handle for invocation 213 * @return new ScriptFunction 214 */ 215 public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle) { 216 return makeFunction(name, methodHandle, null); 217 } 218 219 /** 220 * This method is used to create a bound function. See also 221 * {@link NativeFunction#bind(Object, Object...)} method implementation. 222 * 223 * @param thiz this reference to bind 224 * @param args arguments to bind 225 */ 226 @Override 227 public ScriptFunction makeBoundFunction(final Object thiz, final Object[] args) { 228 Object[] allArgs = args; 229 230 if (allArgs == null) { 231 allArgs = ScriptRuntime.EMPTY_ARRAY; 232 } 233 234 final Object boundThiz = convertThisObject(thiz); 235 final MethodHandle boundMethod = MH.insertArguments(BOUND_FUNCTION, 0, this, boundThiz, allArgs); 236 final ScriptFunction boundFunc = makeFunction("", boundMethod, null, true); 237 238 MethodHandle consHandle = this.getConstructHandle(); 239 240 if (consHandle != null) { 241 consHandle = MH.insertArguments(BOUND_CONSTRUCTOR, 0, this, allArgs); 242 } 243 244 boundFunc.setConstructHandle(consHandle); 245 int newArity = this.getArity(); 246 if (newArity != -1) { 247 newArity -= Math.min(newArity, allArgs.length); 248 } 249 boundFunc.setArity(newArity); 250 251 return boundFunc; 252 } 253 254 @SuppressWarnings("unused") 255 private static Object boundFunction(final ScriptFunction wrapped, final Object boundThiz, final Object[] boundArgs, final Object thiz, final Object[] args) { 256 final Object[] allArgs = new Object[boundArgs.length + args.length]; 257 258 System.arraycopy(boundArgs, 0, allArgs, 0, boundArgs.length); 259 System.arraycopy(args, 0, allArgs, boundArgs.length, args.length); 260 261 return ScriptRuntime.apply(wrapped, boundThiz, allArgs); 262 } 263 264 @SuppressWarnings("unused") 265 private static Object boundConstructor(final ScriptFunction wrapped, final Object[] boundArgs, final Object thiz, final Object[] args) { 266 final Object[] allArgs = new Object[boundArgs.length + args.length]; 267 System.arraycopy(boundArgs, 0, allArgs, 0, boundArgs.length); 268 System.arraycopy(args, 0, allArgs, boundArgs.length, args.length); 269 270 return ScriptRuntime.construct(wrapped, allArgs); 271 } 272 273 // return Object.prototype - used by "allocate" 274 @Override 275 protected final ScriptObject getObjectPrototype() { 276 return Global.objectPrototype(); 277 } 278 279 // Internals below.. 280 private void init() { 281 this.setProto(Global.instance().getFunctionPrototype()); 282 this.setPrototype(new PrototypeObject(this)); 283 284 if (isStrict()) { 285 final ScriptFunction func = getTypeErrorThrower(); 286 // We have to fill user accessor functions late as these are stored 287 // in this object rather than in the PropertyMap of this object. 288 setUserAccessors("arguments", func, func); 289 setUserAccessors("caller", func, func); 290 } 291 } 292 293 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 294 try { 295 return MethodHandles.lookup().findStatic(ScriptFunctionImpl.class, name, MH.type(rtype, types)); 296 } catch (final NoSuchMethodException | IllegalAccessException e) { 297 throw new MethodHandleFactory.LookupException(e); 298 } 299 } 300 }