1 /* 2 * Copyright (c) 2010, 2014, 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; 27 28 import java.lang.invoke.MethodType; 29 import java.util.Arrays; 30 import java.util.NoSuchElementException; 31 import jdk.nashorn.internal.codegen.types.Type; 32 import jdk.nashorn.internal.ir.FunctionNode; 33 import jdk.nashorn.internal.runtime.ScriptFunction; 34 35 /** 36 * A tuple containing function id, parameter types, return type and needsCallee flag. 37 */ 38 public final class TypeMap { 39 private final int functionNodeId; 40 private final Type[] paramTypes; 41 private final Type returnType; 42 private final boolean needsCallee; 43 44 /** 45 * Constructor 46 * @param functionNodeId function node id 47 * @param type method type found at runtime corresponding to parameter guess 48 * @param needsCallee does the function using this type map need a callee 49 */ 50 public TypeMap(final int functionNodeId, final MethodType type, final boolean needsCallee) { 51 final Type[] types = new Type[type.parameterCount()]; 52 int pos = 0; 53 for (final Class<?> p : type.parameterArray()) { 54 types[pos++] = Type.typeFor(p); 55 } 56 57 this.functionNodeId = functionNodeId; 58 this.paramTypes = types; 59 this.returnType = Type.typeFor(type.returnType()); 60 this.needsCallee = needsCallee; 61 } 62 63 /** 64 * Returns the array of parameter types for a particular function node 65 * @param functionNodeId the ID of the function node 66 * @return an array of parameter types 67 * @throws NoSuchElementException if the type map has no mapping for the requested function 68 */ 69 public Type[] getParameterTypes(final int functionNodeId) { 70 assert this.functionNodeId == functionNodeId; 71 return paramTypes.clone(); 72 } 73 74 MethodType getCallSiteType(final FunctionNode functionNode) { 75 assert this.functionNodeId == functionNode.getId(); 76 final Type[] types = paramTypes; 77 MethodType mt = MethodType.methodType(returnType.getTypeClass()); 78 if (needsCallee) { 79 mt = mt.appendParameterTypes(ScriptFunction.class); 80 } 81 82 mt = mt.appendParameterTypes(Object.class); //this 83 84 for (final Type type : types) { 85 if (type == null) { 86 return null; // not all parameter information is supplied 87 } 88 mt = mt.appendParameterTypes(type.getTypeClass()); 89 } 90 91 return mt; 92 } 93 94 /** 95 * Does the function using this TypeMap need a callee argument. This is used 96 * to compute correct param index offsets in {@link jdk.nashorn.internal.codegen.ApplySpecialization} 97 * @return true if a callee is needed, false otherwise 98 */ 99 public boolean needsCallee() { 100 return needsCallee; 101 } 102 103 /** 104 * Get the parameter type for this parameter position, or 105 * null if now known 106 * @param functionNode functionNode 107 * @param pos position 108 * @return parameter type for this callsite if known 109 */ 110 Type get(final FunctionNode functionNode, final int pos) { 111 assert this.functionNodeId == functionNode.getId(); 112 final Type[] types = paramTypes; 113 assert types == null || pos < types.length : "fn = " + functionNode.getId() + " " + "types=" + Arrays.toString(types) + " || pos=" + pos + " >= length=" + types.length + " in " + this; 114 if (types != null && pos < types.length) { 115 return types[pos]; 116 } 117 return null; 118 } 119 120 /** 121 * Get the return type required for the call site we're compiling for. This only determines 122 * whether object return type is required or not. 123 * @return Type.OBJECT for call sites with object return types, Type.UNKNOWN for everything else 124 */ 125 Type getReturnType() { 126 return returnType.isObject() ? Type.OBJECT : Type.UNKNOWN; 127 } 128 129 @Override 130 public String toString() { 131 return toString(""); 132 } 133 134 String toString(final String prefix) { 135 final StringBuilder sb = new StringBuilder(); 136 137 final int id = functionNodeId; 138 sb.append(prefix).append('\t'); 139 sb.append("function ").append(id).append('\n'); 140 sb.append(prefix).append("\t\tparamTypes="); 141 sb.append(Arrays.toString(paramTypes)); 142 sb.append('\n'); 143 sb.append(prefix).append("\t\treturnType="); 144 final Type ret = returnType; 145 sb.append(ret == null ? "N/A" : ret); 146 sb.append('\n'); 147 148 return sb.toString(); 149 } 150 }