Tue, 12 Mar 2013 15:30:53 +0100
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
Reviewed-by: attila, jlaskey
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 package jdk.nashorn.internal.runtime;
27 import java.lang.invoke.MethodHandle;
28 import java.lang.invoke.MethodType;
30 import jdk.nashorn.internal.codegen.types.Type;
32 /**
33 * An version of a JavaScript function, native or JavaScript.
34 * Supports lazily generating a constructor version of the invocation.
35 */
36 final class CompiledFunction implements Comparable<CompiledFunction> {
38 private final MethodHandle invoker;
39 private MethodHandle constructor;
41 CompiledFunction(final MethodHandle invoker) {
42 this(invoker, null);
43 }
45 CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
46 this.invoker = invoker;
47 this.constructor = constructor; //isConstructor
48 }
50 @Override
51 public String toString() {
52 return "<invoker=" + invoker + " ctor=" + constructor + ">";
53 }
55 MethodHandle getInvoker() {
56 return invoker;
57 }
59 MethodHandle getConstructor() {
60 return constructor;
61 }
63 void setConstructor(final MethodHandle constructor) {
64 this.constructor = constructor;
65 }
67 boolean hasConstructor() {
68 return constructor != null;
69 }
71 MethodType type() {
72 return invoker.type();
73 }
75 @Override
76 public int compareTo(final CompiledFunction o) {
77 return weight() - o.weight();
78 }
80 private int weight() {
81 return weight(type());
82 }
84 private static int weight(final MethodType type) {
85 if (isVarArgsType(type)) {
86 return Integer.MAX_VALUE; //if there is a varargs it should be the heavist and last fallback
87 }
89 int weight = Type.typeFor(type.returnType()).getWeight();
90 for (final Class<?> paramType : type.parameterArray()) {
91 final int pweight = Type.typeFor(paramType).getWeight();
92 weight += pweight;
93 }
94 return weight;
95 }
97 private static boolean isVarArgsType(final MethodType type) {
98 assert type.parameterCount() >= 1 : type;
99 return type.parameterType(type.parameterCount() - 1) == Object[].class;
100 }
102 boolean moreGenericThan(final CompiledFunction o) {
103 return weight() > o.weight();
104 }
106 boolean moreGenericThan(final MethodType type) {
107 return weight() > weight(type);
108 }
110 /**
111 * Check whether a given method descriptor is compatible with this invocation.
112 * It is compatible if the types are narrower than the invocation type so that
113 * a semantically equivalent linkage can be performed.
114 *
115 * @param typesc
116 * @return
117 */
118 boolean typeCompatible(final MethodType type) {
119 final Class<?>[] wantedParams = type.parameterArray();
120 final Class<?>[] existingParams = type().parameterArray();
122 //if we are not examining a varargs type, the number of parameters must be the same
123 if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
124 return false;
125 }
127 //we only go as far as the shortest array. the only chance to make this work if
128 //parameters lengths do not match is if our type ends with a varargs argument.
129 //then every trailing parameter in the given callsite can be folded into it, making
130 //us compatible (albeit slower than a direct specialization)
131 final int lastParamIndex = Math.min(wantedParams.length, existingParams.length);
132 for (int i = 0; i < lastParamIndex; i++) {
133 final Type w = Type.typeFor(wantedParams[i]);
134 final Type e = Type.typeFor(existingParams[i]);
136 //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
137 //we also currently don't support boolean as a javascript function callsite type.
138 //it will always box.
139 if (w.isBoolean()) {
140 return false;
141 }
143 //This callsite type has a vararg here. it will swallow all remaining args.
144 //for consistency, check that it's the last argument
145 if (e.isArray()) {
146 return true;
147 }
149 //Our arguments must be at least as wide as the wanted one, if not wider
150 if (Type.widest(w, e) != e) {
151 //e.g. this invocation takes double and callsite says "object". reject. won't fit
152 //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine
153 return false;
154 }
155 }
157 return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
158 }
162 }