diff options
author | jfrijters <jfrijters> | 2014-07-01 19:12:34 +0400 |
---|---|---|
committer | jfrijters <jfrijters> | 2014-07-01 19:12:34 +0400 |
commit | baa72377e131fa1d3a5bce2529e860f0ba40b0f9 (patch) | |
tree | 2d5a278d857c1c48e274e97f98840216441ba755 | |
parent | 3bfe04144498cb03e1ea1ccecf553dc85bbe70b7 (diff) |
Added intrinsic for LambdaMetafactory.metafactory().
-rw-r--r-- | ikvmc.8.csproj | 1 | ||||
-rw-r--r-- | ikvmc/CompilerClassLoader.cs | 4 | ||||
-rw-r--r-- | ikvmc/ikvmc.build | 1 | ||||
-rw-r--r-- | openjdk/response.txt | 46 | ||||
-rw-r--r-- | runtime/ClassLoaderWrapper.cs | 18 | ||||
-rw-r--r-- | runtime/DynamicTypeWrapper.cs | 59 | ||||
-rw-r--r-- | runtime/IKVM.Runtime.8.csproj | 1 | ||||
-rw-r--r-- | runtime/LambdaMetafactory.cs | 771 | ||||
-rw-r--r-- | runtime/TypeWrapper.cs | 61 | ||||
-rw-r--r-- | runtime/compiler.cs | 5 | ||||
-rw-r--r-- | runtime/runtime.build | 1 |
11 files changed, 925 insertions, 43 deletions
diff --git a/ikvmc.8.csproj b/ikvmc.8.csproj index 0f5d45bf..188dba9f 100644 --- a/ikvmc.8.csproj +++ b/ikvmc.8.csproj @@ -120,6 +120,7 @@ <SubType>Code</SubType> </Compile> <Compile Include="runtime\JsrInliner.cs" /> + <Compile Include="runtime\LambdaMetafactory.cs" /> <Compile Include="runtime\LocalVars.cs" /> <Compile Include="runtime\MemberWrapper.cs"> <SubType>Code</SubType> diff --git a/ikvmc/CompilerClassLoader.cs b/ikvmc/CompilerClassLoader.cs index 23b938dd..b71e0f94 100644 --- a/ikvmc/CompilerClassLoader.cs +++ b/ikvmc/CompilerClassLoader.cs @@ -3681,6 +3681,7 @@ namespace IKVM.Internal WrongClassName = 135, ReflectionCallerClassRequiresCallerID = 136, LegacyAssemblyAttributesFound = 137, + UnableToCreateLambdaFactory = 138, UnknownWarning = 999, // This is where the errors start StartErrors = 4000, @@ -4035,6 +4036,9 @@ namespace IKVM.Internal case Message.LegacyAssemblyAttributesFound: msg = "Legacy assembly attributes container found. Please use the -assemblyattributes:<file> option."; break; + case Message.UnableToCreateLambdaFactory: + msg = "Unable to create static lambda factory."; + break; case Message.UnableToCreateProxy: msg = "Unable to create proxy \"{0}\"" + Environment.NewLine + " (\"{1}\")"; diff --git a/ikvmc/ikvmc.build b/ikvmc/ikvmc.build index a77ed836..06dda99f 100644 --- a/ikvmc/ikvmc.build +++ b/ikvmc/ikvmc.build @@ -61,6 +61,7 @@ <include name="../runtime/intrinsics.cs" /> <include name="../runtime/JavaException.cs" /> <include name="../runtime/JsrInliner.cs" /> + <include name="../runtime/LambdaMetafactory.cs" /> <include name="../runtime/LocalVars.cs" /> <include name="../runtime/MemberWrapper.cs" /> <include name="../runtime/MethodHandleUtil.cs" /> diff --git a/openjdk/response.txt b/openjdk/response.txt index c7d6e965..0371c2e1 100644 --- a/openjdk/response.txt +++ b/openjdk/response.txt @@ -191,7 +191,7 @@ } { -out:IKVM.OpenJDK.Corba.dll - -baseaddress:0x57380000 + -baseaddress:0x57320000 -recurse:resources.zip/com/sun/corba/* -recurse:resources.zip/com/sun/jndi/cosnaming/jndiprovider.properties -resource:com/sun/corba/se/impl/logging/LogStrings.properties=@OPENJDK@/build/linux-x86_64-normal-server-release/jdk/classes/com/sun/corba/se/impl/logging/LogStrings.properties @@ -312,7 +312,7 @@ } { -out:IKVM.OpenJDK.XML.API.dll - -baseaddress:0x579B0000 + -baseaddress:0x57950000 -resource:META-INF/services/sun.util.spi.XmlPropertiesProvider=@OPENJDK@/jdk/src/share/classes/sun/util/xml/META-INF/services/sun.util.spi.XmlPropertiesProvider @OPENJDK@/jaxp/src/javax/xml/*.class @OPENJDK@/jaxp/src/javax/xml/datatype/*.class @@ -347,7 +347,7 @@ } { -out:IKVM.OpenJDK.XML.XPath.dll - -baseaddress:0x57A70000 + -baseaddress:0x57A10000 -recurse:resources.zip/com/sun/org/apache/xalan/internal/res/* @OPENJDK@/jaxp/src/com/sun/org/apache/xalan/internal/extensions/*.class @OPENJDK@/jaxp/src/com/sun/org/apache/xalan/internal/res/*.class @@ -372,7 +372,7 @@ } { -out:IKVM.OpenJDK.XML.Parse.dll - -baseaddress:0x57DD0000 + -baseaddress:0x57D70000 -recurse:resources.zip/com/sun/org/apache/xerces/* -recurse:resources.zip/com/sun/org/apache/xml/internal/* @OPENJDK@/jaxp/src/com/sun/org/apache/bcel/internal/util/SecuritySupport.class @@ -434,7 +434,7 @@ } { -out:IKVM.OpenJDK.XML.Transform.dll - -baseaddress:0x585E0000 + -baseaddress:0x58580000 @OPENJDK@/jaxp/src/com/sun/java_cup/internal/runtime/*.class @OPENJDK@/jaxp/src/com/sun/org/apache/bcel/internal/*.class @OPENJDK@/jaxp/src/com/sun/org/apache/bcel/internal/classfile/*.class @@ -458,7 +458,7 @@ } { -out:IKVM.OpenJDK.XML.Bind.dll - -baseaddress:0x58A30000 + -baseaddress:0x589D0000 -recurse:resources.zip/javax/xml/bind/* -recurse:resources.zip/com/sun/xml/internal/bind/* -recurse:resources.zip/com/sun/xml/internal/fastinfoset/* @@ -517,7 +517,7 @@ } { -out:IKVM.OpenJDK.XML.WebServices.dll - -baseaddress:0x58E50000 + -baseaddress:0x58DF0000 -recurse:resources.zip/com/sun/xml/internal/messaging/* -recurse:resources.zip/com/sun/xml/internal/ws/* @OPENJDK@/jaxws/src/share/jaxws_classes/com/oracle/webservices/internal/api/*.class @@ -658,7 +658,7 @@ } { -out:IKVM.OpenJDK.XML.Crypto.dll - -baseaddress:0x59660000 + -baseaddress:0x59600000 @OPENJDK@/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/*.class @OPENJDK@/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/*.class @OPENJDK@/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/*.class @@ -694,7 +694,7 @@ } { -out:IKVM.OpenJDK.SwingAWT.dll - -baseaddress:0x597E0000 + -baseaddress:0x59780000 -remap:swingawt.xml -resource:META-INF/services/sun.java2d.pipe.RenderingEngine=resources/META-INF/services/sun.java2d.pipe.RenderingEngine -resource:META-INF/services/sun.java2d.cmm.CMMServiceProvider=@OPENJDK@/jdk/src/share/classes/sun/java2d/cmm/lcms/META-INF/services/sun.java2d.cmm.CMMServiceProvider @@ -794,14 +794,14 @@ } { -out:IKVM.OpenJDK.Charsets.dll - -baseaddress:0x5AA10000 + -baseaddress:0x5A9B0000 -resource:sun/nio/cs/ext/sjis0213.dat=@OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/nio/cs/ext/sjis0213.dat @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/nio/cs/ext/*.class @OPENJDK@/jdk/src/share/classes/sun/nio/cs/ext/*.class } { -out:IKVM.OpenJDK.Util.dll - -baseaddress:0x5AF20000 + -baseaddress:0x5AEC0000 -recurse:resources.zip/com/sun/java/util/jar/pack/intrinsic.properties -recurse:resources.zip/sun/launcher/resources/* -resource:META-INF/services/java.nio.file.spi.FileSystemProvider=@OPENJDK@/jdk/src/share/demo/nio/zipfs/src/META-INF/services/java.nio.file.spi.FileSystemProvider @@ -826,7 +826,7 @@ } { -out:IKVM.OpenJDK.Text.dll - -baseaddress:0x5B1F0000 + -baseaddress:0x5B190000 -recurse:resources.zip/sun/text/resources/* @OPENJDK@/jdk/src/share/classes/java/text/*.class @OPENJDK@/jdk/src/share/classes/java/text/spi/*.class @@ -838,7 +838,7 @@ } { -out:IKVM.OpenJDK.Security.dll - -baseaddress:0x5B3A0000 + -baseaddress:0x5B340000 -remap:security.xml sun/security/jgss/wrapper/*.class @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/security/util/*.class @@ -912,7 +912,7 @@ } { -out:IKVM.OpenJDK.Management.dll - -baseaddress:0x5BBE0000 + -baseaddress:0x5BB80000 java/lang/management/*.class sun/management/*.class rmistubs/org/omg/stub/javax/management/remote/rmi/*.class @@ -946,7 +946,7 @@ } { -out:IKVM.OpenJDK.Misc.dll - -baseaddress:0x5BF70000 + -baseaddress:0x5BF10000 @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/misc/resources/*.class @OPENJDK@/corba/src/share/classes/javax/activity/*.class @OPENJDK@/jaxws/src/share/jaxws_classes/javax/annotation/*.class @@ -977,7 +977,7 @@ } { -out:IKVM.OpenJDK.Naming.dll - -baseaddress:0x5C030000 + -baseaddress:0x5BFD0000 -recurse:resources.zip/com/sun/jndi/ldap/jndiprovider.properties -resource:META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor=@OPENJDK@/jdk/src/share/classes/sun/net/spi/nameservice/dns/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor sun/net/dns/*.class @@ -1003,7 +1003,7 @@ } { -out:IKVM.OpenJDK.Jdbc.dll - -baseaddress:0x5C1B0000 + -baseaddress:0x5C150000 -resource:META-INF/services/java.sql.Driver=resources/META-INF/services/java.sql.Driver -recurse:resources.zip/com/sun/rowset/* -recurse:resources.zip/javax/sql/* @@ -1020,7 +1020,7 @@ } { -out:IKVM.OpenJDK.Remoting.dll - -baseaddress:0x5C330000 + -baseaddress:0x5C2D0000 -recurse:resources.zip/sun/rmi/* rmistubs/com/sun/jndi/rmi/registry/*.class rmistubs/java/rmi/activation/*.class @@ -1046,7 +1046,7 @@ } { -out:IKVM.OpenJDK.Beans.dll - -baseaddress:0x5C450000 + -baseaddress:0x5C3F0000 -resource:META-INF/mailcap.default=@OPENJDK@/jaxws/src/share/jaf_classes/META-INF/mailcap.default -resource:META-INF/mimetypes.default=@OPENJDK@/jaxws/src/share/jaf_classes/META-INF/mimetypes.default @OPENJDK@/jaxws/src/share/jaf_classes/com/sun/activation/registries/*.class @@ -1062,7 +1062,7 @@ } { -out:IKVM.OpenJDK.Media.dll - -baseaddress:0x5C540000 + -baseaddress:0x5C4E0000 -resource:META-INF/services/javax.print.PrintServiceLookup=@OPENJDK@/jdk/src/windows/classes/sun/print/services/javax.print.PrintServiceLookup -resource:META-INF/services/javax.print.StreamPrintServiceFactory=@OPENJDK@/jdk/src/windows/classes/sun/print/services/javax.print.StreamPrintServiceFactory -resource:META-INF/services/javax.sound.midi.spi.MidiDeviceProvider=@OPENJDK@/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiDeviceProvider @@ -1109,7 +1109,7 @@ } { -out:IKVM.OpenJDK.Nashorn.dll - -baseaddress:0x5C7B0000 + -baseaddress:0x5C750000 -resource:META-INF/services/javax.script.ScriptEngineFactory=@OPENJDK@/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory -resource:jdk/nashorn/internal/runtime/resources/version.properties=resources/nashorn/version.properties -recurse:@OPENJDK@/nashorn/src/*.js @@ -1144,7 +1144,7 @@ } { -out:IKVM.OpenJDK.Localedata.dll - -baseaddress:0x5CC00000 + -baseaddress:0x5CBA0000 @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/util/resources/*.class @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/util/resources/ar/*.class @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/util/resources/be/*.class @@ -1245,7 +1245,7 @@ } { -out:IKVM.OpenJDK.Cldrdata.dll - -baseaddress:0x5D0E0000 + -baseaddress:0x5D080000 @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/text/resources/cldr/*.class @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/text/resources/cldr/aa/*.class @OPENJDK@/build/linux-x86_64-normal-server-release/jdk/gensrc/sun/text/resources/cldr/af/*.class diff --git a/runtime/ClassLoaderWrapper.cs b/runtime/ClassLoaderWrapper.cs index 19a52882..d9fba6e9 100644 --- a/runtime/ClassLoaderWrapper.cs +++ b/runtime/ClassLoaderWrapper.cs @@ -1093,6 +1093,24 @@ namespace IKVM.Internal } } #endif + if(AnonymousTypeWrapper.IsAnonymous(type)) + { + Dictionary<Type, TypeWrapper> typeToTypeWrapper; +#if CLASSGC + typeToTypeWrapper = loader != null ? loader.typeToTypeWrapper : globalTypeToTypeWrapper; +#else + typeToTypeWrapper = globalTypeToTypeWrapper; +#endif + TypeWrapper tw = new AnonymousTypeWrapper(type); + lock(typeToTypeWrapper) + { + if(!typeToTypeWrapper.TryGetValue(type, out wrapper)) + { + typeToTypeWrapper.Add(type, wrapper = tw); + } + } + return wrapper; + } #if !STATIC_COMPILER && !STUB_GENERATOR if(ReflectUtil.IsReflectionOnly(type)) { diff --git a/runtime/DynamicTypeWrapper.cs b/runtime/DynamicTypeWrapper.cs index 29d6389f..c9578b03 100644 --- a/runtime/DynamicTypeWrapper.cs +++ b/runtime/DynamicTypeWrapper.cs @@ -3999,6 +3999,11 @@ namespace IKVM.Internal this.typeBuilder = typeBuilder; } + internal TypeWrapper TypeWrapper + { + get { return wrapper; } + } + internal T GetValue<T>(int key) where T : class, new() { @@ -5152,31 +5157,36 @@ namespace IKVM.Internal mb = methods[i].GetDefineMethodHelper().DefineMethod(wrapper.GetClassLoader().GetTypeWrapperFactory(), typeBuilder, NamePrefix.DefaultMethod + mb.Name, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, typeBuilder, false); } - CodeEmitter ilgen = CodeEmitter.Create(mb); - if (mmw.BaseMethod.DeclaringType.IsGhost) - { - CodeEmitterLocal local = ilgen.DeclareLocal(mmw.BaseMethod.DeclaringType.TypeAsSignatureType); - ilgen.Emit(OpCodes.Ldloca, local); - ilgen.EmitLdarg(0); - ilgen.Emit(OpCodes.Stfld, mmw.BaseMethod.DeclaringType.GhostRefField); - ilgen.Emit(OpCodes.Ldloca, local); - } - else - { - ilgen.EmitLdarg(0); - } - for (int j = 0, count = mmw.GetParameters().Length; j < count; j++) - { - ilgen.EmitLdarg(j + 1); - } - ilgen.Emit(OpCodes.Call, DefaultInterfaceMethodWrapper.GetImpl(mmw.BaseMethod)); - ilgen.Emit(OpCodes.Ret); - ilgen.DoEmit(); + EmitCallDefaultInterfaceMethod(mb, mmw.BaseMethod); } } } } + internal static void EmitCallDefaultInterfaceMethod(MethodBuilder mb, MethodWrapper defaultMethod) + { + CodeEmitter ilgen = CodeEmitter.Create(mb); + if (defaultMethod.DeclaringType.IsGhost) + { + CodeEmitterLocal local = ilgen.DeclareLocal(defaultMethod.DeclaringType.TypeAsSignatureType); + ilgen.Emit(OpCodes.Ldloca, local); + ilgen.EmitLdarg(0); + ilgen.Emit(OpCodes.Stfld, defaultMethod.DeclaringType.GhostRefField); + ilgen.Emit(OpCodes.Ldloca, local); + } + else + { + ilgen.EmitLdarg(0); + } + for (int j = 0, count = defaultMethod.GetParameters().Length; j < count; j++) + { + ilgen.EmitLdarg(j + 1); + } + ilgen.Emit(OpCodes.Call, DefaultInterfaceMethodWrapper.GetImpl(defaultMethod)); + ilgen.Emit(OpCodes.Ret); + ilgen.DoEmit(); + } + #if STATIC_COMPILER private void AddAccessStubs() { @@ -6412,6 +6422,15 @@ namespace IKVM.Internal return tb; } + // this is used to define intrinsified anonymous classes (in the Unsafe.defineAnonymousClass() sense) + internal TypeBuilder DefineAnonymousClass() + { + int id = nestedTypeBuilders == null ? 0 : nestedTypeBuilders.Count; + TypeBuilder tb = typeBuilder.DefineNestedType(NestedTypeName.IntrinsifiedAnonymousClass + id, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.SpecialName | TypeAttributes.BeforeFieldInit); + RegisterNestedTypeBuilder(tb); + return tb; + } + private MethodBuilder DefineHelperMethod(string name, Type returnType, Type[] parameterTypes) { #if STATIC_COMPILER diff --git a/runtime/IKVM.Runtime.8.csproj b/runtime/IKVM.Runtime.8.csproj index 5635c0fd..0418b8ed 100644 --- a/runtime/IKVM.Runtime.8.csproj +++ b/runtime/IKVM.Runtime.8.csproj @@ -144,6 +144,7 @@ <SubType>Code</SubType> </Compile> <Compile Include="JsrInliner.cs" /> + <Compile Include="LambdaMetafactory.cs" /> <Compile Include="LocalVars.cs" /> <Compile Include="MemberWrapper.cs"> <SubType>Code</SubType> diff --git a/runtime/LambdaMetafactory.cs b/runtime/LambdaMetafactory.cs new file mode 100644 index 00000000..99d817d8 --- /dev/null +++ b/runtime/LambdaMetafactory.cs @@ -0,0 +1,771 @@ +/* + Copyright (C) 2014 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +#if STATIC_COMPILER +using IKVM.Reflection; +using IKVM.Reflection.Emit; +using Type = IKVM.Reflection.Type; +#else +using System.Reflection; +using System.Reflection.Emit; +#endif + +namespace IKVM.Internal +{ + static class LambdaMetafactory + { + internal static bool Emit(DynamicTypeWrapper.FinishContext context, ClassFile classFile, ClassFile.ConstantPoolItemInvokeDynamic cpi, CodeEmitter ilgen) + { + ClassFile.BootstrapMethod bsm = classFile.GetBootstrapMethod(cpi.BootstrapMethod); + if (!IsLambdaMetafactory(classFile, bsm)) + { + return false; + } + if (!EmitImpl(context, classFile, cpi, bsm, ilgen)) + { +#if STATIC_COMPILER + if (context.TypeWrapper.GetClassLoader().DisableDynamicBinding) + { + StaticCompiler.IssueMessage(Message.UnableToCreateLambdaFactory); + } +#endif + return false; + } + return true; + } + + private static bool EmitImpl(DynamicTypeWrapper.FinishContext context, ClassFile classFile, ClassFile.ConstantPoolItemInvokeDynamic cpi, ClassFile.BootstrapMethod bsm, CodeEmitter ilgen) + { + if (HasUnloadable(cpi)) + { + Fail("cpi has unloadable"); + 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 (!IsSupportedInterface(interfaceType, out methodList)) + { + Fail("interfaceType " + interfaceType.Name); + return false; + } + if (!interfaceType.IsAccessibleFrom(context.TypeWrapper)) + { + Fail("interfaceType not accessible"); + return false; + } + if (!IsSupportedImplMethod(implMethod, context.TypeWrapper, cpi.GetArgTypes(), instantiatedMethodType)) + { + Fail("implMethod " + implMethod.MemberConstantPoolItem.Class + "::" + implMethod.MemberConstantPoolItem.Name + implMethod.MemberConstantPoolItem.Signature); + return false; + } + if (!IsSubTypeOf(instantiatedMethodType, samMethodType)) + { + Fail("instantiatedMethodType <= samMethodType"); + return false; + } + TypeWrapper[] implParameters = GetImplParameters(implMethod); + if (cpi.GetArgTypes().Length + samMethodType.GetArgTypes().Length != implParameters.Length) + { + Fail("K + N = M"); + return false; + } + for (int i = 0, K = cpi.GetArgTypes().Length; i < K; i++) + { + if (!cpi.GetArgTypes()[i].IsSubTypeOf(implParameters[i])) + { + Fail("For i=1..K, Di = Ai"); + return false; + } + } + for (int i = 0, N = samMethodType.GetArgTypes().Length, k = cpi.GetArgTypes().Length; i < N; i++) + { + if (!IsAdaptable(instantiatedMethodType.GetArgTypes()[i], implParameters[i + k], false)) + { + Fail("For i=1..N, Ti is adaptable to Aj, where j=i+k (in" + context.TypeWrapper.Name + ")"); + 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"); + Console.WriteLine("Ra = " + Ra.SigName); + Console.WriteLine("Rt = " + Rt.SigName); + return false; + } + } + MethodWrapper interfaceMethod = null; + foreach (MethodWrapper mw in methodList) + { + if (mw.Name == cpi.Name && mw.Signature == samMethodType.Signature) + { + interfaceMethod = mw; + break; + } + } + 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); + TypeWrapperFactory factory = context.TypeWrapper.GetClassLoader().GetTypeWrapperFactory(); + MethodBuilder ctor = CreateConstructorAndDispatch(factory, cpi.GetArgTypes(), tb, interfaceMethod, implParameters, samMethodType, implMethod, instantiatedMethodType); + AddDefaultInterfaceMethods(factory, methodList, tb); + ilgen.Emit(OpCodes.Newobj, ctor); + // the CLR verification rules about type merging mean we have to explicitly cast to the interface type here + ilgen.Emit(OpCodes.Castclass, interfaceType.TypeAsBaseType); + return true; + } + + [Conditional("TRACE_LAMBDA_METAFACTORY")] + private static void Fail(string msg) + { + Console.WriteLine("Fail: " + msg); + } + + private static TypeWrapper[] GetImplParameters(ClassFile.ConstantPoolItemMethodHandle implMethod) + { + MethodWrapper mw = (MethodWrapper)implMethod.Member; + TypeWrapper[] parameters = mw.GetParameters(); + if (mw.IsStatic || mw.IsConstructor) + { + return parameters; + } + return ArrayUtil.Concat(mw.DeclaringType, parameters); + } + + private static TypeWrapper GetImplReturnType(ClassFile.ConstantPoolItemMethodHandle implMethod) + { + return implMethod.Kind == ClassFile.RefKind.newInvokeSpecial + ? implMethod.Member.DeclaringType + : ((MethodWrapper)implMethod.Member).ReturnType; + } + + private static bool IsAdaptable(TypeWrapper Q, TypeWrapper S, bool isReturn) + { + if (Q == S) + { + return true; + } + + if (Q.IsPrimitive) + { + if (S.IsPrimitive) + { + // Q can be converted to S via a primitive widening conversion + switch (Q.SigName[0] | S.SigName[0] << 8) + { + case 'B' | 'S' << 8: + case 'B' | 'I' << 8: + case 'B' | 'J' << 8: + case 'B' | 'F' << 8: + case 'B' | 'D' << 8: + case 'S' | 'I' << 8: + case 'S' | 'J' << 8: + case 'S' | 'F' << 8: + case 'S' | 'D' << 8: + case 'C' | 'I' << 8: + case 'C' | 'J' << 8: + case 'C' | 'F' << 8: + case 'C' | 'D' << 8: + case 'I' | 'J' << 8: + case 'I' | 'F' << 8: + case 'I' | 'D' << 8: + case 'J' | 'F' << 8: + case 'J' | 'D' << 8: + case 'F' | 'D' << 8: + return true; + default: + return false; + } + } + else + { + // S is a supertype of the Wrapper(Q) + return GetWrapper(Q).IsAssignableTo(S); + } + } + else if (isReturn) + { + return true; + } + else + { + if (S.IsPrimitive) + { + // If Q is a primitive wrapper, check that Primitive(Q) can be widened to S + TypeWrapper primitive = GetPrimitiveFromWrapper(Q); + return primitive != null && IsAdaptable(primitive, S, isReturn); + } + else + { + // for parameter types: S is a supertype of Q + return Q.IsAssignableTo(S); + } + } + } + + private static TypeWrapper GetWrapper(TypeWrapper primitive) + { + Debug.Assert(primitive.IsPrimitive); + switch (primitive.SigName[0]) + { + case 'Z': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Boolean"); + case 'B': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Byte"); + case 'S': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Short"); + case 'C': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Character"); + case 'I': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Integer"); + case 'J': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Long"); + case 'F': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Float"); + case 'D': + return ClassLoaderWrapper.LoadClassCritical("java.lang.Double"); + default: + throw new InvalidOperationException(); + } + } + + private static TypeWrapper GetPrimitiveFromWrapper(TypeWrapper wrapper) + { + switch (wrapper.Name) + { + case "java.lang.Boolean": + return PrimitiveTypeWrapper.BOOLEAN; + case "java.lang.Byte": + return PrimitiveTypeWrapper.BYTE; + case "java.lang.Short": + return PrimitiveTypeWrapper.SHORT; + case "java.lang.Character": + return PrimitiveTypeWrapper.CHAR; + case "java.lang.Integer": + return PrimitiveTypeWrapper.INT; + case "java.lang.Long": + return PrimitiveTypeWrapper.LONG; + case "java.lang.Float": + return PrimitiveTypeWrapper.FLOAT; + case "java.lang.Double": + return PrimitiveTypeWrapper.DOUBLE; + default: + return null; + } + } + + 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 MethodBuilder CreateConstructorAndDispatch(TypeWrapperFactory context, TypeWrapper[] args, TypeBuilder tb, MethodWrapper interfaceMethod, TypeWrapper[] implParameters, + ClassFile.ConstantPoolItemMethodType samMethodType, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType) + { + // 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("c" + i, 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 method + MethodBuilder mb = interfaceMethod.GetDefineMethodHelper().DefineMethod(context, tb, interfaceMethod.RealName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); + ilgen = CodeEmitter.Create(mb); + for (int i = 0; i < capturedTypes.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 = samMethodType.GetArgTypes()[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(); + + return ctor; + } + + private static void EmitConvertingUnbox(CodeEmitter ilgen, TypeWrapper tw) + { + switch (tw.SigName[0]) + { + case 'Z': + case 'C': + Boxer.EmitUnbox(ilgen, tw, true); + break; + case 'B': + EmitUnboxNumber(ilgen, "byteValue", "()B"); + break; + case 'S': + EmitUnboxNumber(ilgen, "shortValue", "()S"); + break; + case 'I': + EmitUnboxNumber(ilgen, "intValue", "()I"); + break; + case 'J': + EmitUnboxNumber(ilgen, "longValue", "()J"); + break; + case 'F': + EmitUnboxNumber(ilgen, "floatValue", "()F"); + break; + case 'D': + EmitUnboxNumber(ilgen, "doubleValue", "()D"); + break; + default: + throw new InvalidOperationException(); + } + } + + private static void EmitUnboxNumber(CodeEmitter ilgen, string methodName, string methodSig) + { + TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical("java.lang.Number"); + tw.EmitCheckcast(ilgen); + MethodWrapper mw = tw.GetMethodWrapper(methodName, methodSig, false); + mw.Link(); + mw.EmitCallvirt(ilgen); + } + + private static void AddDefaultInterfaceMethods(TypeWrapperFactory context, MethodWrapper[] methodList, TypeBuilder tb) + { + foreach (MethodWrapper mw in methodList) + { + if (!mw.IsAbstract) + { + MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(context, tb, mw.RealName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); + DynamicTypeWrapper.FinishContext.EmitCallDefaultInterfaceMethod(mb, mw); + } + else if (IsObjectMethod(mw)) + { + MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(context, tb, mw.RealName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); + CodeEmitter ilgen = CodeEmitter.Create(mb); + for (int i = 0, count = mw.GetParameters().Length; i <= count; i++) + { + ilgen.EmitLdarg(i); + } + CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper(mw.Name, mw.Signature, false).EmitCallvirt(ilgen); + ilgen.Emit(OpCodes.Ret); + ilgen.DoEmit(); + } + } + } + + private static bool IsSupportedImplMethod(ClassFile.ConstantPoolItemMethodHandle implMethod, TypeWrapper caller, TypeWrapper[] captured, ClassFile.ConstantPoolItemMethodType instantiatedMethodType) + { + switch (implMethod.Kind) + { + case ClassFile.RefKind.invokeVirtual: + case ClassFile.RefKind.invokeInterface: + case ClassFile.RefKind.newInvokeSpecial: + case ClassFile.RefKind.invokeStatic: + case ClassFile.RefKind.invokeSpecial: + break; + default: + return false; + } + MethodWrapper mw = (MethodWrapper)implMethod.Member; + if (mw == null || mw.HasCallerID || DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(mw.DeclaringType.Name, mw.Name, mw.Signature)) + { + return false; + } + TypeWrapper instance; + if (mw.IsConstructor) + { + instance = mw.DeclaringType; + } + else if (mw.IsStatic) + { + instance = null; + } + else + { + // if implMethod is an instance method, the type of the first captured value must be subtype of implMethod.DeclaringType + instance = captured.Length == 0 ? instantiatedMethodType.GetArgTypes()[0] : captured[0]; + if (!instance.IsAssignableTo(mw.DeclaringType)) + { + return false; + } + } + if (!mw.IsAccessibleFrom(mw.DeclaringType, caller, instance)) + { + return false; + } + mw.Link(); + return true; + } + + private static bool IsSupportedInterface(TypeWrapper tw, out MethodWrapper[] methodList) + { + // we don't need to check for unloadable, because we already did that while validating the invoke signature + if (!tw.IsInterface || tw.IsGhost) + { + methodList = null; + return false; + } + Dictionary<MethodKey, MethodWrapper> methods = new Dictionary<MethodKey,MethodWrapper>(); + int abstractMethodCount = 0; + if (GatherAllInterfaceMethods(tw, methods, ref abstractMethodCount) && abstractMethodCount == 1) + { + methodList = new MethodWrapper[methods.Count]; + methods.Values.CopyTo(methodList, 0); + return true; + } + methodList = null; + return false; + } + + private static bool GatherAllInterfaceMethods(TypeWrapper tw, Dictionary<MethodKey, MethodWrapper> methods, ref int abstractMethodCount) + { + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (mw.IsVirtual) + { + MirandaMethodWrapper mmw = mw as MirandaMethodWrapper; + if (mmw != null) + { + if (mmw.Error != null) + { + return false; + } + continue; + } + MethodKey key = new MethodKey("", mw.Name, mw.Signature); + MethodWrapper current; + if (methods.TryGetValue(key, out current)) + { + if (!MatchSignatures(mw, current)) + { + // linkage error (or unloadable type) + return false; + } + } + else + { + methods.Add(key, mw); + if (mw.IsAbstract && !IsObjectMethod(mw)) + { + abstractMethodCount++; + } + } + mw.Link(); + if (mw.GetMethod() == null) + { + return false; + } + } + } + foreach (TypeWrapper tw1 in tw.Interfaces) + { + if (!GatherAllInterfaceMethods(tw1, methods, ref abstractMethodCount)) + { + return false; + } + } + return true; + } + + private static bool IsObjectMethod(MethodWrapper mw) + { + MethodWrapper objectMethod; + return (objectMethod = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper(mw.Name, mw.Signature, false)) != null + && objectMethod.IsPublic; + } + + private static bool MatchSignatures(MethodWrapper interfaceMethod, ClassFile.ConstantPoolItemMethodType samMethodType) + { + return interfaceMethod.ReturnType == samMethodType.GetRetType() + && MatchTypes(interfaceMethod.GetParameters(), samMethodType.GetArgTypes()); + } + + private static bool MatchSignatures(MethodWrapper mw1, MethodWrapper mw2) + { + return mw1.ReturnType == mw2.ReturnType + && MatchTypes(mw1.GetParameters(), mw2.GetParameters()); + } + + private static bool MatchTypes(TypeWrapper[] ar1, TypeWrapper[] ar2) + { + if (ar1.Length != ar2.Length) + { + return false; + } + for (int i = 0; i < ar1.Length; i++) + { + if (ar1[i] != ar2[i]) + { + return false; + } + } + return true; + } + + 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 IsLambdaMetafactory(MemberWrapper mw) + { + return mw.Name == "metafactory" + && mw.Signature == "(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;" + && mw.DeclaringType.Name == "java.lang.invoke.LambdaMetafactory"; + } + + private static bool HasUnloadable(ClassFile.ConstantPoolItemInvokeDynamic cpi) + { + return HasUnloadable(cpi.GetArgTypes()) || cpi.GetRetType().IsUnloadable; + } + + private static bool HasUnloadable(ClassFile.ConstantPoolItemMethodType cpi) + { + return HasUnloadable(cpi.GetArgTypes()) || cpi.GetRetType().IsUnloadable; + } + + private static bool HasUnloadable(ClassFile.ConstantPoolItemMI cpi) + { + return HasUnloadable(cpi.GetArgTypes()) || cpi.GetRetType().IsUnloadable; + } + + private static bool HasUnloadable(TypeWrapper[] wrappers) + { + foreach (TypeWrapper tw in wrappers) + { + if (tw.IsUnloadable) + { + return true; + } + } + return false; + } + } +} diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index 3f24f045..b82281a5 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -1977,6 +1977,7 @@ namespace IKVM.Internal internal const string IndyCallSite = "__<>IndyCS"; internal const string MethodHandleConstant = "__<>MHC"; internal const string MethodTypeConstant = "__<>MTC"; + internal const string IntrinsifiedAnonymousClass = "__<>Anon"; } internal abstract class TypeWrapper @@ -5680,4 +5681,64 @@ namespace IKVM.Internal throw new InvalidOperationException("Finish called on " + this); } } + + // this represents an intrinsified anonymous class (currently used only by LambdaMetafactory) + sealed class AnonymousTypeWrapper : TypeWrapper + { + private readonly Type type; + + internal AnonymousTypeWrapper(Type type) + : base(TypeFlags.None, Modifiers.Final | Modifiers.Synthetic, GetName(type)) + { + this.type = type; + } + + internal static bool IsAnonymous(Type type) + { + return type.IsSpecialName + && type.Name.StartsWith(NestedTypeName.IntrinsifiedAnonymousClass, StringComparison.Ordinal) + && AttributeHelper.IsJavaModule(type.Module); + } + + internal static string GetName(Type type) + { + return ClassLoaderWrapper.GetWrapperFromType(type.DeclaringType).Name + + type.Name.Replace(NestedTypeName.IntrinsifiedAnonymousClass, "$$Lambda$") + + "/" + (type.GetHashCode() & Int32.MaxValue); + } + + internal override ClassLoaderWrapper GetClassLoader() + { + return ClassLoaderWrapper.GetWrapperFromType(type.DeclaringType).GetClassLoader(); + } + + internal override Type TypeAsTBD + { + get { return type; } + } + + internal override TypeWrapper BaseTypeWrapper + { + get { return CoreClasses.java.lang.Object.Wrapper; } + } + + internal override TypeWrapper[] Interfaces + { + get { return GetImplementedInterfacesAsTypeWrappers(type); } + } + + internal override TypeWrapper[] InnerClasses + { + get { return TypeWrapper.EmptyArray; } + } + + internal override TypeWrapper DeclaringTypeWrapper + { + get { return null; } + } + + internal override void Finish() + { + } + } } diff --git a/runtime/compiler.cs b/runtime/compiler.cs index 650f166d..fc1f264a 100644 --- a/runtime/compiler.cs +++ b/runtime/compiler.cs @@ -3208,6 +3208,11 @@ sealed class Compiler private void EmitInvokeDynamic(ClassFile.ConstantPoolItemInvokeDynamic cpi) { + if (LambdaMetafactory.Emit(context, classFile, cpi, ilGenerator)) + { + // we intrinsified the lambda factory + return; + } CodeEmitter ilgen = ilGenerator; TypeWrapper[] args = cpi.GetArgTypes(); CodeEmitterLocal[] temps = new CodeEmitterLocal[args.Length]; diff --git a/runtime/runtime.build b/runtime/runtime.build index 4cb81818..808f06f1 100644 --- a/runtime/runtime.build +++ b/runtime/runtime.build @@ -158,6 +158,7 @@ <include name="intrinsics.cs" /> <include name="JavaException.cs" /> <include name="JsrInliner.cs" /> + <include name="LambdaMetafactory.cs" /> <include name="LocalVars.cs" /> <include name="MemberWrapper.cs" /> <include name="MethodHandleUtil.cs" /> |