public static CallSite callLambdaMetaFactory(ReloadableType rtype, 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(
				(((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;
		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. The method
				// will be static with a new leading parameter.
				if (executorClass == null) {
					// TODO is final parameter here correct?
					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;
			case Opcodes.H_INVOKEVIRTUAL:
				// There is a possibility to 'shortcut' here. Basically we are trying to resolve a callsite reference
				// to the method that satisfies it. The easiest option is to just find the method on the originally
				// loaded version of the target class and return that. A more optimal shortcut could return the
				// method on the executor class if the target has been reloaded (effectively bypassing the method
				// on the originally loaded version since we know that it will be acting as a pass through). But this
				// opens up a can of worms related to visibility. The executor is loaded into the child classloader,
				// and if the caller has not been reloaded it will not be able to 'see' the executor (since it is in
				// a child classloader). So, basically keep this dumb (but reliable) for now.

				TypeRegistry typeRegistry = rtype.getTypeRegistry();
				ReloadableType ownerRType = typeRegistry.getReloadableType(owner);
				if (null == ownerRType || !ownerRType.hasBeenReloaded()) {
					// target containing the reference/lambdaMethod has not been reloaded, no need to get over
					// complicated.
					Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
					implMethod = caller.findVirtual(clazz, name, implMethodType);
				}
				else {
					MethodMember targetReferenceMethodMember = ownerRType.getCurrentMethod(name, descriptor);
					String targetReferenceDescriptor = targetReferenceMethodMember.getDescriptor();
					MethodType targetReferenceMethodType = MethodType.fromMethodDescriptorString(
							targetReferenceDescriptor, callerLoader);
					Class<?> targetReferenceClass = ownerRType.getClazz();
					MethodMember currentMethod = ownerRType.getCurrentMethod(name, descriptor);

					if (currentMethod.original == null) {
						// null means this method did not exist on the original version of the target.
						// Assert that the caller must have been reloaded, otherwise how would it
						// have a reference to something that did not exist on the first version of the type. In that
						// case we know we can return the method on the executor class because both the reloaded
						// caller and reloaded target are in the same child classloader (no visibility problem).
						if (!rtype.hasBeenReloaded()) {
							throw new IllegalStateException(
									"Assertion violated: When a method added on reload is being referenced"
											+ "in target type '" + ownerRType.getName()
											+ "', expected the caller to also have been reloaded: '"
											+ rtype.getName() + "'");
						}
						CurrentLiveVersion ownerLiveVersion = ownerRType.getLiveVersion();
						Class<?> ownerExecutorClass = ownerLiveVersion.getExecutorClass();
						Method executorMethod = ownerLiveVersion.getExecutorMethod(currentMethod);
						String methodDescriptor = Type.getType(executorMethod).getDescriptor();
						MethodType type = MethodType.fromMethodDescriptorString(methodDescriptor, callerLoader);
						implMethod = caller.findStatic(ownerExecutorClass, name, type);
					}
					else {
						// This finds the reference method on the originally loaded class. It will pass through
						// to the actual code on the reloaded version.
						implMethod = caller.findVirtual(targetReferenceClass, name, targetReferenceMethodType);
					}
				}
				break;
			case Opcodes.H_NEWINVOKESPECIAL:
				Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
				implMethod = caller.findConstructor(clazz, implMethodType);
				break;
			case Opcodes.H_INVOKEINTERFACE:
				Handle h = (Handle) bsmArgs[1];
				String interfaceOwner = h.getOwner();
				// TODO Should there not be a more direct way to this than classloading?
				// TODO What about when this is a method added to the interface on a reload? It won't really exist, should we point
				// to the executor? or something else? (maybe just directly the real method that will satisfy the interface - if it can be worked out)
				Class<?> interfaceClass = callerLoader.loadClass(interfaceOwner.replace('/', '.')); // interface type, eg StreamB$Foo
				implMethod = caller.findVirtual(interfaceClass, name, implMethodType);
				break;
			default:
				throw new IllegalStateException("nyi " + bsmArgsHandle.getTag());
		}

		MethodType instantiatedMethodType = MethodType.fromMethodDescriptorString(
				(((Type) bsmArgs[2]).getDescriptor()), callerLoader);

		return LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod,
				instantiatedMethodType);

	}
public static CallSite callLambdaMetaFactory ( ReloadableType rtype , 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 ) ; MethodType samMethodType = MethodType . fromMethodDescriptorString ( ( ( ( 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 ) ; MethodHandle implMethod = null ; switch ( bsmArgsHandle . getTag ( ) ) { case Opcodes . H_INVOKESTATIC : implMethod = caller . findStatic ( caller . lookupClass ( ) , name , implMethodType ) ; break ; case Opcodes . H_INVOKESPECIAL : 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 ; case Opcodes . H_INVOKEVIRTUAL : TypeRegistry typeRegistry = rtype . getTypeRegistry ( ) ; ReloadableType ownerRType = typeRegistry . getReloadableType ( owner ) ; if ( null == ownerRType || ! ownerRType . hasBeenReloaded ( ) ) { Class < ? > clazz = callerLoader . loadClass ( owner . replace ( "/" , "." ) ) ; implMethod = caller . findVirtual ( clazz , name , implMethodType ) ; } else { MethodMember targetReferenceMethodMember = ownerRType . getCurrentMethod ( name , descriptor ) ; String targetReferenceDescriptor = targetReferenceMethodMember . getDescriptor ( ) ; MethodType targetReferenceMethodType = MethodType . fromMethodDescriptorString ( targetReferenceDescriptor , callerLoader ) ; Class < ? > targetReferenceClass = ownerRType . getClazz ( ) ; MethodMember currentMethod = ownerRType . getCurrentMethod ( name , descriptor ) ; if ( currentMethod . original == null ) { if ( ! rtype . hasBeenReloaded ( ) ) { throw new IllegalStateException ( "Assertion violated: When a method added on reload is being referenced" + "in target type '" + ownerRType . getName ( ) + "', expected the caller to also have been reloaded: '" + rtype . getName ( ) + "'" ) ; } CurrentLiveVersion ownerLiveVersion = ownerRType . getLiveVersion ( ) ; Class < ? > ownerExecutorClass = ownerLiveVersion . getExecutorClass ( ) ; Method executorMethod = ownerLiveVersion . getExecutorMethod ( currentMethod ) ; String methodDescriptor = Type . getType ( executorMethod ) . getDescriptor ( ) ; MethodType type = MethodType . fromMethodDescriptorString ( methodDescriptor , callerLoader ) ; implMethod = caller . findStatic ( ownerExecutorClass , name , type ) ; } else { implMethod = caller . findVirtual ( targetReferenceClass , name , targetReferenceMethodType ) ; } } break ; case Opcodes . H_NEWINVOKESPECIAL : Class < ? > clazz = callerLoader . loadClass ( owner . replace ( "/" , "." ) ) ; implMethod = caller . findConstructor ( clazz , implMethodType ) ; break ; case Opcodes . H_INVOKEINTERFACE : Handle h = ( Handle ) bsmArgs [ 1 ] ; String interfaceOwner = h . getOwner ( ) ; Class < ? > interfaceClass = callerLoader . loadClass ( interfaceOwner . replace ( '/' , '.' ) ) ; implMethod = caller . findVirtual ( interfaceClass , name , implMethodType ) ; break ; default : throw new IllegalStateException ( "nyi " + bsmArgsHandle . getTag ( ) ) ; } MethodType instantiatedMethodType = MethodType . fromMethodDescriptorString ( ( ( ( Type ) bsmArgs [ 2 ] ) . getDescriptor ( ) ) , callerLoader ) ; return LambdaMetafactory . metafactory ( caller , invokedName , invokedType , samMethodType , implMethod , instantiatedMethodType ) ; }
TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)