Simplifying the build. Move Java8 code into the main module (springloaded).
This means the springloaded module must be built on top of a 1.8 JRE although it can be built with 1.6 compliance.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2014 Pivotal Software Inc. and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springsource.loaded.support;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* This class encapsulates dependencies on Java 8 APIs (e.g. LambdaMetafactory).
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 1.2
|
||||
*/
|
||||
public class Java8 {
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* Useful to have an example of how this code behaves. Here is a bit of code:
|
||||
*
|
||||
* class basic.LambdaA {
|
||||
* interface Foo { int m(); }
|
||||
* static int run() {
|
||||
* Foo f = null;
|
||||
* f = () -> 77;
|
||||
* return f.m();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Here is a bootstrap method entry in the constant pool:
|
||||
*
|
||||
* 0: #31 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:
|
||||
* (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;
|
||||
* Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
||||
* Method arguments:
|
||||
* #32 ()I
|
||||
* #33 invokestatic basic/LambdaA.lambda$run$0:()I
|
||||
* #32 ()I
|
||||
*
|
||||
* At the invokedynamic site:
|
||||
* bsmId = 0
|
||||
* nameAndDescriptor = m()Lbasic/LambdaA$Foo;
|
||||
*
|
||||
* When invoking the metafactory bootstrap method the first two parameters are stacked by the VM automatically, namely the MethodHandles$Lookup
|
||||
* instance (caller) and the first String (invokedName). What the VM actually sees is this:
|
||||
*
|
||||
* metaFactory parameters:
|
||||
* 0:MethodHandles$Lookup caller = basic.LambdaA
|
||||
* 1:String invokedName = "m"
|
||||
* 2:MethodType invokedType = "()Foo"
|
||||
* 3:MethodType samMethodType = "()int"
|
||||
* 4:MethodHandle implMethod = (actually a DirectMethodHandle where memberName is "basic.LambdaA.lambda$run$0()int/invokeStatic")
|
||||
* 5:MethodType instantiatedMethodType = "()int"
|
||||
*
|
||||
* With all that information then the calls in this case are relatively straightforward:
|
||||
* CallSite callsite = LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
|
||||
* callsite.dynamicInvoker().invokeWithArguments((Object[])null);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Programmatic emulation of INVOKEDYNAMIC so initialize the callsite via use of the bootstrap method then
|
||||
* invoke the result.
|
||||
*
|
||||
* @param executorClass null if not yet reloaded
|
||||
* @param handle
|
||||
* @param bsmArgs
|
||||
* @param lookup
|
||||
* @return
|
||||
*/
|
||||
public static Object emulateInvokeDynamic(Class executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) {
|
||||
try {
|
||||
CallSite callsite = callLambdaMetaFactory(bsmArgs,lookup,indyNameAndDescriptor,executorClass);
|
||||
return callsite.dynamicInvoker().invokeWithArguments(indyParams);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
// TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types!
|
||||
|
||||
// TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)
|
||||
public static CallSite callLambdaMetaFactory(Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class executorClass) throws Exception {
|
||||
MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup;
|
||||
|
||||
ClassLoader callerLoader = caller.lookupClass().getClassLoader();
|
||||
|
||||
int descriptorStart = indyNameAndDescriptor.indexOf('(');
|
||||
String invokedName = indyNameAndDescriptor.substring(0,descriptorStart);
|
||||
MethodType invokedType = MethodType.fromMethodDescriptorString(indyNameAndDescriptor.substring(descriptorStart), callerLoader);
|
||||
|
||||
// Use bsmArgs to build the parameters
|
||||
MethodType samMethodType = MethodType.fromMethodDescriptorString((String)(((Type)bsmArgs[0]).getDescriptor()), callerLoader);
|
||||
|
||||
Handle bsmArgsHandle = (Handle)bsmArgs[1];
|
||||
String owner = bsmArgsHandle.getOwner();
|
||||
String name = bsmArgsHandle.getName();
|
||||
String descriptor = bsmArgsHandle.getDesc();
|
||||
MethodType implMethodType = MethodType.fromMethodDescriptorString(descriptor, callerLoader);
|
||||
// Looking up the lambda$run method in the caller class (note the caller class is the executor, which gets us around the
|
||||
// problem of having to hack into LambdaMetafactory to intercept reflection)
|
||||
MethodHandle implMethod = null;
|
||||
// TODO [lambda] need to handle invokevirtual, surely
|
||||
switch (bsmArgsHandle.getTag()) {
|
||||
case Opcodes.H_INVOKESTATIC:
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, implMethodType);
|
||||
break;
|
||||
case Opcodes.H_INVOKESPECIAL:
|
||||
// If there is an executor, the lambda function is actually modified from 'private instance' to 'public static' so adjust lookup:
|
||||
if (executorClass == null) {
|
||||
implMethod = caller.findSpecial(caller.lookupClass(), name, implMethodType, caller.lookupClass());
|
||||
}
|
||||
else {
|
||||
implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L"+owner+";"+descriptor.substring(1),callerLoader));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("nyi "+bsmArgsHandle.getTag());
|
||||
}
|
||||
|
||||
MethodType instantiatedMethodType = MethodType.fromMethodDescriptorString((String)(((Type)bsmArgs[2]).getDescriptor()), callerLoader);
|
||||
|
||||
return LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user