Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2014-07-01 19:12:34 +0400
committerjfrijters <jfrijters>2014-07-01 19:12:34 +0400
commitbaa72377e131fa1d3a5bce2529e860f0ba40b0f9 (patch)
tree2d5a278d857c1c48e274e97f98840216441ba755
parent3bfe04144498cb03e1ea1ccecf553dc85bbe70b7 (diff)
Added intrinsic for LambdaMetafactory.metafactory().
-rw-r--r--ikvmc.8.csproj1
-rw-r--r--ikvmc/CompilerClassLoader.cs4
-rw-r--r--ikvmc/ikvmc.build1
-rw-r--r--openjdk/response.txt46
-rw-r--r--runtime/ClassLoaderWrapper.cs18
-rw-r--r--runtime/DynamicTypeWrapper.cs59
-rw-r--r--runtime/IKVM.Runtime.8.csproj1
-rw-r--r--runtime/LambdaMetafactory.cs771
-rw-r--r--runtime/TypeWrapper.cs61
-rw-r--r--runtime/compiler.cs5
-rw-r--r--runtime/runtime.build1
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" />