internal virtual LambdaForm CollectArgumentsForm(int pos, MethodType collectorType) { int collectorArity = collectorType.ParameterCount(); bool dropResult = (collectorType.ReturnType() == typeof(void)); if (collectorArity == 1 && !dropResult) { return(FilterArgumentForm(pos, basicType(collectorType.ParameterType(0)))); } BasicType[] newTypes = BasicType.basicTypes(collectorType.ParameterList()); Transform.Kind kind = (dropResult ? Transform.Kind.COLLECT_ARGS_TO_VOID : Transform.Kind.COLLECT_ARGS); if (dropResult && collectorArity == 0) // pure side effect { pos = 1; } Transform key = Transform.Of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes)); LambdaForm form = GetInCache(key); if (form != null) { assert(form.Arity_Renamed == LambdaForm.Arity_Renamed - (dropResult ? 0 : 1) + collectorArity); return(form); } form = MakeArgumentCombinationForm(pos, collectorType, false, dropResult); return(PutInCache(key, form)); }
/// <summary> /// Facilitates the creation of simple "function objects" that implement one /// or more interfaces by delegation to a provided <seealso cref="MethodHandle"/>, /// after appropriate type adaptation and partial evaluation of arguments. /// Typically used as a <em>bootstrap method</em> for {@code invokedynamic} /// call sites, to support the <em>lambda expression</em> and <em>method /// reference expression</em> features of the Java Programming Language. /// /// <para>This is the general, more flexible metafactory; a streamlined version /// is provided by {@link #metafactory(java.lang.invoke.MethodHandles.Lookup, /// String, MethodType, MethodType, MethodHandle, MethodType)}. /// A general description of the behavior of this method is provided /// <seealso cref="LambdaMetafactory above"/>. /// /// </para> /// <para>The argument list for this method includes three fixed parameters, /// corresponding to the parameters automatically stacked by the VM for the /// bootstrap method in an {@code invokedynamic} invocation, and an {@code Object[]} /// parameter that contains additional parameters. The declared argument /// list for this method is: /// /// <pre>{@code /// CallSite altMetafactory(MethodHandles.Lookup caller, /// String invokedName, /// MethodType invokedType, /// Object... args) /// }</pre> /// /// </para> /// <para>but it behaves as if the argument list is as follows: /// /// <pre>{@code /// CallSite altMetafactory(MethodHandles.Lookup caller, /// String invokedName, /// MethodType invokedType, /// MethodType samMethodType, /// MethodHandle implMethod, /// MethodType instantiatedMethodType, /// int flags, /// int markerInterfaceCount, // IF flags has MARKERS set /// Class... markerInterfaces, // IF flags has MARKERS set /// int bridgeCount, // IF flags has BRIDGES set /// MethodType... bridges // IF flags has BRIDGES set /// ) /// }</pre> /// /// </para> /// <para>Arguments that appear in the argument list for /// <seealso cref="#metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)"/> /// have the same specification as in that method. The additional arguments /// are interpreted as follows: /// <ul> /// <li>{@code flags} indicates additional options; this is a bitwise /// OR of desired flags. Defined flags are <seealso cref="#FLAG_BRIDGES"/>, /// <seealso cref="#FLAG_MARKERS"/>, and <seealso cref="#FLAG_SERIALIZABLE"/>.</li> /// <li>{@code markerInterfaceCount} is the number of additional interfaces /// the function object should implement, and is present if and only if the /// {@code FLAG_MARKERS} flag is set.</li> /// <li>{@code markerInterfaces} is a variable-length list of additional /// interfaces to implement, whose length equals {@code markerInterfaceCount}, /// and is present if and only if the {@code FLAG_MARKERS} flag is set.</li> /// <li>{@code bridgeCount} is the number of additional method signatures /// the function object should implement, and is present if and only if /// the {@code FLAG_BRIDGES} flag is set.</li> /// <li>{@code bridges} is a variable-length list of additional /// methods signatures to implement, whose length equals {@code bridgeCount}, /// and is present if and only if the {@code FLAG_BRIDGES} flag is set.</li> /// </ul> /// /// </para> /// <para>Each class named by {@code markerInterfaces} is subject to the same /// restrictions as {@code Rd}, the return type of {@code invokedType}, /// as described <seealso cref="LambdaMetafactory above"/>. Each {@code MethodType} /// named by {@code bridges} is subject to the same restrictions as /// {@code samMethodType}, as described <seealso cref="LambdaMetafactory above"/>. /// /// </para> /// <para>When FLAG_SERIALIZABLE is set in {@code flags}, the function objects /// will implement {@code Serializable}, and will have a {@code writeReplace} /// method that returns an appropriate <seealso cref="SerializedLambda"/>. The /// {@code caller} class must have an appropriate {@code $deserializeLambda$} /// method, as described in <seealso cref="SerializedLambda"/>. /// /// </para> /// <para>When the target of the {@code CallSite} returned from this method is /// invoked, the resulting function objects are instances of a class with /// the following properties: /// <ul> /// <li>The class implements the interface named by the return type /// of {@code invokedType} and any interfaces named by {@code markerInterfaces}</li> /// <li>The class declares methods with the name given by {@code invokedName}, /// and the signature given by {@code samMethodType} and additional signatures /// given by {@code bridges}</li> /// <li>The class may override methods from {@code Object}, and may /// implement methods related to serialization.</li> /// </ul> /// /// </para> /// </summary> /// <param name="caller"> Represents a lookup context with the accessibility /// privileges of the caller. When used with {@code invokedynamic}, /// this is stacked automatically by the VM. </param> /// <param name="invokedName"> The name of the method to implement. When used with /// {@code invokedynamic}, this is provided by the /// {@code NameAndType} of the {@code InvokeDynamic} /// structure and is stacked automatically by the VM. </param> /// <param name="invokedType"> The expected signature of the {@code CallSite}. The /// parameter types represent the types of capture variables; /// the return type is the interface to implement. When /// used with {@code invokedynamic}, this is provided by /// the {@code NameAndType} of the {@code InvokeDynamic} /// structure and is stacked automatically by the VM. /// In the event that the implementation method is an /// instance method and this signature has any parameters, /// the first parameter in the invocation signature must /// correspond to the receiver. </param> /// <param name="args"> An {@code Object[]} array containing the required /// arguments {@code samMethodType}, {@code implMethod}, /// {@code instantiatedMethodType}, {@code flags}, and any /// optional arguments, as described /// <seealso cref="#altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)"/> above} </param> /// <returns> a CallSite whose target can be used to perform capture, generating /// instances of the interface named by {@code invokedType} </returns> /// <exception cref="LambdaConversionException"> If any of the linkage invariants /// described <seealso cref="LambdaMetafactory above"/> /// are violated </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public static CallSite altMetafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, Object... args) throws LambdaConversionException public static CallSite AltMetafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, params Object[] args) { MethodType samMethodType = (MethodType)args[0]; MethodHandle implMethod = (MethodHandle)args[1]; MethodType instantiatedMethodType = (MethodType)args[2]; int flags = (Integer)args[3]; Class[] markerInterfaces; MethodType[] bridges; int argIndex = 4; if ((flags & FLAG_MARKERS) != 0) { int markerCount = (Integer)args[argIndex++]; markerInterfaces = new Class[markerCount]; System.Array.Copy(args, argIndex, markerInterfaces, 0, markerCount); argIndex += markerCount; } else { markerInterfaces = EMPTY_CLASS_ARRAY; } if ((flags & FLAG_BRIDGES) != 0) { int bridgeCount = (Integer)args[argIndex++]; bridges = new MethodType[bridgeCount]; System.Array.Copy(args, argIndex, bridges, 0, bridgeCount); argIndex += bridgeCount; } else { bridges = EMPTY_MT_ARRAY; } bool isSerializable = ((flags & FLAG_SERIALIZABLE) != 0); if (isSerializable) { bool foundSerializableSupertype = invokedType.ReturnType().IsSubclassOf(typeof(Serializable)); foreach (Class c in markerInterfaces) { foundSerializableSupertype |= c.IsSubclassOf(typeof(Serializable)); } if (!foundSerializableSupertype) { markerInterfaces = Arrays.CopyOf(markerInterfaces, markerInterfaces.Length + 1); markerInterfaces[markerInterfaces.Length - 1] = typeof(Serializable); } } AbstractValidatingLambdaMetafactory mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, isSerializable, markerInterfaces, bridges); mf.ValidateMetafactoryArgs(); return(mf.BuildCallSite()); }
internal readonly MethodType[] AdditionalBridges; // Signatures of additional methods to bridge /// <summary> /// Meta-factory constructor. /// </summary> /// <param name="caller"> Stacked automatically by VM; represents a lookup context /// with the accessibility privileges of the caller. </param> /// <param name="invokedType"> Stacked automatically by VM; the signature of the /// invoked method, which includes the expected static /// type of the returned lambda object, and the static /// types of the captured arguments for the lambda. In /// the event that the implementation method is an /// instance method, the first argument in the invocation /// signature will correspond to the receiver. </param> /// <param name="samMethodName"> Name of the method in the functional interface to /// which the lambda or method reference is being /// converted, represented as a String. </param> /// <param name="samMethodType"> Type of the method in the functional interface to /// which the lambda or method reference is being /// converted, represented as a MethodType. </param> /// <param name="implMethod"> The implementation method which should be called /// (with suitable adaptation of argument types, return /// types, and adjustment for captured arguments) when /// methods of the resulting functional interface instance /// are invoked. </param> /// <param name="instantiatedMethodType"> The signature of the primary functional /// interface method after type variables are /// substituted with their instantiation from /// the capture site </param> /// <param name="isSerializable"> Should the lambda be made serializable? If set, /// either the target type or one of the additional SAM /// types must extend {@code Serializable}. </param> /// <param name="markerInterfaces"> Additional interfaces which the lambda object /// should implement. </param> /// <param name="additionalBridges"> Method types for additional signatures to be /// bridged to the implementation method </param> /// <exception cref="LambdaConversionException"> If any of the meta-factory protocol /// invariants are violated </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, boolean isSerializable, Class[] markerInterfaces, MethodType[] additionalBridges) throws LambdaConversionException internal AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, bool isSerializable, Class[] markerInterfaces, MethodType[] additionalBridges) { if ((caller.LookupModes() & MethodHandles.Lookup.PRIVATE) == 0) { throw new LambdaConversionException(string.Format("Invalid caller: {0}", caller.LookupClass().Name)); } this.TargetClass = caller.LookupClass(); this.InvokedType = invokedType; this.SamBase = invokedType.ReturnType(); this.SamMethodName = samMethodName; this.SamMethodType = samMethodType; this.ImplMethod = implMethod; this.ImplInfo = caller.RevealDirect(implMethod); this.ImplKind = ImplInfo.ReferenceKind; this.ImplIsInstanceMethod = ImplKind == MethodHandleInfo.REF_invokeVirtual || ImplKind == MethodHandleInfo.REF_invokeSpecial || ImplKind == MethodHandleInfo.REF_invokeInterface; this.ImplDefiningClass = ImplInfo.DeclaringClass; this.ImplMethodType = ImplInfo.MethodType; this.InstantiatedMethodType = instantiatedMethodType; this.IsSerializable = isSerializable; this.MarkerInterfaces = markerInterfaces; this.AdditionalBridges = additionalBridges; if (!SamBase.Interface) { throw new LambdaConversionException(string.Format("Functional interface {0} is not an interface", SamBase.Name)); } foreach (Class c in markerInterfaces) { if (!c.Interface) { throw new LambdaConversionException(string.Format("Marker interface {0} is not an interface", c.Name)); } } }
private LambdaForm MakeArgumentCombinationForm(int pos, MethodType combinerType, bool keepArguments, bool dropResult) { LambdaFormBuffer buf = Buffer(); buf.StartEdit(); int combinerArity = combinerType.ParameterCount(); int resultArity = (dropResult ? 0 : 1); assert(pos <= MethodType.MAX_JVM_ARITY); assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= LambdaForm.Arity_Renamed); assert(pos > 0); // cannot filter the MH arg itself assert(combinerType == combinerType.BasicType()); assert(combinerType.ReturnType() != typeof(void) || dropResult); BoundMethodHandle.SpeciesData oldData = OldSpeciesData(); BoundMethodHandle.SpeciesData newData = NewSpeciesData(L_TYPE); // The newly created LF will run with a different BMH. // Switch over any pre-existing BMH field references to the new BMH class. Name oldBaseAddress = LambdaForm.Parameter(0); // BMH holding the values buf.ReplaceFunctions(oldData.GetterFunctions(), newData.GetterFunctions(), oldBaseAddress); Name newBaseAddress = oldBaseAddress.withConstraint(newData); buf.RenameParameter(0, newBaseAddress); Name getCombiner = new Name(newData.GetterFunction(oldData.FieldCount()), newBaseAddress); Object[] combinerArgs = new Object[1 + combinerArity]; combinerArgs[0] = getCombiner; Name[] newParams; if (keepArguments) { newParams = new Name[0]; System.Array.Copy(LambdaForm.Names, pos + resultArity, combinerArgs, 1, combinerArity); } else { newParams = new Name[combinerArity]; BasicType[] newTypes = basicTypes(combinerType.ParameterList()); for (int i = 0; i < newTypes.Length; i++) { newParams[i] = new Name(pos + i, newTypes[i]); } System.Array.Copy(newParams, 0, combinerArgs, 1, combinerArity); } Name callCombiner = new Name(combinerType, combinerArgs); // insert the two new expressions int exprPos = LambdaForm.Arity(); buf.InsertExpression(exprPos + 0, getCombiner); buf.InsertExpression(exprPos + 1, callCombiner); // insert new arguments, if needed int argPos = pos + resultArity; // skip result parameter foreach (Name newParam in newParams) { buf.InsertParameter(argPos++, newParam); } assert(buf.LastIndexOf(callCombiner) == exprPos + 1 + newParams.Length); if (!dropResult) { buf.ReplaceParameterByCopy(pos, exprPos + 1 + newParams.Length); } return(buf.EndEdit()); }
internal virtual LambdaForm CollectArgumentArrayForm(int pos, MethodHandle arrayCollector) { MethodType collectorType = arrayCollector.Type(); int collectorArity = collectorType.ParameterCount(); assert(arrayCollector.IntrinsicName() == Intrinsic.NEW_ARRAY); Class arrayType = collectorType.ReturnType(); Class elementType = arrayType.ComponentType; BasicType argType = basicType(elementType); int argTypeKey = argType.ordinal(); if (argType.basicTypeClass() != elementType) { // return null if it requires more metadata (like String[].class) if (!elementType.Primitive) { return(null); } argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal(); } assert(collectorType.ParameterList().Equals(Collections.NCopies(collectorArity, elementType))); Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY; Transform key = Transform.Of(kind, pos, collectorArity, argTypeKey); LambdaForm form = GetInCache(key); if (form != null) { assert(form.Arity_Renamed == LambdaForm.Arity_Renamed - 1 + collectorArity); return(form); } LambdaFormBuffer buf = Buffer(); buf.StartEdit(); assert(pos + 1 <= LambdaForm.Arity_Renamed); assert(pos > 0); // cannot filter the MH arg itself Name[] newParams = new Name[collectorArity]; for (int i = 0; i < collectorArity; i++) { newParams[i] = new Name(pos + i, argType); } Name callCombiner = new Name(arrayCollector, (Object[])newParams); //... // insert the new expression int exprPos = LambdaForm.Arity(); buf.InsertExpression(exprPos, callCombiner); // insert new arguments int argPos = pos + 1; // skip result parameter foreach (Name newParam in newParams) { buf.InsertParameter(argPos++, newParam); } assert(buf.LastIndexOf(callCombiner) == exprPos + newParams.Length); buf.ReplaceParameterByCopy(pos, exprPos + newParams.Length); form = buf.EndEdit(); return(PutInCache(key, form)); }
/// <summary> /// Check the meta-factory arguments for errors </summary> /// <exception cref="LambdaConversionException"> if there are improper conversions </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: void validateMetafactoryArgs() throws LambdaConversionException internal virtual void ValidateMetafactoryArgs() { switch (ImplKind) { case MethodHandleInfo.REF_invokeInterface: case MethodHandleInfo.REF_invokeVirtual: case MethodHandleInfo.REF_invokeStatic: case MethodHandleInfo.REF_newInvokeSpecial: case MethodHandleInfo.REF_invokeSpecial: break; default: throw new LambdaConversionException(string.Format("Unsupported MethodHandle kind: {0}", ImplInfo)); } // Check arity: optional-receiver + captured + SAM == impl //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int implArity = implMethodType.parameterCount(); int implArity = ImplMethodType.ParameterCount(); //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int receiverArity = implIsInstanceMethod ? 1 : 0; int receiverArity = ImplIsInstanceMethod ? 1 : 0; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int capturedArity = invokedType.parameterCount(); int capturedArity = InvokedType.ParameterCount(); //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int samArity = samMethodType.parameterCount(); int samArity = SamMethodType.ParameterCount(); //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int instantiatedArity = instantiatedMethodType.parameterCount(); int instantiatedArity = InstantiatedMethodType.ParameterCount(); if (implArity + receiverArity != capturedArity + samArity) { throw new LambdaConversionException(string.Format("Incorrect number of parameters for {0} method {1}; {2:D} captured parameters, {3:D} functional interface method parameters, {4:D} implementation parameters", ImplIsInstanceMethod ? "instance" : "static", ImplInfo, capturedArity, samArity, implArity)); } if (instantiatedArity != samArity) { throw new LambdaConversionException(string.Format("Incorrect number of parameters for {0} method {1}; {2:D} instantiated parameters, {3:D} functional interface method parameters", ImplIsInstanceMethod ? "instance" : "static", ImplInfo, instantiatedArity, samArity)); } foreach (MethodType bridgeMT in AdditionalBridges) { if (bridgeMT.ParameterCount() != samArity) { throw new LambdaConversionException(string.Format("Incorrect number of parameters for bridge signature {0}; incompatible with {1}", bridgeMT, SamMethodType)); } } // If instance: first captured arg (receiver) must be subtype of class where impl method is defined //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int capturedStart; int capturedStart; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int samStart; int samStart; if (ImplIsInstanceMethod) { //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final Class receiverClass; Class receiverClass; // implementation is an instance method, adjust for receiver in captured variables / SAM arguments if (capturedArity == 0) { // receiver is function parameter capturedStart = 0; samStart = 1; receiverClass = InstantiatedMethodType.ParameterType(0); } else { // receiver is a captured variable capturedStart = 1; samStart = 0; receiverClass = InvokedType.ParameterType(0); } // check receiver type if (!receiverClass.IsSubclassOf(ImplDefiningClass)) { throw new LambdaConversionException(string.Format("Invalid receiver type {0}; not a subtype of implementation type {1}", receiverClass, ImplDefiningClass)); } Class implReceiverClass = ImplMethod.Type().ParameterType(0); if (implReceiverClass != ImplDefiningClass && !receiverClass.IsSubclassOf(implReceiverClass)) { throw new LambdaConversionException(string.Format("Invalid receiver type {0}; not a subtype of implementation receiver type {1}", receiverClass, implReceiverClass)); } } else { // no receiver capturedStart = 0; samStart = 0; } // Check for exact match on non-receiver captured arguments //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int implFromCaptured = capturedArity - capturedStart; int implFromCaptured = capturedArity - capturedStart; for (int i = 0; i < implFromCaptured; i++) { Class implParamType = ImplMethodType.ParameterType(i); Class capturedParamType = InvokedType.ParameterType(i + capturedStart); if (!capturedParamType.Equals(implParamType)) { throw new LambdaConversionException(string.Format("Type mismatch in captured lambda parameter {0:D}: expecting {1}, found {2}", i, capturedParamType, implParamType)); } } // Check for adaptation match on SAM arguments //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int samOffset = samStart - implFromCaptured; int samOffset = samStart - implFromCaptured; for (int i = implFromCaptured; i < implArity; i++) { Class implParamType = ImplMethodType.ParameterType(i); Class instantiatedParamType = InstantiatedMethodType.ParameterType(i + samOffset); if (!IsAdaptableTo(instantiatedParamType, implParamType, true)) { throw new LambdaConversionException(string.Format("Type mismatch for lambda argument {0:D}: {1} is not convertible to {2}", i, instantiatedParamType, implParamType)); } } // Adaptation match: return type Class expectedType = InstantiatedMethodType.ReturnType(); Class actualReturnType = (ImplKind == MethodHandleInfo.REF_newInvokeSpecial) ? ImplDefiningClass : ImplMethodType.ReturnType(); Class samReturnType = SamMethodType.ReturnType(); if (!IsAdaptableToAsReturn(actualReturnType, expectedType)) { throw new LambdaConversionException(string.Format("Type mismatch for lambda return: {0} is not convertible to {1}", actualReturnType, expectedType)); } if (!IsAdaptableToAsReturnStrict(expectedType, samReturnType)) { throw new LambdaConversionException(string.Format("Type mismatch for lambda expected return: {0} is not convertible to {1}", expectedType, samReturnType)); } foreach (MethodType bridgeMT in AdditionalBridges) { if (!IsAdaptableToAsReturnStrict(expectedType, bridgeMT.ReturnType())) { throw new LambdaConversionException(string.Format("Type mismatch for lambda expected return: {0} is not convertible to {1}", expectedType, bridgeMT.ReturnType())); } } }