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.runtime; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodType; 30 import java.util.Collection; 31 import java.util.List; 32 33 /** 34 * This is a subclass that represents a script function that may not be regenerated. 35 * This is used for example for bound functions and builtins. 36 */ 37 final class FinalScriptFunctionData extends ScriptFunctionData { 38 39 // documentation key for this function, may be null 40 private String docKey; 41 42 private static final long serialVersionUID = -930632846167768864L; 43 44 /** 45 * Constructor - used for bind 46 * 47 * @param name name 48 * @param arity arity 49 * @param functions precompiled code 50 * @param flags {@link ScriptFunctionData} flags 51 */ 52 FinalScriptFunctionData(final String name, final int arity, final List<CompiledFunction> functions, final int flags) { 53 super(name, arity, flags); 54 code.addAll(functions); 55 assert !needsCallee(); 56 } 57 58 /** 59 * Constructor - used from ScriptFunction. This assumes that we have code already for the 60 * method (typically a native method) and possibly specializations. 61 * 62 * @param name name 63 * @param mh method handle for generic version of method 64 * @param specs specializations 65 * @param flags {@link ScriptFunctionData} flags 66 */ 67 FinalScriptFunctionData(final String name, final MethodHandle mh, final Specialization[] specs, final int flags) { 68 super(name, methodHandleArity(mh), flags); 69 70 addInvoker(mh); 71 if (specs != null) { 72 for (final Specialization spec : specs) { 73 addInvoker(spec.getMethodHandle(), spec); 74 } 75 } 76 } 77 78 @Override 79 String getDocumentationKey() { 80 return docKey; 81 } 82 83 @Override 84 void setDocumentationKey(final String docKey) { 85 this.docKey = docKey; 86 } 87 88 @Override 89 String getDocumentation() { 90 final String doc = docKey != null? 91 FunctionDocumentation.getDoc(docKey) : null; 92 return doc != null? doc : super.getDocumentation(); 93 } 94 95 @Override 96 protected boolean needsCallee() { 97 final boolean needsCallee = code.getFirst().needsCallee(); 98 assert allNeedCallee(needsCallee); 99 return needsCallee; 100 } 101 102 private boolean allNeedCallee(final boolean needCallee) { 103 for (final CompiledFunction inv : code) { 104 if(inv.needsCallee() != needCallee) { 105 return false; 106 } 107 } 108 return true; 109 } 110 111 @Override 112 CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden, final boolean linkLogicOkay) { 113 assert isValidCallSite(callSiteType) : callSiteType; 114 115 CompiledFunction best = null; 116 for (final CompiledFunction candidate: code) { 117 if (!linkLogicOkay && candidate.hasLinkLogic()) { 118 // Skip! Version with no link logic is desired, but this one has link logic! 119 continue; 120 } 121 122 if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) { 123 best = candidate; 124 } 125 } 126 127 return best; 128 } 129 130 @Override 131 MethodType getGenericType() { 132 // We need to ask the code for its generic type. We can't just rely on this function data's arity, as it's not 133 // actually correct for lots of built-ins. E.g. ECMAScript 5.1 section 15.5.3.2 prescribes that 134 // Script.fromCharCode([char0[, char1[, ...]]]) has a declared arity of 1 even though it's a variable arity 135 // method. 136 int max = 0; 137 for(final CompiledFunction fn: code) { 138 final MethodType t = fn.type(); 139 if(ScriptFunctionData.isVarArg(t)) { 140 // 2 for (callee, this, args[]) 141 return MethodType.genericMethodType(2, true); 142 } 143 final int paramCount = t.parameterCount() - (ScriptFunctionData.needsCallee(t) ? 1 : 0); 144 if(paramCount > max) { 145 max = paramCount; 146 } 147 } 148 // +1 for callee 149 return MethodType.genericMethodType(max + 1); 150 } 151 152 private CompiledFunction addInvoker(final MethodHandle mh, final Specialization specialization) { 153 assert !needsCallee(mh); 154 155 final CompiledFunction invoker; 156 if (isConstructor(mh)) { 157 // only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor 158 // is too conservative a check. However, isConstructor(mh) always implies isConstructor param 159 assert isConstructor(); 160 invoker = CompiledFunction.createBuiltInConstructor(mh); 161 } else { 162 invoker = new CompiledFunction(mh, null, specialization); 163 } 164 code.add(invoker); 165 166 return invoker; 167 } 168 169 private CompiledFunction addInvoker(final MethodHandle mh) { 170 return addInvoker(mh, null); 171 } 172 173 private static int methodHandleArity(final MethodHandle mh) { 174 if (isVarArg(mh)) { 175 return MAX_ARITY; 176 } 177 178 //drop self, callee and boolean constructor flag to get real arity 179 return mh.type().parameterCount() - 1 - (needsCallee(mh) ? 1 : 0) - (isConstructor(mh) ? 1 : 0); 180 } 181 182 private static boolean isConstructor(final MethodHandle mh) { 183 return mh.type().parameterCount() >= 1 && mh.type().parameterType(0) == boolean.class; 184 } 185 186 }