1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java Sat Aug 09 11:11:13 2014 +0200
1.3 @@ -0,0 +1,1646 @@
1.4 +/*
1.5 + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.lang.invoke;
1.30 +
1.31 +import java.lang.annotation.*;
1.32 +import java.lang.reflect.Method;
1.33 +import java.util.Map;
1.34 +import java.util.List;
1.35 +import java.util.Arrays;
1.36 +import java.util.ArrayList;
1.37 +import java.util.HashMap;
1.38 +import java.util.concurrent.ConcurrentHashMap;
1.39 +import sun.invoke.util.Wrapper;
1.40 +import static java.lang.invoke.MethodHandleStatics.*;
1.41 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
1.42 +import java.lang.reflect.Field;
1.43 +import java.util.Objects;
1.44 +
1.45 +/**
1.46 + * The symbolic, non-executable form of a method handle's invocation semantics.
1.47 + * It consists of a series of names.
1.48 + * The first N (N=arity) names are parameters,
1.49 + * while any remaining names are temporary values.
1.50 + * Each temporary specifies the application of a function to some arguments.
1.51 + * The functions are method handles, while the arguments are mixes of
1.52 + * constant values and local names.
1.53 + * The result of the lambda is defined as one of the names, often the last one.
1.54 + * <p>
1.55 + * Here is an approximate grammar:
1.56 + * <blockquote><pre>{@code
1.57 + * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
1.58 + * ArgName = "a" N ":" T
1.59 + * TempName = "t" N ":" T "=" Function "(" Argument* ");"
1.60 + * Function = ConstantValue
1.61 + * Argument = NameRef | ConstantValue
1.62 + * Result = NameRef | "void"
1.63 + * NameRef = "a" N | "t" N
1.64 + * N = (any whole number)
1.65 + * T = "L" | "I" | "J" | "F" | "D" | "V"
1.66 + * }</pre></blockquote>
1.67 + * Names are numbered consecutively from left to right starting at zero.
1.68 + * (The letters are merely a taste of syntax sugar.)
1.69 + * Thus, the first temporary (if any) is always numbered N (where N=arity).
1.70 + * Every occurrence of a name reference in an argument list must refer to
1.71 + * a name previously defined within the same lambda.
1.72 + * A lambda has a void result if and only if its result index is -1.
1.73 + * If a temporary has the type "V", it cannot be the subject of a NameRef,
1.74 + * even though possesses a number.
1.75 + * Note that all reference types are erased to "L", which stands for {@code Object}.
1.76 + * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
1.77 + * The other types stand for the usual primitive types.
1.78 + * <p>
1.79 + * Function invocation closely follows the static rules of the Java verifier.
1.80 + * Arguments and return values must exactly match when their "Name" types are
1.81 + * considered.
1.82 + * Conversions are allowed only if they do not change the erased type.
1.83 + * <ul>
1.84 + * <li>L = Object: casts are used freely to convert into and out of reference types
1.85 + * <li>I = int: subword types are forcibly narrowed when passed as arguments (see {@code explicitCastArguments})
1.86 + * <li>J = long: no implicit conversions
1.87 + * <li>F = float: no implicit conversions
1.88 + * <li>D = double: no implicit conversions
1.89 + * <li>V = void: a function result may be void if and only if its Name is of type "V"
1.90 + * </ul>
1.91 + * Although implicit conversions are not allowed, explicit ones can easily be
1.92 + * encoded by using temporary expressions which call type-transformed identity functions.
1.93 + * <p>
1.94 + * Examples:
1.95 + * <blockquote><pre>{@code
1.96 + * (a0:J)=>{ a0 }
1.97 + * == identity(long)
1.98 + * (a0:I)=>{ t1:V = System.out#println(a0); void }
1.99 + * == System.out#println(int)
1.100 + * (a0:L)=>{ t1:V = System.out#println(a0); a0 }
1.101 + * == identity, with printing side-effect
1.102 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
1.103 + * t3:L = BoundMethodHandle#target(a0);
1.104 + * t4:L = MethodHandle#invoke(t3, t2, a1); t4 }
1.105 + * == general invoker for unary insertArgument combination
1.106 + * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
1.107 + * t3:L = MethodHandle#invoke(t2, a1);
1.108 + * t4:L = FilterMethodHandle#target(a0);
1.109 + * t5:L = MethodHandle#invoke(t4, t3); t5 }
1.110 + * == general invoker for unary filterArgument combination
1.111 + * (a0:L, a1:L)=>{ ...(same as previous example)...
1.112 + * t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
1.113 + * == general invoker for unary/unary foldArgument combination
1.114 + * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
1.115 + * == invoker for identity method handle which performs i2l
1.116 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
1.117 + * t3:L = Class#cast(t2,a1); t3 }
1.118 + * == invoker for identity method handle which performs cast
1.119 + * }</pre></blockquote>
1.120 + * <p>
1.121 + * @author John Rose, JSR 292 EG
1.122 + */
1.123 +class LambdaForm {
1.124 + final int arity;
1.125 + final int result;
1.126 + @Stable final Name[] names;
1.127 + final String debugName;
1.128 + MemberName vmentry; // low-level behavior, or null if not yet prepared
1.129 + private boolean isCompiled;
1.130 +
1.131 + // Caches for common structural transforms:
1.132 + LambdaForm[] bindCache;
1.133 +
1.134 + public static final int VOID_RESULT = -1, LAST_RESULT = -2;
1.135 +
1.136 + LambdaForm(String debugName,
1.137 + int arity, Name[] names, int result) {
1.138 + assert(namesOK(arity, names));
1.139 + this.arity = arity;
1.140 + this.result = fixResult(result, names);
1.141 + this.names = names.clone();
1.142 + this.debugName = debugName;
1.143 + normalize();
1.144 + }
1.145 +
1.146 + LambdaForm(String debugName,
1.147 + int arity, Name[] names) {
1.148 + this(debugName,
1.149 + arity, names, LAST_RESULT);
1.150 + }
1.151 +
1.152 + LambdaForm(String debugName,
1.153 + Name[] formals, Name[] temps, Name result) {
1.154 + this(debugName,
1.155 + formals.length, buildNames(formals, temps, result), LAST_RESULT);
1.156 + }
1.157 +
1.158 + private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
1.159 + int arity = formals.length;
1.160 + int length = arity + temps.length + (result == null ? 0 : 1);
1.161 + Name[] names = Arrays.copyOf(formals, length);
1.162 + System.arraycopy(temps, 0, names, arity, temps.length);
1.163 + if (result != null)
1.164 + names[length - 1] = result;
1.165 + return names;
1.166 + }
1.167 +
1.168 + private LambdaForm(String sig) {
1.169 + // Make a blank lambda form, which returns a constant zero or null.
1.170 + // It is used as a template for managing the invocation of similar forms that are non-empty.
1.171 + // Called only from getPreparedForm.
1.172 + assert(isValidSignature(sig));
1.173 + this.arity = signatureArity(sig);
1.174 + this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
1.175 + this.names = buildEmptyNames(arity, sig);
1.176 + this.debugName = "LF.zero";
1.177 + assert(nameRefsAreLegal());
1.178 + assert(isEmpty());
1.179 + assert(sig.equals(basicTypeSignature()));
1.180 + }
1.181 +
1.182 + private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
1.183 + assert(isValidSignature(basicTypeSignature));
1.184 + int resultPos = arity + 1; // skip '_'
1.185 + if (arity < 0 || basicTypeSignature.length() != resultPos+1)
1.186 + throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
1.187 + int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
1.188 + Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
1.189 + for (int i = 0; i < numRes; i++) {
1.190 + names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
1.191 + }
1.192 + return names;
1.193 + }
1.194 +
1.195 + private static int fixResult(int result, Name[] names) {
1.196 + if (result >= 0) {
1.197 + if (names[result].type == 'V')
1.198 + return -1;
1.199 + } else if (result == LAST_RESULT) {
1.200 + return names.length - 1;
1.201 + }
1.202 + return result;
1.203 + }
1.204 +
1.205 + private static boolean namesOK(int arity, Name[] names) {
1.206 + for (int i = 0; i < names.length; i++) {
1.207 + Name n = names[i];
1.208 + assert(n != null) : "n is null";
1.209 + if (i < arity)
1.210 + assert( n.isParam()) : n + " is not param at " + i;
1.211 + else
1.212 + assert(!n.isParam()) : n + " is param at " + i;
1.213 + }
1.214 + return true;
1.215 + }
1.216 +
1.217 + /** Renumber and/or replace params so that they are interned and canonically numbered. */
1.218 + private void normalize() {
1.219 + Name[] oldNames = null;
1.220 + int changesStart = 0;
1.221 + for (int i = 0; i < names.length; i++) {
1.222 + Name n = names[i];
1.223 + if (!n.initIndex(i)) {
1.224 + if (oldNames == null) {
1.225 + oldNames = names.clone();
1.226 + changesStart = i;
1.227 + }
1.228 + names[i] = n.cloneWithIndex(i);
1.229 + }
1.230 + }
1.231 + if (oldNames != null) {
1.232 + int startFixing = arity;
1.233 + if (startFixing <= changesStart)
1.234 + startFixing = changesStart+1;
1.235 + for (int i = startFixing; i < names.length; i++) {
1.236 + Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
1.237 + names[i] = fixed.newIndex(i);
1.238 + }
1.239 + }
1.240 + assert(nameRefsAreLegal());
1.241 + int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
1.242 + boolean needIntern = false;
1.243 + for (int i = 0; i < maxInterned; i++) {
1.244 + Name n = names[i], n2 = internArgument(n);
1.245 + if (n != n2) {
1.246 + names[i] = n2;
1.247 + needIntern = true;
1.248 + }
1.249 + }
1.250 + if (needIntern) {
1.251 + for (int i = arity; i < names.length; i++) {
1.252 + names[i].internArguments();
1.253 + }
1.254 + assert(nameRefsAreLegal());
1.255 + }
1.256 + }
1.257 +
1.258 + /**
1.259 + * Check that all embedded Name references are localizable to this lambda,
1.260 + * and are properly ordered after their corresponding definitions.
1.261 + * <p>
1.262 + * Note that a Name can be local to multiple lambdas, as long as
1.263 + * it possesses the same index in each use site.
1.264 + * This allows Name references to be freely reused to construct
1.265 + * fresh lambdas, without confusion.
1.266 + */
1.267 + private boolean nameRefsAreLegal() {
1.268 + assert(arity >= 0 && arity <= names.length);
1.269 + assert(result >= -1 && result < names.length);
1.270 + // Do all names possess an index consistent with their local definition order?
1.271 + for (int i = 0; i < arity; i++) {
1.272 + Name n = names[i];
1.273 + assert(n.index() == i) : Arrays.asList(n.index(), i);
1.274 + assert(n.isParam());
1.275 + }
1.276 + // Also, do all local name references
1.277 + for (int i = arity; i < names.length; i++) {
1.278 + Name n = names[i];
1.279 + assert(n.index() == i);
1.280 + for (Object arg : n.arguments) {
1.281 + if (arg instanceof Name) {
1.282 + Name n2 = (Name) arg;
1.283 + int i2 = n2.index;
1.284 + assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
1.285 + assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
1.286 + assert(i2 < i); // ref must come after def!
1.287 + }
1.288 + }
1.289 + }
1.290 + return true;
1.291 + }
1.292 +
1.293 + /** Invoke this form on the given arguments. */
1.294 + // final Object invoke(Object... args) throws Throwable {
1.295 + // // NYI: fit this into the fast path?
1.296 + // return interpretWithArguments(args);
1.297 + // }
1.298 +
1.299 + /** Report the return type. */
1.300 + char returnType() {
1.301 + if (result < 0) return 'V';
1.302 + Name n = names[result];
1.303 + return n.type;
1.304 + }
1.305 +
1.306 + /** Report the N-th argument type. */
1.307 + char parameterType(int n) {
1.308 + assert(n < arity);
1.309 + return names[n].type;
1.310 + }
1.311 +
1.312 + /** Report the arity. */
1.313 + int arity() {
1.314 + return arity;
1.315 + }
1.316 +
1.317 + /** Return the method type corresponding to my basic type signature. */
1.318 + MethodType methodType() {
1.319 + return signatureType(basicTypeSignature());
1.320 + }
1.321 + /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */
1.322 + final String basicTypeSignature() {
1.323 + StringBuilder buf = new StringBuilder(arity() + 3);
1.324 + for (int i = 0, a = arity(); i < a; i++)
1.325 + buf.append(parameterType(i));
1.326 + return buf.append('_').append(returnType()).toString();
1.327 + }
1.328 + static int signatureArity(String sig) {
1.329 + assert(isValidSignature(sig));
1.330 + return sig.indexOf('_');
1.331 + }
1.332 + static char signatureReturn(String sig) {
1.333 + return sig.charAt(signatureArity(sig)+1);
1.334 + }
1.335 + static boolean isValidSignature(String sig) {
1.336 + int arity = sig.indexOf('_');
1.337 + if (arity < 0) return false; // must be of the form *_*
1.338 + int siglen = sig.length();
1.339 + if (siglen != arity + 2) return false; // *_X
1.340 + for (int i = 0; i < siglen; i++) {
1.341 + if (i == arity) continue; // skip '_'
1.342 + char c = sig.charAt(i);
1.343 + if (c == 'V')
1.344 + return (i == siglen - 1 && arity == siglen - 2);
1.345 + if (ALL_TYPES.indexOf(c) < 0) return false; // must be [LIJFD]
1.346 + }
1.347 + return true; // [LIJFD]*_[LIJFDV]
1.348 + }
1.349 + static Class<?> typeClass(char t) {
1.350 + switch (t) {
1.351 + case 'I': return int.class;
1.352 + case 'J': return long.class;
1.353 + case 'F': return float.class;
1.354 + case 'D': return double.class;
1.355 + case 'L': return Object.class;
1.356 + case 'V': return void.class;
1.357 + default: assert false;
1.358 + }
1.359 + return null;
1.360 + }
1.361 + static MethodType signatureType(String sig) {
1.362 + Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
1.363 + for (int i = 0; i < ptypes.length; i++)
1.364 + ptypes[i] = typeClass(sig.charAt(i));
1.365 + Class<?> rtype = typeClass(signatureReturn(sig));
1.366 + return MethodType.methodType(rtype, ptypes);
1.367 + }
1.368 +
1.369 + /*
1.370 + * Code generation issues:
1.371 + *
1.372 + * Compiled LFs should be reusable in general.
1.373 + * The biggest issue is how to decide when to pull a name into
1.374 + * the bytecode, versus loading a reified form from the MH data.
1.375 + *
1.376 + * For example, an asType wrapper may require execution of a cast
1.377 + * after a call to a MH. The target type of the cast can be placed
1.378 + * as a constant in the LF itself. This will force the cast type
1.379 + * to be compiled into the bytecodes and native code for the MH.
1.380 + * Or, the target type of the cast can be erased in the LF, and
1.381 + * loaded from the MH data. (Later on, if the MH as a whole is
1.382 + * inlined, the data will flow into the inlined instance of the LF,
1.383 + * as a constant, and the end result will be an optimal cast.)
1.384 + *
1.385 + * This erasure of cast types can be done with any use of
1.386 + * reference types. It can also be done with whole method
1.387 + * handles. Erasing a method handle might leave behind
1.388 + * LF code that executes correctly for any MH of a given
1.389 + * type, and load the required MH from the enclosing MH's data.
1.390 + * Or, the erasure might even erase the expected MT.
1.391 + *
1.392 + * Also, for direct MHs, the MemberName of the target
1.393 + * could be erased, and loaded from the containing direct MH.
1.394 + * As a simple case, a LF for all int-valued non-static
1.395 + * field getters would perform a cast on its input argument
1.396 + * (to non-constant base type derived from the MemberName)
1.397 + * and load an integer value from the input object
1.398 + * (at a non-constant offset also derived from the MemberName).
1.399 + * Such MN-erased LFs would be inlinable back to optimized
1.400 + * code, whenever a constant enclosing DMH is available
1.401 + * to supply a constant MN from its data.
1.402 + *
1.403 + * The main problem here is to keep LFs reasonably generic,
1.404 + * while ensuring that hot spots will inline good instances.
1.405 + * "Reasonably generic" means that we don't end up with
1.406 + * repeated versions of bytecode or machine code that do
1.407 + * not differ in their optimized form. Repeated versions
1.408 + * of machine would have the undesirable overheads of
1.409 + * (a) redundant compilation work and (b) extra I$ pressure.
1.410 + * To control repeated versions, we need to be ready to
1.411 + * erase details from LFs and move them into MH data,
1.412 + * whevener those details are not relevant to significant
1.413 + * optimization. "Significant" means optimization of
1.414 + * code that is actually hot.
1.415 + *
1.416 + * Achieving this may require dynamic splitting of MHs, by replacing
1.417 + * a generic LF with a more specialized one, on the same MH,
1.418 + * if (a) the MH is frequently executed and (b) the MH cannot
1.419 + * be inlined into a containing caller, such as an invokedynamic.
1.420 + *
1.421 + * Compiled LFs that are no longer used should be GC-able.
1.422 + * If they contain non-BCP references, they should be properly
1.423 + * interlinked with the class loader(s) that their embedded types
1.424 + * depend on. This probably means that reusable compiled LFs
1.425 + * will be tabulated (indexed) on relevant class loaders,
1.426 + * or else that the tables that cache them will have weak links.
1.427 + */
1.428 +
1.429 + /**
1.430 + * Make this LF directly executable, as part of a MethodHandle.
1.431 + * Invariant: Every MH which is invoked must prepare its LF
1.432 + * before invocation.
1.433 + * (In principle, the JVM could do this very lazily,
1.434 + * as a sort of pre-invocation linkage step.)
1.435 + */
1.436 + public void prepare() {
1.437 + if (COMPILE_THRESHOLD == 0) {
1.438 + compileToBytecode();
1.439 + }
1.440 + if (this.vmentry != null) {
1.441 + // already prepared (e.g., a primitive DMH invoker form)
1.442 + return;
1.443 + }
1.444 + LambdaForm prep = getPreparedForm(basicTypeSignature());
1.445 + this.vmentry = prep.vmentry;
1.446 + // TO DO: Maybe add invokeGeneric, invokeWithArguments
1.447 + }
1.448 +
1.449 + /** Generate optimizable bytecode for this form. */
1.450 + MemberName compileToBytecode() {
1.451 + MethodType invokerType = methodType();
1.452 + assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
1.453 + if (vmentry != null && isCompiled) {
1.454 + return vmentry; // already compiled somehow
1.455 + }
1.456 + try {
1.457 + vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
1.458 + if (TRACE_INTERPRETER)
1.459 + traceInterpreter("compileToBytecode", this);
1.460 + isCompiled = true;
1.461 + return vmentry;
1.462 + } catch (Error | Exception ex) {
1.463 + throw newInternalError("compileToBytecode", ex);
1.464 + }
1.465 + }
1.466 +
1.467 + private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
1.468 + static {
1.469 + int capacity = 512; // expect many distinct signatures over time
1.470 + float loadFactor = 0.75f; // normal default
1.471 + int writers = 1;
1.472 + PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers);
1.473 + }
1.474 +
1.475 + private static Map<String,LambdaForm> computeInitialPreparedForms() {
1.476 + // Find all predefined invokers and associate them with canonical empty lambda forms.
1.477 + HashMap<String,LambdaForm> forms = new HashMap<>();
1.478 + for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
1.479 + if (!m.isStatic() || !m.isPackage()) continue;
1.480 + MethodType mt = m.getMethodType();
1.481 + if (mt.parameterCount() > 0 &&
1.482 + mt.parameterType(0) == MethodHandle.class &&
1.483 + m.getName().startsWith("interpret_")) {
1.484 + String sig = basicTypeSignature(mt);
1.485 + assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
1.486 + LambdaForm form = new LambdaForm(sig);
1.487 + form.vmentry = m;
1.488 + mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
1.489 + // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
1.490 + forms.put(sig, form);
1.491 + }
1.492 + }
1.493 + //System.out.println("computeInitialPreparedForms => "+forms);
1.494 + return forms;
1.495 + }
1.496 +
1.497 + // Set this false to disable use of the interpret_L methods defined in this file.
1.498 + private static final boolean USE_PREDEFINED_INTERPRET_METHODS = true;
1.499 +
1.500 + // The following are predefined exact invokers. The system must build
1.501 + // a separate invoker for each distinct signature.
1.502 + static Object interpret_L(MethodHandle mh) throws Throwable {
1.503 + Object[] av = {mh};
1.504 + String sig = null;
1.505 + assert(argumentTypesMatch(sig = "L_L", av));
1.506 + Object res = mh.form.interpretWithArguments(av);
1.507 + assert(returnTypesMatch(sig, av, res));
1.508 + return res;
1.509 + }
1.510 + static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
1.511 + Object[] av = {mh, x1};
1.512 + String sig = null;
1.513 + assert(argumentTypesMatch(sig = "LL_L", av));
1.514 + Object res = mh.form.interpretWithArguments(av);
1.515 + assert(returnTypesMatch(sig, av, res));
1.516 + return res;
1.517 + }
1.518 + static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
1.519 + Object[] av = {mh, x1, x2};
1.520 + String sig = null;
1.521 + assert(argumentTypesMatch(sig = "LLL_L", av));
1.522 + Object res = mh.form.interpretWithArguments(av);
1.523 + assert(returnTypesMatch(sig, av, res));
1.524 + return res;
1.525 + }
1.526 + private static LambdaForm getPreparedForm(String sig) {
1.527 + MethodType mtype = signatureType(sig);
1.528 + //LambdaForm prep = PREPARED_FORMS.get(sig);
1.529 + LambdaForm prep = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
1.530 + if (prep != null) return prep;
1.531 + assert(isValidSignature(sig));
1.532 + prep = new LambdaForm(sig);
1.533 + prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
1.534 + //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
1.535 + return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
1.536 + }
1.537 +
1.538 + // The next few routines are called only from assert expressions
1.539 + // They verify that the built-in invokers process the correct raw data types.
1.540 + private static boolean argumentTypesMatch(String sig, Object[] av) {
1.541 + int arity = signatureArity(sig);
1.542 + assert(av.length == arity) : "av.length == arity: av.length=" + av.length + ", arity=" + arity;
1.543 + assert(av[0] instanceof MethodHandle) : "av[0] not instace of MethodHandle: " + av[0];
1.544 + MethodHandle mh = (MethodHandle) av[0];
1.545 + MethodType mt = mh.type();
1.546 + assert(mt.parameterCount() == arity-1);
1.547 + for (int i = 0; i < av.length; i++) {
1.548 + Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
1.549 + assert(valueMatches(sig.charAt(i), pt, av[i]));
1.550 + }
1.551 + return true;
1.552 + }
1.553 + private static boolean valueMatches(char tc, Class<?> type, Object x) {
1.554 + // The following line is needed because (...)void method handles can use non-void invokers
1.555 + if (type == void.class) tc = 'V'; // can drop any kind of value
1.556 + assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
1.557 + switch (tc) {
1.558 + case 'I': assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break;
1.559 + case 'J': assert x instanceof Long : "instanceof Long: " + x; break;
1.560 + case 'F': assert x instanceof Float : "instanceof Float: " + x; break;
1.561 + case 'D': assert x instanceof Double : "instanceof Double: " + x; break;
1.562 + case 'L': assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break;
1.563 + case 'V': break; // allow anything here; will be dropped
1.564 + default: assert(false);
1.565 + }
1.566 + return true;
1.567 + }
1.568 + private static boolean returnTypesMatch(String sig, Object[] av, Object res) {
1.569 + MethodHandle mh = (MethodHandle) av[0];
1.570 + return valueMatches(signatureReturn(sig), mh.type().returnType(), res);
1.571 + }
1.572 + private static boolean checkInt(Class<?> type, Object x) {
1.573 + assert(x instanceof Integer);
1.574 + if (type == int.class) return true;
1.575 + Wrapper w = Wrapper.forBasicType(type);
1.576 + assert(w.isSubwordOrInt());
1.577 + Object x1 = Wrapper.INT.wrap(w.wrap(x));
1.578 + return x.equals(x1);
1.579 + }
1.580 + private static boolean checkRef(Class<?> type, Object x) {
1.581 + assert(!type.isPrimitive());
1.582 + if (x == null) return true;
1.583 + if (type.isInterface()) return true;
1.584 + return type.isInstance(x);
1.585 + }
1.586 +
1.587 + /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
1.588 + private static final int COMPILE_THRESHOLD;
1.589 + static {
1.590 + if (MethodHandleStatics.COMPILE_THRESHOLD != null)
1.591 + COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
1.592 + else
1.593 + COMPILE_THRESHOLD = 30; // default value
1.594 + }
1.595 + private int invocationCounter = 0;
1.596 +
1.597 + @Hidden
1.598 + @DontInline
1.599 + /** Interpretively invoke this form on the given arguments. */
1.600 + Object interpretWithArguments(Object... argumentValues) throws Throwable {
1.601 + if (TRACE_INTERPRETER)
1.602 + return interpretWithArgumentsTracing(argumentValues);
1.603 + checkInvocationCounter();
1.604 + assert(arityCheck(argumentValues));
1.605 + Object[] values = Arrays.copyOf(argumentValues, names.length);
1.606 + for (int i = argumentValues.length; i < values.length; i++) {
1.607 + values[i] = interpretName(names[i], values);
1.608 + }
1.609 + return (result < 0) ? null : values[result];
1.610 + }
1.611 +
1.612 + @Hidden
1.613 + @DontInline
1.614 + /** Evaluate a single Name within this form, applying its function to its arguments. */
1.615 + Object interpretName(Name name, Object[] values) throws Throwable {
1.616 + if (TRACE_INTERPRETER)
1.617 + traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
1.618 + Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
1.619 + for (int i = 0; i < arguments.length; i++) {
1.620 + Object a = arguments[i];
1.621 + if (a instanceof Name) {
1.622 + int i2 = ((Name)a).index();
1.623 + assert(names[i2] == a);
1.624 + a = values[i2];
1.625 + arguments[i] = a;
1.626 + }
1.627 + }
1.628 + return name.function.invokeWithArguments(arguments);
1.629 + }
1.630 +
1.631 + private void checkInvocationCounter() {
1.632 + if (COMPILE_THRESHOLD != 0 &&
1.633 + invocationCounter < COMPILE_THRESHOLD) {
1.634 + invocationCounter++; // benign race
1.635 + if (invocationCounter >= COMPILE_THRESHOLD) {
1.636 + // Replace vmentry with a bytecode version of this LF.
1.637 + compileToBytecode();
1.638 + }
1.639 + }
1.640 + }
1.641 + Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
1.642 + traceInterpreter("[ interpretWithArguments", this, argumentValues);
1.643 + if (invocationCounter < COMPILE_THRESHOLD) {
1.644 + int ctr = invocationCounter++; // benign race
1.645 + traceInterpreter("| invocationCounter", ctr);
1.646 + if (invocationCounter >= COMPILE_THRESHOLD) {
1.647 + compileToBytecode();
1.648 + }
1.649 + }
1.650 + Object rval;
1.651 + try {
1.652 + assert(arityCheck(argumentValues));
1.653 + Object[] values = Arrays.copyOf(argumentValues, names.length);
1.654 + for (int i = argumentValues.length; i < values.length; i++) {
1.655 + values[i] = interpretName(names[i], values);
1.656 + }
1.657 + rval = (result < 0) ? null : values[result];
1.658 + } catch (Throwable ex) {
1.659 + traceInterpreter("] throw =>", ex);
1.660 + throw ex;
1.661 + }
1.662 + traceInterpreter("] return =>", rval);
1.663 + return rval;
1.664 + }
1.665 +
1.666 + //** This transform is applied (statically) to every name.function. */
1.667 + /*
1.668 + private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
1.669 + MethodType mt = mh.type();
1.670 + if (mt.hasPrimitives()) {
1.671 + mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
1.672 + for (int i = 0; i < mt.parameterCount(); i++) {
1.673 + mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
1.674 + }
1.675 + mh = MethodHandles.explicitCastArguments(mh, mt);
1.676 + }
1.677 + return mh;
1.678 + }
1.679 + private static Class<?> eraseSubwordType(Class<?> type) {
1.680 + if (!type.isPrimitive()) return type;
1.681 + if (type == int.class) return type;
1.682 + Wrapper w = Wrapper.forPrimitiveType(type);
1.683 + if (w.isSubwordOrInt()) return int.class;
1.684 + return type;
1.685 + }
1.686 + */
1.687 +
1.688 + static void traceInterpreter(String event, Object obj, Object... args) {
1.689 + if (TRACE_INTERPRETER) {
1.690 + System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
1.691 + }
1.692 + }
1.693 + static void traceInterpreter(String event, Object obj) {
1.694 + traceInterpreter(event, obj, (Object[])null);
1.695 + }
1.696 + private boolean arityCheck(Object[] argumentValues) {
1.697 + assert(argumentValues.length == arity) : arity+"!="+Arrays.asList(argumentValues)+".length";
1.698 + // also check that the leading (receiver) argument is somehow bound to this LF:
1.699 + assert(argumentValues[0] instanceof MethodHandle) : "not MH: " + argumentValues[0];
1.700 + assert(((MethodHandle)argumentValues[0]).internalForm() == this);
1.701 + // note: argument #0 could also be an interface wrapper, in the future
1.702 + return true;
1.703 + }
1.704 +
1.705 + private boolean isEmpty() {
1.706 + if (result < 0)
1.707 + return (names.length == arity);
1.708 + else if (result == arity && names.length == arity + 1)
1.709 + return names[arity].isConstantZero();
1.710 + else
1.711 + return false;
1.712 + }
1.713 +
1.714 + public String toString() {
1.715 + StringBuilder buf = new StringBuilder(debugName+"=Lambda(");
1.716 + for (int i = 0; i < names.length; i++) {
1.717 + if (i == arity) buf.append(")=>{");
1.718 + Name n = names[i];
1.719 + if (i >= arity) buf.append("\n ");
1.720 + buf.append(n);
1.721 + if (i < arity) {
1.722 + if (i+1 < arity) buf.append(",");
1.723 + continue;
1.724 + }
1.725 + buf.append("=").append(n.exprString());
1.726 + buf.append(";");
1.727 + }
1.728 + buf.append(result < 0 ? "void" : names[result]).append("}");
1.729 + if (TRACE_INTERPRETER) {
1.730 + // Extra verbosity:
1.731 + buf.append(":").append(basicTypeSignature());
1.732 + buf.append("/").append(vmentry);
1.733 + }
1.734 + return buf.toString();
1.735 + }
1.736 +
1.737 + /**
1.738 + * Apply immediate binding for a Name in this form indicated by its position relative to the form.
1.739 + * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
1.740 + * accepted as valid.
1.741 + */
1.742 + LambdaForm bindImmediate(int pos, char basicType, Object value) {
1.743 + // must be an argument, and the types must match
1.744 + assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
1.745 +
1.746 + int arity2 = arity - 1;
1.747 + Name[] names2 = new Name[names.length - 1];
1.748 + for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
1.749 + Name n = names[r];
1.750 + if (n.isParam()) {
1.751 + if (n.index == pos) {
1.752 + // do not copy over the argument that is to be replaced with a literal,
1.753 + // but adjust the write index
1.754 + --w;
1.755 + } else {
1.756 + names2[w] = new Name(w, n.type);
1.757 + }
1.758 + } else {
1.759 + Object[] arguments2 = new Object[n.arguments.length];
1.760 + for (int i = 0; i < n.arguments.length; ++i) {
1.761 + Object arg = n.arguments[i];
1.762 + if (arg instanceof Name) {
1.763 + int ni = ((Name) arg).index;
1.764 + if (ni == pos) {
1.765 + arguments2[i] = value;
1.766 + } else if (ni < pos) {
1.767 + // replacement position not yet passed
1.768 + arguments2[i] = names2[ni];
1.769 + } else {
1.770 + // replacement position passed
1.771 + arguments2[i] = names2[ni - 1];
1.772 + }
1.773 + } else {
1.774 + arguments2[i] = arg;
1.775 + }
1.776 + }
1.777 + names2[w] = new Name(n.function, arguments2);
1.778 + names2[w].initIndex(w);
1.779 + }
1.780 + }
1.781 +
1.782 + int result2 = result == -1 ? -1 : result - 1;
1.783 + return new LambdaForm(debugName, arity2, names2, result2);
1.784 + }
1.785 +
1.786 + LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
1.787 + Name name = names[namePos];
1.788 + BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
1.789 + return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
1.790 + }
1.791 + LambdaForm bind(Name name, Name binding,
1.792 + BoundMethodHandle.SpeciesData oldData,
1.793 + BoundMethodHandle.SpeciesData newData) {
1.794 + int pos = name.index;
1.795 + assert(name.isParam());
1.796 + assert(!binding.isParam());
1.797 + assert(name.type == binding.type);
1.798 + assert(0 <= pos && pos < arity && names[pos] == name);
1.799 + assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
1.800 + assert(oldData.getters.length == newData.getters.length-1);
1.801 + if (bindCache != null) {
1.802 + LambdaForm form = bindCache[pos];
1.803 + if (form != null) {
1.804 + assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
1.805 + return form;
1.806 + }
1.807 + } else {
1.808 + bindCache = new LambdaForm[arity];
1.809 + }
1.810 + assert(nameRefsAreLegal());
1.811 + int arity2 = arity-1;
1.812 + Name[] names2 = names.clone();
1.813 + names2[pos] = binding; // we might move this in a moment
1.814 +
1.815 + // The newly created LF will run with a different BMH.
1.816 + // Switch over any pre-existing BMH field references to the new BMH class.
1.817 + int firstOldRef = -1;
1.818 + for (int i = 0; i < names2.length; i++) {
1.819 + Name n = names[i];
1.820 + if (n.function != null &&
1.821 + n.function.memberDeclaringClassOrNull() == oldData.clazz) {
1.822 + MethodHandle oldGetter = n.function.resolvedHandle;
1.823 + MethodHandle newGetter = null;
1.824 + for (int j = 0; j < oldData.getters.length; j++) {
1.825 + if (oldGetter == oldData.getters[j])
1.826 + newGetter = newData.getters[j];
1.827 + }
1.828 + if (newGetter != null) {
1.829 + if (firstOldRef < 0) firstOldRef = i;
1.830 + Name n2 = new Name(newGetter, n.arguments);
1.831 + names2[i] = n2;
1.832 + }
1.833 + }
1.834 + }
1.835 +
1.836 + // Walk over the new list of names once, in forward order.
1.837 + // Replace references to 'name' with 'binding'.
1.838 + // Replace data structure references to the old BMH species with the new.
1.839 + // This might cause a ripple effect, but it will settle in one pass.
1.840 + assert(firstOldRef < 0 || firstOldRef > pos);
1.841 + for (int i = pos+1; i < names2.length; i++) {
1.842 + if (i <= arity2) continue;
1.843 + names2[i] = names2[i].replaceNames(names, names2, pos, i);
1.844 + }
1.845 +
1.846 + // (a0, a1, name=a2, a3, a4) => (a0, a1, a3, a4, binding)
1.847 + int insPos = pos;
1.848 + for (; insPos+1 < names2.length; insPos++) {
1.849 + Name n = names2[insPos+1];
1.850 + if (n.isSiblingBindingBefore(binding)) {
1.851 + names2[insPos] = n;
1.852 + } else {
1.853 + break;
1.854 + }
1.855 + }
1.856 + names2[insPos] = binding;
1.857 +
1.858 + // Since we moved some stuff, maybe update the result reference:
1.859 + int result2 = result;
1.860 + if (result2 == pos)
1.861 + result2 = insPos;
1.862 + else if (result2 > pos && result2 <= insPos)
1.863 + result2 -= 1;
1.864 +
1.865 + return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2);
1.866 + }
1.867 +
1.868 + boolean contains(Name name) {
1.869 + int pos = name.index();
1.870 + if (pos >= 0) {
1.871 + return pos < names.length && name.equals(names[pos]);
1.872 + }
1.873 + for (int i = arity; i < names.length; i++) {
1.874 + if (name.equals(names[i]))
1.875 + return true;
1.876 + }
1.877 + return false;
1.878 + }
1.879 +
1.880 + LambdaForm addArguments(int pos, char... types) {
1.881 + assert(pos <= arity);
1.882 + int length = names.length;
1.883 + int inTypes = types.length;
1.884 + Name[] names2 = Arrays.copyOf(names, length + inTypes);
1.885 + int arity2 = arity + inTypes;
1.886 + int result2 = result;
1.887 + if (result2 >= arity)
1.888 + result2 += inTypes;
1.889 + // names array has MH in slot 0; skip it.
1.890 + int argpos = pos + 1;
1.891 + // Note: The LF constructor will rename names2[argpos...].
1.892 + // Make space for new arguments (shift temporaries).
1.893 + System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos);
1.894 + for (int i = 0; i < inTypes; i++) {
1.895 + names2[argpos + i] = new Name(types[i]);
1.896 + }
1.897 + return new LambdaForm(debugName, arity2, names2, result2);
1.898 + }
1.899 +
1.900 + LambdaForm addArguments(int pos, List<Class<?>> types) {
1.901 + char[] basicTypes = new char[types.size()];
1.902 + for (int i = 0; i < basicTypes.length; i++)
1.903 + basicTypes[i] = basicType(types.get(i));
1.904 + return addArguments(pos, basicTypes);
1.905 + }
1.906 +
1.907 + LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
1.908 + // Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg.
1.909 + // The types are the types of the new (incoming) arguments.
1.910 + int length = names.length;
1.911 + int inTypes = types.length;
1.912 + int outArgs = reorder.length;
1.913 + assert(skip+outArgs == arity);
1.914 + assert(permutedTypesMatch(reorder, types, names, skip));
1.915 + int pos = 0;
1.916 + // skip trivial first part of reordering:
1.917 + while (pos < outArgs && reorder[pos] == pos) pos += 1;
1.918 + Name[] names2 = new Name[length - outArgs + inTypes];
1.919 + System.arraycopy(names, 0, names2, 0, skip+pos);
1.920 + // copy the body:
1.921 + int bodyLength = length - arity;
1.922 + System.arraycopy(names, skip+outArgs, names2, skip+inTypes, bodyLength);
1.923 + int arity2 = names2.length - bodyLength;
1.924 + int result2 = result;
1.925 + if (result2 >= 0) {
1.926 + if (result2 < skip+outArgs) {
1.927 + // return the corresponding inArg
1.928 + result2 = reorder[result2-skip];
1.929 + } else {
1.930 + result2 = result2 - outArgs + inTypes;
1.931 + }
1.932 + }
1.933 + // rework names in the body:
1.934 + for (int j = pos; j < outArgs; j++) {
1.935 + Name n = names[skip+j];
1.936 + int i = reorder[j];
1.937 + // replace names[skip+j] by names2[skip+i]
1.938 + Name n2 = names2[skip+i];
1.939 + if (n2 == null)
1.940 + names2[skip+i] = n2 = new Name(types[i]);
1.941 + else
1.942 + assert(n2.type == types[i]);
1.943 + for (int k = arity2; k < names2.length; k++) {
1.944 + names2[k] = names2[k].replaceName(n, n2);
1.945 + }
1.946 + }
1.947 + // some names are unused, but must be filled in
1.948 + for (int i = skip+pos; i < arity2; i++) {
1.949 + if (names2[i] == null)
1.950 + names2[i] = argument(i, types[i - skip]);
1.951 + }
1.952 + for (int j = arity; j < names.length; j++) {
1.953 + int i = j - arity + arity2;
1.954 + // replace names2[i] by names[j]
1.955 + Name n = names[j];
1.956 + Name n2 = names2[i];
1.957 + if (n != n2) {
1.958 + for (int k = i+1; k < names2.length; k++) {
1.959 + names2[k] = names2[k].replaceName(n, n2);
1.960 + }
1.961 + }
1.962 + }
1.963 + return new LambdaForm(debugName, arity2, names2, result2);
1.964 + }
1.965 +
1.966 + static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
1.967 + int inTypes = types.length;
1.968 + int outArgs = reorder.length;
1.969 + for (int i = 0; i < outArgs; i++) {
1.970 + assert(names[skip+i].isParam());
1.971 + assert(names[skip+i].type == types[reorder[i]]);
1.972 + }
1.973 + return true;
1.974 + }
1.975 +
1.976 + static class NamedFunction {
1.977 + final MemberName member;
1.978 + @Stable MethodHandle resolvedHandle;
1.979 + @Stable MethodHandle invoker;
1.980 +
1.981 + NamedFunction(MethodHandle resolvedHandle) {
1.982 + this(resolvedHandle.internalMemberName(), resolvedHandle);
1.983 + }
1.984 + NamedFunction(MemberName member, MethodHandle resolvedHandle) {
1.985 + this.member = member;
1.986 + //resolvedHandle = eraseSubwordTypes(resolvedHandle);
1.987 + this.resolvedHandle = resolvedHandle;
1.988 + }
1.989 + NamedFunction(MethodType basicInvokerType) {
1.990 + assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
1.991 + if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
1.992 + this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
1.993 + this.member = resolvedHandle.internalMemberName();
1.994 + } else {
1.995 + // necessary to pass BigArityTest
1.996 + this.member = Invokers.invokeBasicMethod(basicInvokerType);
1.997 + }
1.998 + }
1.999 +
1.1000 + // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
1.1001 + // Any LambdaForm containing such a member is not interpretable.
1.1002 + // This is OK, since all such LFs are prepared with special primitive vmentry points.
1.1003 + // And even without the resolvedHandle, the name can still be compiled and optimized.
1.1004 + NamedFunction(Method method) {
1.1005 + this(new MemberName(method));
1.1006 + }
1.1007 + NamedFunction(Field field) {
1.1008 + this(new MemberName(field));
1.1009 + }
1.1010 + NamedFunction(MemberName member) {
1.1011 + this.member = member;
1.1012 + this.resolvedHandle = null;
1.1013 + }
1.1014 +
1.1015 + MethodHandle resolvedHandle() {
1.1016 + if (resolvedHandle == null) resolve();
1.1017 + return resolvedHandle;
1.1018 + }
1.1019 +
1.1020 + void resolve() {
1.1021 + resolvedHandle = DirectMethodHandle.make(member);
1.1022 + }
1.1023 +
1.1024 + @Override
1.1025 + public boolean equals(Object other) {
1.1026 + if (this == other) return true;
1.1027 + if (other == null) return false;
1.1028 + if (!(other instanceof NamedFunction)) return false;
1.1029 + NamedFunction that = (NamedFunction) other;
1.1030 + return this.member != null && this.member.equals(that.member);
1.1031 + }
1.1032 +
1.1033 + @Override
1.1034 + public int hashCode() {
1.1035 + if (member != null)
1.1036 + return member.hashCode();
1.1037 + return super.hashCode();
1.1038 + }
1.1039 +
1.1040 + // Put the predefined NamedFunction invokers into the table.
1.1041 + static void initializeInvokers() {
1.1042 + for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
1.1043 + if (!m.isStatic() || !m.isPackage()) continue;
1.1044 + MethodType type = m.getMethodType();
1.1045 + if (type.equals(INVOKER_METHOD_TYPE) &&
1.1046 + m.getName().startsWith("invoke_")) {
1.1047 + String sig = m.getName().substring("invoke_".length());
1.1048 + int arity = LambdaForm.signatureArity(sig);
1.1049 + MethodType srcType = MethodType.genericMethodType(arity);
1.1050 + if (LambdaForm.signatureReturn(sig) == 'V')
1.1051 + srcType = srcType.changeReturnType(void.class);
1.1052 + MethodTypeForm typeForm = srcType.form();
1.1053 + typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
1.1054 + }
1.1055 + }
1.1056 + }
1.1057 +
1.1058 + // The following are predefined NamedFunction invokers. The system must build
1.1059 + // a separate invoker for each distinct signature.
1.1060 + /** void return type invokers. */
1.1061 + @Hidden
1.1062 + static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable {
1.1063 + assert(a.length == 0);
1.1064 + mh.invokeBasic();
1.1065 + return null;
1.1066 + }
1.1067 + @Hidden
1.1068 + static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable {
1.1069 + assert(a.length == 1);
1.1070 + mh.invokeBasic(a[0]);
1.1071 + return null;
1.1072 + }
1.1073 + @Hidden
1.1074 + static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable {
1.1075 + assert(a.length == 2);
1.1076 + mh.invokeBasic(a[0], a[1]);
1.1077 + return null;
1.1078 + }
1.1079 + @Hidden
1.1080 + static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable {
1.1081 + assert(a.length == 3);
1.1082 + mh.invokeBasic(a[0], a[1], a[2]);
1.1083 + return null;
1.1084 + }
1.1085 + @Hidden
1.1086 + static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable {
1.1087 + assert(a.length == 4);
1.1088 + mh.invokeBasic(a[0], a[1], a[2], a[3]);
1.1089 + return null;
1.1090 + }
1.1091 + @Hidden
1.1092 + static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable {
1.1093 + assert(a.length == 5);
1.1094 + mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
1.1095 + return null;
1.1096 + }
1.1097 + /** Object return type invokers. */
1.1098 + @Hidden
1.1099 + static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable {
1.1100 + assert(a.length == 0);
1.1101 + return mh.invokeBasic();
1.1102 + }
1.1103 + @Hidden
1.1104 + static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable {
1.1105 + assert(a.length == 1);
1.1106 + return mh.invokeBasic(a[0]);
1.1107 + }
1.1108 + @Hidden
1.1109 + static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable {
1.1110 + assert(a.length == 2);
1.1111 + return mh.invokeBasic(a[0], a[1]);
1.1112 + }
1.1113 + @Hidden
1.1114 + static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable {
1.1115 + assert(a.length == 3);
1.1116 + return mh.invokeBasic(a[0], a[1], a[2]);
1.1117 + }
1.1118 + @Hidden
1.1119 + static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable {
1.1120 + assert(a.length == 4);
1.1121 + return mh.invokeBasic(a[0], a[1], a[2], a[3]);
1.1122 + }
1.1123 + @Hidden
1.1124 + static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable {
1.1125 + assert(a.length == 5);
1.1126 + return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
1.1127 + }
1.1128 +
1.1129 + static final MethodType INVOKER_METHOD_TYPE =
1.1130 + MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
1.1131 +
1.1132 + private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
1.1133 + MethodHandle mh = typeForm.namedFunctionInvoker;
1.1134 + if (mh != null) return mh;
1.1135 + MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
1.1136 + mh = DirectMethodHandle.make(invoker);
1.1137 + MethodHandle mh2 = typeForm.namedFunctionInvoker;
1.1138 + if (mh2 != null) return mh2; // benign race
1.1139 + if (!mh.type().equals(INVOKER_METHOD_TYPE))
1.1140 + throw new InternalError(mh.debugString());
1.1141 + return typeForm.namedFunctionInvoker = mh;
1.1142 + }
1.1143 +
1.1144 + @Hidden
1.1145 + Object invokeWithArguments(Object... arguments) throws Throwable {
1.1146 + // If we have a cached invoker, call it right away.
1.1147 + // NOTE: The invoker always returns a reference value.
1.1148 + if (TRACE_INTERPRETER) return invokeWithArgumentsTracing(arguments);
1.1149 + assert(checkArgumentTypes(arguments, methodType()));
1.1150 + return invoker().invokeBasic(resolvedHandle(), arguments);
1.1151 + }
1.1152 +
1.1153 + @Hidden
1.1154 + Object invokeWithArgumentsTracing(Object[] arguments) throws Throwable {
1.1155 + Object rval;
1.1156 + try {
1.1157 + traceInterpreter("[ call", this, arguments);
1.1158 + if (invoker == null) {
1.1159 + traceInterpreter("| getInvoker", this);
1.1160 + invoker();
1.1161 + }
1.1162 + if (resolvedHandle == null) {
1.1163 + traceInterpreter("| resolve", this);
1.1164 + resolvedHandle();
1.1165 + }
1.1166 + assert(checkArgumentTypes(arguments, methodType()));
1.1167 + rval = invoker().invokeBasic(resolvedHandle(), arguments);
1.1168 + } catch (Throwable ex) {
1.1169 + traceInterpreter("] throw =>", ex);
1.1170 + throw ex;
1.1171 + }
1.1172 + traceInterpreter("] return =>", rval);
1.1173 + return rval;
1.1174 + }
1.1175 +
1.1176 + private MethodHandle invoker() {
1.1177 + if (invoker != null) return invoker;
1.1178 + // Get an invoker and cache it.
1.1179 + return invoker = computeInvoker(methodType().form());
1.1180 + }
1.1181 +
1.1182 + private static boolean checkArgumentTypes(Object[] arguments, MethodType methodType) {
1.1183 + if (true) return true; // FIXME
1.1184 + MethodType dstType = methodType.form().erasedType();
1.1185 + MethodType srcType = dstType.basicType().wrap();
1.1186 + Class<?>[] ptypes = new Class<?>[arguments.length];
1.1187 + for (int i = 0; i < arguments.length; i++) {
1.1188 + Object arg = arguments[i];
1.1189 + Class<?> ptype = arg == null ? Object.class : arg.getClass();
1.1190 + // If the dest. type is a primitive we keep the
1.1191 + // argument type.
1.1192 + ptypes[i] = dstType.parameterType(i).isPrimitive() ? ptype : Object.class;
1.1193 + }
1.1194 + MethodType argType = MethodType.methodType(srcType.returnType(), ptypes).wrap();
1.1195 + assert(argType.isConvertibleTo(srcType)) : "wrong argument types: cannot convert " + argType + " to " + srcType;
1.1196 + return true;
1.1197 + }
1.1198 +
1.1199 + String basicTypeSignature() {
1.1200 + //return LambdaForm.basicTypeSignature(resolvedHandle.type());
1.1201 + return LambdaForm.basicTypeSignature(methodType());
1.1202 + }
1.1203 +
1.1204 + MethodType methodType() {
1.1205 + if (resolvedHandle != null)
1.1206 + return resolvedHandle.type();
1.1207 + else
1.1208 + // only for certain internal LFs during bootstrapping
1.1209 + return member.getInvocationType();
1.1210 + }
1.1211 +
1.1212 + MemberName member() {
1.1213 + assert(assertMemberIsConsistent());
1.1214 + return member;
1.1215 + }
1.1216 +
1.1217 + // Called only from assert.
1.1218 + private boolean assertMemberIsConsistent() {
1.1219 + if (resolvedHandle instanceof DirectMethodHandle) {
1.1220 + MemberName m = resolvedHandle.internalMemberName();
1.1221 + assert(m.equals(member));
1.1222 + }
1.1223 + return true;
1.1224 + }
1.1225 +
1.1226 + Class<?> memberDeclaringClassOrNull() {
1.1227 + return (member == null) ? null : member.getDeclaringClass();
1.1228 + }
1.1229 +
1.1230 + char returnType() {
1.1231 + return basicType(methodType().returnType());
1.1232 + }
1.1233 +
1.1234 + char parameterType(int n) {
1.1235 + return basicType(methodType().parameterType(n));
1.1236 + }
1.1237 +
1.1238 + int arity() {
1.1239 + //int siglen = member.getMethodType().parameterCount();
1.1240 + //if (!member.isStatic()) siglen += 1;
1.1241 + //return siglen;
1.1242 + return methodType().parameterCount();
1.1243 + }
1.1244 +
1.1245 + public String toString() {
1.1246 + if (member == null) return String.valueOf(resolvedHandle);
1.1247 + return member.getDeclaringClass().getSimpleName()+"."+member.getName();
1.1248 + }
1.1249 + }
1.1250 +
1.1251 + void resolve() {
1.1252 + for (Name n : names) n.resolve();
1.1253 + }
1.1254 +
1.1255 + public static char basicType(Class<?> type) {
1.1256 + char c = Wrapper.basicTypeChar(type);
1.1257 + if ("ZBSC".indexOf(c) >= 0) c = 'I';
1.1258 + assert("LIJFDV".indexOf(c) >= 0);
1.1259 + return c;
1.1260 + }
1.1261 + public static char[] basicTypes(List<Class<?>> types) {
1.1262 + char[] btypes = new char[types.size()];
1.1263 + for (int i = 0; i < btypes.length; i++) {
1.1264 + btypes[i] = basicType(types.get(i));
1.1265 + }
1.1266 + return btypes;
1.1267 + }
1.1268 + public static String basicTypeSignature(MethodType type) {
1.1269 + char[] sig = new char[type.parameterCount() + 2];
1.1270 + int sigp = 0;
1.1271 + for (Class<?> pt : type.parameterList()) {
1.1272 + sig[sigp++] = basicType(pt);
1.1273 + }
1.1274 + sig[sigp++] = '_';
1.1275 + sig[sigp++] = basicType(type.returnType());
1.1276 + assert(sigp == sig.length);
1.1277 + return String.valueOf(sig);
1.1278 + }
1.1279 +
1.1280 + static final class Name {
1.1281 + final char type;
1.1282 + private short index;
1.1283 + final NamedFunction function;
1.1284 + @Stable final Object[] arguments;
1.1285 +
1.1286 + private Name(int index, char type, NamedFunction function, Object[] arguments) {
1.1287 + this.index = (short)index;
1.1288 + this.type = type;
1.1289 + this.function = function;
1.1290 + this.arguments = arguments;
1.1291 + assert(this.index == index);
1.1292 + }
1.1293 + Name(MethodHandle function, Object... arguments) {
1.1294 + this(new NamedFunction(function), arguments);
1.1295 + }
1.1296 + Name(MethodType functionType, Object... arguments) {
1.1297 + this(new NamedFunction(functionType), arguments);
1.1298 + assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
1.1299 + }
1.1300 + Name(MemberName function, Object... arguments) {
1.1301 + this(new NamedFunction(function), arguments);
1.1302 + }
1.1303 + Name(NamedFunction function, Object... arguments) {
1.1304 + this(-1, function.returnType(), function, arguments = arguments.clone());
1.1305 + assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString();
1.1306 + for (int i = 0; i < arguments.length; i++)
1.1307 + assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
1.1308 + }
1.1309 + Name(int index, char type) {
1.1310 + this(index, type, null, null);
1.1311 + }
1.1312 + Name(char type) {
1.1313 + this(-1, type);
1.1314 + }
1.1315 +
1.1316 + char type() { return type; }
1.1317 + int index() { return index; }
1.1318 + boolean initIndex(int i) {
1.1319 + if (index != i) {
1.1320 + if (index != -1) return false;
1.1321 + index = (short)i;
1.1322 + }
1.1323 + return true;
1.1324 + }
1.1325 +
1.1326 +
1.1327 + void resolve() {
1.1328 + if (function != null)
1.1329 + function.resolve();
1.1330 + }
1.1331 +
1.1332 + Name newIndex(int i) {
1.1333 + if (initIndex(i)) return this;
1.1334 + return cloneWithIndex(i);
1.1335 + }
1.1336 + Name cloneWithIndex(int i) {
1.1337 + Object[] newArguments = (arguments == null) ? null : arguments.clone();
1.1338 + return new Name(i, type, function, newArguments);
1.1339 + }
1.1340 + Name replaceName(Name oldName, Name newName) { // FIXME: use replaceNames uniformly
1.1341 + if (oldName == newName) return this;
1.1342 + @SuppressWarnings("LocalVariableHidesMemberVariable")
1.1343 + Object[] arguments = this.arguments;
1.1344 + if (arguments == null) return this;
1.1345 + boolean replaced = false;
1.1346 + for (int j = 0; j < arguments.length; j++) {
1.1347 + if (arguments[j] == oldName) {
1.1348 + if (!replaced) {
1.1349 + replaced = true;
1.1350 + arguments = arguments.clone();
1.1351 + }
1.1352 + arguments[j] = newName;
1.1353 + }
1.1354 + }
1.1355 + if (!replaced) return this;
1.1356 + return new Name(function, arguments);
1.1357 + }
1.1358 + Name replaceNames(Name[] oldNames, Name[] newNames, int start, int end) {
1.1359 + @SuppressWarnings("LocalVariableHidesMemberVariable")
1.1360 + Object[] arguments = this.arguments;
1.1361 + boolean replaced = false;
1.1362 + eachArg:
1.1363 + for (int j = 0; j < arguments.length; j++) {
1.1364 + if (arguments[j] instanceof Name) {
1.1365 + Name n = (Name) arguments[j];
1.1366 + int check = n.index;
1.1367 + // harmless check to see if the thing is already in newNames:
1.1368 + if (check >= 0 && check < newNames.length && n == newNames[check])
1.1369 + continue eachArg;
1.1370 + // n might not have the correct index: n != oldNames[n.index].
1.1371 + for (int i = start; i < end; i++) {
1.1372 + if (n == oldNames[i]) {
1.1373 + if (n == newNames[i])
1.1374 + continue eachArg;
1.1375 + if (!replaced) {
1.1376 + replaced = true;
1.1377 + arguments = arguments.clone();
1.1378 + }
1.1379 + arguments[j] = newNames[i];
1.1380 + continue eachArg;
1.1381 + }
1.1382 + }
1.1383 + }
1.1384 + }
1.1385 + if (!replaced) return this;
1.1386 + return new Name(function, arguments);
1.1387 + }
1.1388 + void internArguments() {
1.1389 + @SuppressWarnings("LocalVariableHidesMemberVariable")
1.1390 + Object[] arguments = this.arguments;
1.1391 + for (int j = 0; j < arguments.length; j++) {
1.1392 + if (arguments[j] instanceof Name) {
1.1393 + Name n = (Name) arguments[j];
1.1394 + if (n.isParam() && n.index < INTERNED_ARGUMENT_LIMIT)
1.1395 + arguments[j] = internArgument(n);
1.1396 + }
1.1397 + }
1.1398 + }
1.1399 + boolean isParam() {
1.1400 + return function == null;
1.1401 + }
1.1402 + boolean isConstantZero() {
1.1403 + return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
1.1404 + }
1.1405 +
1.1406 + public String toString() {
1.1407 + return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
1.1408 + }
1.1409 + public String debugString() {
1.1410 + String s = toString();
1.1411 + return (function == null) ? s : s + "=" + exprString();
1.1412 + }
1.1413 + public String exprString() {
1.1414 + if (function == null) return "null";
1.1415 + StringBuilder buf = new StringBuilder(function.toString());
1.1416 + buf.append("(");
1.1417 + String cma = "";
1.1418 + for (Object a : arguments) {
1.1419 + buf.append(cma); cma = ",";
1.1420 + if (a instanceof Name || a instanceof Integer)
1.1421 + buf.append(a);
1.1422 + else
1.1423 + buf.append("(").append(a).append(")");
1.1424 + }
1.1425 + buf.append(")");
1.1426 + return buf.toString();
1.1427 + }
1.1428 +
1.1429 + private static boolean typesMatch(char parameterType, Object object) {
1.1430 + if (object instanceof Name) {
1.1431 + return ((Name)object).type == parameterType;
1.1432 + }
1.1433 + switch (parameterType) {
1.1434 + case 'I': return object instanceof Integer;
1.1435 + case 'J': return object instanceof Long;
1.1436 + case 'F': return object instanceof Float;
1.1437 + case 'D': return object instanceof Double;
1.1438 + }
1.1439 + assert(parameterType == 'L');
1.1440 + return true;
1.1441 + }
1.1442 +
1.1443 + /**
1.1444 + * Does this Name precede the given binding node in some canonical order?
1.1445 + * This predicate is used to order data bindings (via insertion sort)
1.1446 + * with some stability.
1.1447 + */
1.1448 + boolean isSiblingBindingBefore(Name binding) {
1.1449 + assert(!binding.isParam());
1.1450 + if (isParam()) return true;
1.1451 + if (function.equals(binding.function) &&
1.1452 + arguments.length == binding.arguments.length) {
1.1453 + boolean sawInt = false;
1.1454 + for (int i = 0; i < arguments.length; i++) {
1.1455 + Object a1 = arguments[i];
1.1456 + Object a2 = binding.arguments[i];
1.1457 + if (!a1.equals(a2)) {
1.1458 + if (a1 instanceof Integer && a2 instanceof Integer) {
1.1459 + if (sawInt) continue;
1.1460 + sawInt = true;
1.1461 + if ((int)a1 < (int)a2) continue; // still might be true
1.1462 + }
1.1463 + return false;
1.1464 + }
1.1465 + }
1.1466 + return sawInt;
1.1467 + }
1.1468 + return false;
1.1469 + }
1.1470 +
1.1471 + public boolean equals(Name that) {
1.1472 + if (this == that) return true;
1.1473 + if (isParam())
1.1474 + // each parameter is a unique atom
1.1475 + return false; // this != that
1.1476 + return
1.1477 + //this.index == that.index &&
1.1478 + this.type == that.type &&
1.1479 + this.function.equals(that.function) &&
1.1480 + Arrays.equals(this.arguments, that.arguments);
1.1481 + }
1.1482 + @Override
1.1483 + public boolean equals(Object x) {
1.1484 + return x instanceof Name && equals((Name)x);
1.1485 + }
1.1486 + @Override
1.1487 + public int hashCode() {
1.1488 + if (isParam())
1.1489 + return index | (type << 8);
1.1490 + return function.hashCode() ^ Arrays.hashCode(arguments);
1.1491 + }
1.1492 + }
1.1493 +
1.1494 + static Name argument(int which, char type) {
1.1495 + int tn = ALL_TYPES.indexOf(type);
1.1496 + if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
1.1497 + return new Name(which, type);
1.1498 + return INTERNED_ARGUMENTS[tn][which];
1.1499 + }
1.1500 + static Name internArgument(Name n) {
1.1501 + assert(n.isParam()) : "not param: " + n;
1.1502 + assert(n.index < INTERNED_ARGUMENT_LIMIT);
1.1503 + return argument(n.index, n.type);
1.1504 + }
1.1505 + static Name[] arguments(int extra, String types) {
1.1506 + int length = types.length();
1.1507 + Name[] names = new Name[length + extra];
1.1508 + for (int i = 0; i < length; i++)
1.1509 + names[i] = argument(i, types.charAt(i));
1.1510 + return names;
1.1511 + }
1.1512 + static Name[] arguments(int extra, char... types) {
1.1513 + int length = types.length;
1.1514 + Name[] names = new Name[length + extra];
1.1515 + for (int i = 0; i < length; i++)
1.1516 + names[i] = argument(i, types[i]);
1.1517 + return names;
1.1518 + }
1.1519 + static Name[] arguments(int extra, List<Class<?>> types) {
1.1520 + int length = types.size();
1.1521 + Name[] names = new Name[length + extra];
1.1522 + for (int i = 0; i < length; i++)
1.1523 + names[i] = argument(i, basicType(types.get(i)));
1.1524 + return names;
1.1525 + }
1.1526 + static Name[] arguments(int extra, Class<?>... types) {
1.1527 + int length = types.length;
1.1528 + Name[] names = new Name[length + extra];
1.1529 + for (int i = 0; i < length; i++)
1.1530 + names[i] = argument(i, basicType(types[i]));
1.1531 + return names;
1.1532 + }
1.1533 + static Name[] arguments(int extra, MethodType types) {
1.1534 + int length = types.parameterCount();
1.1535 + Name[] names = new Name[length + extra];
1.1536 + for (int i = 0; i < length; i++)
1.1537 + names[i] = argument(i, basicType(types.parameterType(i)));
1.1538 + return names;
1.1539 + }
1.1540 + static final String ALL_TYPES = "LIJFD"; // omit V, not an argument type
1.1541 + static final int INTERNED_ARGUMENT_LIMIT = 10;
1.1542 + private static final Name[][] INTERNED_ARGUMENTS
1.1543 + = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT];
1.1544 + static {
1.1545 + for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
1.1546 + for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) {
1.1547 + char type = ALL_TYPES.charAt(tn);
1.1548 + INTERNED_ARGUMENTS[tn][i] = new Name(i, type);
1.1549 + }
1.1550 + }
1.1551 + }
1.1552 +
1.1553 + private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
1.1554 +
1.1555 + static Name constantZero(int which, char type) {
1.1556 + return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which);
1.1557 + }
1.1558 + private static final Name[] CONSTANT_ZERO
1.1559 + = new Name[ALL_TYPES.length()];
1.1560 + static {
1.1561 + for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
1.1562 + char bt = ALL_TYPES.charAt(tn);
1.1563 + Wrapper wrap = Wrapper.forBasicType(bt);
1.1564 + MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic);
1.1565 + try {
1.1566 + zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
1.1567 + } catch (IllegalAccessException|NoSuchMethodException ex) {
1.1568 + throw newInternalError(ex);
1.1569 + }
1.1570 + NamedFunction zcon = new NamedFunction(zmem);
1.1571 + Name n = new Name(zcon).newIndex(0);
1.1572 + assert(n.type == ALL_TYPES.charAt(tn));
1.1573 + CONSTANT_ZERO[tn] = n;
1.1574 + assert(n.isConstantZero());
1.1575 + }
1.1576 + }
1.1577 +
1.1578 + // Avoid appealing to ValueConversions at bootstrap time:
1.1579 + private static int zeroI() { return 0; }
1.1580 + private static long zeroJ() { return 0; }
1.1581 + private static float zeroF() { return 0; }
1.1582 + private static double zeroD() { return 0; }
1.1583 + private static Object zeroL() { return null; }
1.1584 +
1.1585 + // Put this last, so that previous static inits can run before.
1.1586 + static {
1.1587 + if (USE_PREDEFINED_INTERPRET_METHODS)
1.1588 + PREPARED_FORMS.putAll(computeInitialPreparedForms());
1.1589 + }
1.1590 +
1.1591 + /**
1.1592 + * Internal marker for byte-compiled LambdaForms.
1.1593 + */
1.1594 + /*non-public*/
1.1595 + @Target(ElementType.METHOD)
1.1596 + @Retention(RetentionPolicy.RUNTIME)
1.1597 + @interface Compiled {
1.1598 + }
1.1599 +
1.1600 + /**
1.1601 + * Internal marker for LambdaForm interpreter frames.
1.1602 + */
1.1603 + /*non-public*/
1.1604 + @Target(ElementType.METHOD)
1.1605 + @Retention(RetentionPolicy.RUNTIME)
1.1606 + @interface Hidden {
1.1607 + }
1.1608 +
1.1609 +
1.1610 +/*
1.1611 + // Smoke-test for the invokers used in this file.
1.1612 + static void testMethodHandleLinkers() throws Throwable {
1.1613 + MemberName.Factory lookup = MemberName.getFactory();
1.1614 + MemberName asList_MN = new MemberName(Arrays.class, "asList",
1.1615 + MethodType.methodType(List.class, Object[].class),
1.1616 + REF_invokeStatic);
1.1617 + //MethodHandleNatives.resolve(asList_MN, null);
1.1618 + asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class);
1.1619 + System.out.println("about to call "+asList_MN);
1.1620 + Object[] abc = { "a", "bc" };
1.1621 + List<?> lst = (List<?>) MethodHandle.linkToStatic(abc, asList_MN);
1.1622 + System.out.println("lst="+lst);
1.1623 + MemberName toString_MN = new MemberName(Object.class.getMethod("toString"));
1.1624 + String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN);
1.1625 + toString_MN = new MemberName(Object.class.getMethod("toString"), true);
1.1626 + String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN);
1.1627 + System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
1.1628 + MemberName toArray_MN = new MemberName(List.class.getMethod("toArray"));
1.1629 + Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN);
1.1630 + System.out.println("toArray="+Arrays.toString(arr));
1.1631 + }
1.1632 + static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
1.1633 + // Requires these definitions in MethodHandle:
1.1634 + static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable;
1.1635 + static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable;
1.1636 + static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable;
1.1637 + static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
1.1638 + */
1.1639 +
1.1640 + static { NamedFunction.initializeInvokers(); }
1.1641 +
1.1642 + // The following hack is necessary in order to suppress TRACE_INTERPRETER
1.1643 + // during execution of the static initializes of this class.
1.1644 + // Turning on TRACE_INTERPRETER too early will cause
1.1645 + // stack overflows and other misbehavior during attempts to trace events
1.1646 + // that occur during LambdaForm.<clinit>.
1.1647 + // Therefore, do not move this line higher in this file, and do not remove.
1.1648 + private static final boolean TRACE_INTERPRETER = MethodHandleStatics.TRACE_INTERPRETER;
1.1649 +}