internal static bool Emit(DynamicTypeWrapper.FinishContext context, ClassFile classFile, int constantPoolIndex, ClassFile.ConstantPoolItemInvokeDynamic cpi, CodeEmitter ilgen) { ClassFile.BootstrapMethod bsm = classFile.GetBootstrapMethod(cpi.BootstrapMethod); if (!IsLambdaMetafactory(classFile, bsm) && !IsLambdaAltMetafactory(classFile, bsm)) { return false; } LambdaMetafactory lmf = context.GetValue<LambdaMetafactory>(constantPoolIndex); if (lmf.ctor == null && !lmf.EmitImpl(context, classFile, cpi, bsm, ilgen)) { #if STATIC_COMPILER if (context.TypeWrapper.GetClassLoader().DisableDynamicBinding) { StaticCompiler.IssueMessage(Message.UnableToCreateLambdaFactory); } #endif return false; } ilgen.Emit(OpCodes.Newobj, lmf.ctor); // the CLR verification rules about type merging mean we have to explicitly cast to the interface type here ilgen.Emit(OpCodes.Castclass, cpi.GetRetType().TypeAsBaseType); return true; }
internal ReplacedMethodWrapper(ClassFile.ConstantPoolItemMI cpi, IKVM.Internal.MapXml.InstructionList code) : base(cpi.GetClassType(), cpi.Name, cpi.Signature, null, cpi.GetRetType(), cpi.GetArgTypes(), Modifiers.Public, MemberFlags.None) { this.code = code; }
private static bool MatchSignatures(MethodWrapper interfaceMethod, ClassFile.ConstantPoolItemMethodType samMethodType) { return interfaceMethod.ReturnType == samMethodType.GetRetType() && MatchTypes(interfaceMethod.GetParameters(), samMethodType.GetArgTypes()); }
private bool EmitImpl(DynamicTypeWrapper.FinishContext context, ClassFile classFile, ClassFile.ConstantPoolItemInvokeDynamic cpi, ClassFile.BootstrapMethod bsm, CodeEmitter ilgen) { if (HasUnloadable(cpi)) { Fail("cpi has unloadable"); return false; } bool serializable = false; TypeWrapper[] markers = TypeWrapper.EmptyArray; ClassFile.ConstantPoolItemMethodType[] bridges = null; if (bsm.ArgumentCount > 3) { AltFlags flags = (AltFlags)classFile.GetConstantPoolConstantInteger(bsm.GetArgument(3)); serializable = (flags & AltFlags.Serializable) != 0; int argpos = 4; if ((flags & AltFlags.Markers) != 0) { markers = new TypeWrapper[classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++))]; for (int i = 0; i < markers.Length; i++) { if ((markers[i] = classFile.GetConstantPoolClassType(bsm.GetArgument(argpos++))).IsUnloadable) { Fail("unloadable marker"); return false; } } } if ((flags & AltFlags.Bridges) != 0) { bridges = new ClassFile.ConstantPoolItemMethodType[classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++))]; for (int i = 0; i < bridges.Length; i++) { bridges[i] = classFile.GetConstantPoolConstantMethodType(bsm.GetArgument(argpos++)); if (HasUnloadable(bridges[i])) { Fail("unloadable bridge"); return false; } } } } ClassFile.ConstantPoolItemMethodType samMethodType = classFile.GetConstantPoolConstantMethodType(bsm.GetArgument(0)); ClassFile.ConstantPoolItemMethodHandle implMethod = classFile.GetConstantPoolConstantMethodHandle(bsm.GetArgument(1)); ClassFile.ConstantPoolItemMethodType instantiatedMethodType = classFile.GetConstantPoolConstantMethodType(bsm.GetArgument(2)); if (HasUnloadable(samMethodType) || HasUnloadable((ClassFile.ConstantPoolItemMI)implMethod.MemberConstantPoolItem) || HasUnloadable(instantiatedMethodType)) { Fail("bsm args has unloadable"); return false; } TypeWrapper interfaceType = cpi.GetRetType(); MethodWrapper[] methodList; if (!CheckSupportedInterfaces(context.TypeWrapper, interfaceType, markers, bridges, out methodList)) { Fail("unsupported interface"); return false; } if (serializable && Array.Exists(methodList, delegate(MethodWrapper mw) { return mw.Name == "writeReplace" && mw.Signature == "()Ljava.lang.Object;"; })) { Fail("writeReplace"); return false; } if (!IsSupportedImplMethod(implMethod, context.TypeWrapper, cpi.GetArgTypes(), instantiatedMethodType)) { Fail("implMethod " + implMethod.MemberConstantPoolItem.Class + "::" + implMethod.MemberConstantPoolItem.Name + implMethod.MemberConstantPoolItem.Signature); return false; } TypeWrapper[] implParameters = GetImplParameters(implMethod); CheckConstraints(instantiatedMethodType, samMethodType, cpi.GetArgTypes(), implParameters); if (bridges != null) { foreach (ClassFile.ConstantPoolItemMethodType bridge in bridges) { if (bridge.Signature == samMethodType.Signature) { Fail("bridge signature matches sam"); return false; } if (!CheckConstraints(instantiatedMethodType, bridge, cpi.GetArgTypes(), implParameters)) { Fail("bridge constraints"); return false; } } } if (instantiatedMethodType.GetRetType() != PrimitiveTypeWrapper.VOID) { TypeWrapper Rt = instantiatedMethodType.GetRetType(); TypeWrapper Ra = GetImplReturnType(implMethod); if (Ra == PrimitiveTypeWrapper.VOID || !IsAdaptable(Ra, Rt, true)) { Fail("The return type Rt is void, or the return type Ra is not void and is adaptable to Rt"); return false; } } MethodWrapper interfaceMethod = null; List<MethodWrapper> methods = new List<MethodWrapper>(); foreach (MethodWrapper mw in methodList) { if (mw.Name == cpi.Name && mw.Signature == samMethodType.Signature) { interfaceMethod = mw; methods.Add(mw); } else if (mw.IsAbstract && !IsObjectMethod(mw)) { methods.Add(mw); } } if (interfaceMethod == null || !interfaceMethod.IsAbstract || IsObjectMethod(interfaceMethod) || !MatchSignatures(interfaceMethod, samMethodType)) { Fail("interfaceMethod"); return false; } TypeBuilder tb = context.DefineAnonymousClass(); // we're not implementing the interfaces recursively (because we don't care about .NET Compact anymore), // but should we decide to do that, we'd need to somehow communicate to AnonymousTypeWrapper what the 'real' interface is tb.AddInterfaceImplementation(interfaceType.TypeAsBaseType); if (serializable && Array.IndexOf(markers, CoreClasses.java.io.Serializable.Wrapper) == -1) { tb.AddInterfaceImplementation(CoreClasses.java.io.Serializable.Wrapper.TypeAsBaseType); } foreach (TypeWrapper marker in markers) { tb.AddInterfaceImplementation(marker.TypeAsBaseType); } ctor = CreateConstructorAndDispatch(context, cpi, tb, methods, implParameters, samMethodType, implMethod, instantiatedMethodType, serializable); AddDefaultInterfaceMethods(context, methodList, tb); return true; }
private static void EmitDispatch(DynamicTypeWrapper.FinishContext context, TypeWrapper[] args, TypeBuilder tb, MethodWrapper interfaceMethod, TypeWrapper[] implParameters, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, FieldBuilder[] capturedFields) { MethodBuilder mb = interfaceMethod.GetDefineMethodHelper().DefineMethod(context.TypeWrapper, tb, interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); if (interfaceMethod.Name != interfaceMethod.RealName) { tb.DefineMethodOverride(mb, (MethodInfo)interfaceMethod.GetMethod()); } CodeEmitter ilgen = CodeEmitter.Create(mb); for (int i = 0; i < capturedFields.Length; i++) { ilgen.EmitLdarg(0); OpCode opc = OpCodes.Ldfld; if (i == 0 && args[0].IsGhost) { switch (implMethod.Kind) { case ClassFile.RefKind.invokeInterface: case ClassFile.RefKind.invokeVirtual: case ClassFile.RefKind.invokeSpecial: opc = OpCodes.Ldflda; break; } } ilgen.Emit(opc, capturedFields[i]); } for (int i = 0, count = interfaceMethod.GetParameters().Length, k = capturedFields.Length; i < count; i++) { ilgen.EmitLdarg(i + 1); TypeWrapper Ui = interfaceMethod.GetParameters()[i]; TypeWrapper Ti = instantiatedMethodType.GetArgTypes()[i]; TypeWrapper Aj = implParameters[i + k]; if (Ui == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } if (Ti != Ui) { if (Ti.IsGhost) { Ti.EmitConvStackTypeToSignatureType(ilgen, Ui); } else if (Ui.IsGhost) { Ui.EmitConvSignatureTypeToStackType(ilgen); } else { Ti.EmitCheckcast(ilgen); } } if (Ti != Aj) { if (Ti.IsPrimitive && !Aj.IsPrimitive) { Boxer.EmitBox(ilgen, Ti); } else if (!Ti.IsPrimitive && Aj.IsPrimitive) { TypeWrapper primitive = GetPrimitiveFromWrapper(Ti); Boxer.EmitUnbox(ilgen, primitive, false); if (primitive == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } } else if (Aj == PrimitiveTypeWrapper.LONG) { ilgen.Emit(OpCodes.Conv_I8); } else if (Aj == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Conv_R4); } else if (Aj == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Conv_R8); } } } switch (implMethod.Kind) { case ClassFile.RefKind.invokeVirtual: case ClassFile.RefKind.invokeInterface: ((MethodWrapper)implMethod.Member).EmitCallvirt(ilgen); break; case ClassFile.RefKind.newInvokeSpecial: ((MethodWrapper)implMethod.Member).EmitNewobj(ilgen); break; case ClassFile.RefKind.invokeStatic: case ClassFile.RefKind.invokeSpecial: ((MethodWrapper)implMethod.Member).EmitCall(ilgen); break; default: throw new InvalidOperationException(); } TypeWrapper Ru = interfaceMethod.ReturnType; TypeWrapper Ra = GetImplReturnType(implMethod); TypeWrapper Rt = instantiatedMethodType.GetRetType(); if (Ra == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } if (Ra != Ru) { if (Ru == PrimitiveTypeWrapper.VOID) { ilgen.Emit(OpCodes.Pop); } else if (Ra.IsGhost) { Ra.EmitConvSignatureTypeToStackType(ilgen); } else if (Ru.IsGhost) { Ru.EmitConvStackTypeToSignatureType(ilgen, Ra); } } if (Ra != Rt) { if (Rt.IsPrimitive) { if (Rt == PrimitiveTypeWrapper.VOID) { // already popped } else if (!Ra.IsPrimitive) { TypeWrapper primitive = GetPrimitiveFromWrapper(Ra); if (primitive != null) { Boxer.EmitUnbox(ilgen, primitive, false); } else { // If Q is not a primitive wrapper, cast Q to the base Wrapper(S); for example Number for numeric types EmitConvertingUnbox(ilgen, Rt); } } else if (Rt == PrimitiveTypeWrapper.LONG) { ilgen.Emit(OpCodes.Conv_I8); } else if (Rt == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Conv_R4); } else if (Rt == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Conv_R8); } } else if (Ra.IsPrimitive) { Boxer.EmitBox(ilgen, GetPrimitiveFromWrapper(Rt)); } else { Rt.EmitCheckcast(ilgen); } } ilgen.EmitTailCallPrevention(); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); }
private static MethodBuilder CreateConstructorAndDispatch(DynamicTypeWrapper.FinishContext context, ClassFile.ConstantPoolItemInvokeDynamic cpi, TypeBuilder tb, List<MethodWrapper> methods, TypeWrapper[] implParameters, ClassFile.ConstantPoolItemMethodType samMethodType, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, bool serializable) { TypeWrapper[] args = cpi.GetArgTypes(); // captured values Type[] capturedTypes = new Type[args.Length]; FieldBuilder[] capturedFields = new FieldBuilder[capturedTypes.Length]; for (int i = 0; i < capturedTypes.Length; i++) { capturedTypes[i] = args[i].TypeAsSignatureType; FieldAttributes attr = FieldAttributes.Private; if (i > 0 || !args[0].IsGhost) { attr |= FieldAttributes.InitOnly; } capturedFields[i] = tb.DefineField("arg$" + (i + 1), capturedTypes[i], attr); } // constructor MethodBuilder ctor = ReflectUtil.DefineConstructor(tb, MethodAttributes.Assembly, capturedTypes); CodeEmitter ilgen = CodeEmitter.Create(ctor); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Call, Types.Object.GetConstructor(Type.EmptyTypes)); for (int i = 0; i < capturedTypes.Length; i++) { ilgen.EmitLdarg(0); ilgen.EmitLdarg(i + 1); ilgen.Emit(OpCodes.Stfld, capturedFields[i]); } ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); // dispatch methods foreach (MethodWrapper mw in methods) { EmitDispatch(context, args, tb, mw, implParameters, implMethod, instantiatedMethodType, capturedFields); } // writeReplace method if (serializable) { MethodBuilder writeReplace = tb.DefineMethod("writeReplace", MethodAttributes.Private, Types.Object, Type.EmptyTypes); ilgen = CodeEmitter.Create(writeReplace); context.TypeWrapper.EmitClassLiteral(ilgen); ilgen.Emit(OpCodes.Ldstr, cpi.GetRetType().Name.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, cpi.Name); ilgen.Emit(OpCodes.Ldstr, samMethodType.Signature.Replace('.', '/')); ilgen.EmitLdc_I4((int)implMethod.Kind); ilgen.Emit(OpCodes.Ldstr, implMethod.Class.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, implMethod.Name); ilgen.Emit(OpCodes.Ldstr, implMethod.Signature.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, instantiatedMethodType.Signature.Replace('.', '/')); ilgen.EmitLdc_I4(capturedFields.Length); ilgen.Emit(OpCodes.Newarr, Types.Object); for (int i = 0; i < capturedFields.Length; i++) { ilgen.Emit(OpCodes.Dup); ilgen.EmitLdc_I4(i); ilgen.EmitLdarg(0); ilgen.Emit(OpCodes.Ldfld, capturedFields[i]); if (args[i].IsPrimitive) { Boxer.EmitBox(ilgen, args[i]); } else if (args[i].IsGhost) { args[i].EmitConvSignatureTypeToStackType(ilgen); } ilgen.Emit(OpCodes.Stelem, Types.Object); } MethodWrapper ctorSerializedLambda = ClassLoaderWrapper.LoadClassCritical("java.lang.invoke.SerializedLambda").GetMethodWrapper(StringConstants.INIT, "(Ljava.lang.Class;Ljava.lang.String;Ljava.lang.String;Ljava.lang.String;ILjava.lang.String;Ljava.lang.String;Ljava.lang.String;Ljava.lang.String;[Ljava.lang.Object;)V", false); ctorSerializedLambda.Link(); ctorSerializedLambda.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); if (!context.TypeWrapper.GetClassLoader().NoAutomagicSerialization) { // add .NET serialization interop support Serialization.MarkSerializable(tb); Serialization.AddGetObjectData(tb); } } return ctor; }
private static bool IsSubTypeOf(ClassFile.ConstantPoolItemMethodType instantiatedMethodType, ClassFile.ConstantPoolItemMethodType samMethodType) { TypeWrapper[] T = instantiatedMethodType.GetArgTypes(); TypeWrapper[] U = samMethodType.GetArgTypes(); if (T.Length != U.Length) { return false; } for (int i = 0; i < T.Length; i++) { if (!T[i].IsAssignableTo(U[i])) { return false; } } TypeWrapper Rt = instantiatedMethodType.GetRetType(); TypeWrapper Ru = samMethodType.GetRetType(); return Rt.IsAssignableTo(Ru); }
private static bool HasUnloadable(ClassFile.ConstantPoolItemMI cpi) { return HasUnloadable(cpi.GetArgTypes()) || cpi.GetRetType().IsUnloadable; }