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.codegen.objects; 27 28 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; 29 import static jdk.nashorn.internal.codegen.Compiler.SCRIPTFUNCTION_IMPL_OBJECT; 30 import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; 31 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; 32 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; 33 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; 34 35 import java.lang.invoke.MethodHandle; 36 import java.util.ArrayList; 37 import java.util.EnumSet; 38 39 import jdk.nashorn.internal.codegen.CodeGenerator; 40 import jdk.nashorn.internal.codegen.FunctionSignature; 41 import jdk.nashorn.internal.codegen.MethodEmitter; 42 import jdk.nashorn.internal.ir.FunctionNode; 43 import jdk.nashorn.internal.ir.IdentNode; 44 import jdk.nashorn.internal.ir.Symbol; 45 import jdk.nashorn.internal.parser.Token; 46 import jdk.nashorn.internal.parser.TokenType; 47 import jdk.nashorn.internal.runtime.PropertyMap; 48 import jdk.nashorn.internal.runtime.ScriptFunction; 49 import jdk.nashorn.internal.runtime.ScriptObject; 50 import jdk.nashorn.internal.runtime.Source; 51 52 /** 53 * Analyze a function object's characteristics for appropriate code 54 * generation. This generates code for the instantiation of ScriptFunctions. 55 */ 56 public class FunctionObjectCreator extends ObjectCreator { 57 58 private final FunctionNode functionNode; 59 60 /** 61 * Constructor 62 * 63 * @param codegen the code generator 64 * @param functionNode the function node to turn into a ScriptFunction implementation 65 */ 66 public FunctionObjectCreator(final CodeGenerator codegen, final FunctionNode functionNode) { 67 super(codegen, new ArrayList<String>(), new ArrayList<Symbol>(), false, false); 68 this.functionNode = functionNode; 69 } 70 71 private void loadHandle(final MethodEmitter method, final String signature) { 72 method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function 73 } 74 75 /** 76 * Emit code for creating the object 77 * 78 * @param method the method emitter 79 */ 80 @Override 81 public void makeObject(final MethodEmitter method) { 82 makeMap(); 83 84 final IdentNode identNode = functionNode.getIdent(); 85 final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); 86 final long firstToken = functionNode.getFirstToken(); 87 final long lastToken = functionNode.getLastToken(); 88 final int position = Token.descPosition(firstToken); 89 final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken); 90 final long token = Token.toDesc(TokenType.FUNCTION, position, length); 91 92 /* 93 * Instantiate the function object, must be referred to by name as 94 * class is not available at compile time 95 */ 96 method._new(SCRIPTFUNCTION_IMPL_OBJECT).dup(); 97 method.load(functionNode.isAnonymous() ? "" : identNode.getName()); 98 loadHandle(method, signature); 99 if(functionNode.needsParentScope()) { 100 method.loadScope(); 101 } else { 102 method.loadNull(); 103 } 104 method.getStatic(compileUnit.getUnitClassName(), SOURCE.tag(), SOURCE.descriptor()); 105 method.load(token); 106 method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); 107 108 /* 109 * Emit code for the correct property map for the object 110 */ 111 loadMap(method); 112 113 /* 114 * Invoke the constructor 115 */ 116 method.load(functionNode.needsCallee()); 117 method.load(functionNode.isStrictMode()); 118 method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_OBJECT, 119 String.class, 120 MethodHandle.class, 121 ScriptObject.class, 122 Source.class, 123 long.class, 124 MethodHandle.class, 125 PropertyMap.class, 126 boolean.class, 127 boolean.class)); 128 129 130 if (functionNode.isVarArg()) { 131 method.dup(); 132 method.load(functionNode.getParameters().size()); 133 method.invoke(ScriptFunction.SET_ARITY); 134 } 135 } 136 }