private static bool CheckOptionalArgs(ClassFile classFile, ClassFile.BootstrapMethod bsm, ClassFile.ConstantType type, ref int argpos) { if (bsm.ArgumentCount - argpos < 1) { return(false); } if (classFile.GetConstantPoolConstantType(bsm.GetArgument(argpos)) != ClassFile.ConstantType.Integer) { return(false); } int count = classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++)); if (count < 0 || bsm.ArgumentCount - argpos < count) { return(false); } for (int i = 0; i < count; i++) { if (classFile.GetConstantPoolConstantType(bsm.GetArgument(argpos++)) != type) { return(false); } } return(true); }
internal static bool Emit(DynamicTypeWrapper.FinishContext context, ClassFile classFile, int constantPoolIndex, ClassFile.ConstantPoolItemInvokeDynamic cpi, CodeEmitter ilgen) { #if !WINRT 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); #else throw new NotImplementedException(); #endif }
private static bool IsLambdaMetafactory(ClassFile classFile, ClassFile.BootstrapMethod bsm) { ClassFile.ConstantPoolItemMethodHandle mh; return(bsm.ArgumentCount == 3 && classFile.GetConstantPoolConstantType(bsm.GetArgument(0)) == ClassFile.ConstantType.MethodType && classFile.GetConstantPoolConstantType(bsm.GetArgument(1)) == ClassFile.ConstantType.MethodHandle && classFile.GetConstantPoolConstantType(bsm.GetArgument(2)) == ClassFile.ConstantType.MethodType && (mh = classFile.GetConstantPoolConstantMethodHandle(bsm.BootstrapMethodIndex)).Kind == ClassFile.RefKind.invokeStatic && IsLambdaMetafactory(mh.Member)); }
private static bool IsLambdaAltMetafactory(ClassFile classFile, ClassFile.BootstrapMethod bsm) { ClassFile.ConstantPoolItemMethodHandle mh; AltFlags flags; int argpos = 4; return(bsm.ArgumentCount >= 4 && (mh = classFile.GetConstantPoolConstantMethodHandle(bsm.BootstrapMethodIndex)).Kind == ClassFile.RefKind.invokeStatic && IsLambdaAltMetafactory(mh.Member) && classFile.GetConstantPoolConstantType(bsm.GetArgument(0)) == ClassFile.ConstantType.MethodType && classFile.GetConstantPoolConstantType(bsm.GetArgument(1)) == ClassFile.ConstantType.MethodHandle && classFile.GetConstantPoolConstantType(bsm.GetArgument(2)) == ClassFile.ConstantType.MethodType && classFile.GetConstantPoolConstantType(bsm.GetArgument(3)) == ClassFile.ConstantType.Integer && ((flags = (AltFlags)classFile.GetConstantPoolConstantInteger(bsm.GetArgument(3))) & ~AltFlags.Mask) == 0 && ((flags & AltFlags.Markers) == 0 || CheckOptionalArgs(classFile, bsm, ClassFile.ConstantType.Class, ref argpos)) && ((flags & AltFlags.Bridges) == 0 || CheckOptionalArgs(classFile, bsm, ClassFile.ConstantType.MethodType, ref argpos)) && argpos == bsm.ArgumentCount); }
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); }