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