diff --git a/classpath/ikvm/lang/DllExport.java b/classpath/ikvm/lang/DllExport.java new file mode 100644 index 00000000..5106ae9c --- /dev/null +++ b/classpath/ikvm/lang/DllExport.java @@ -0,0 +1,40 @@ +/* + Copyright (C) 2011 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 + +*/ +package ikvm.lang; + +import java.lang.annotation.*; + +/** + * Can be used to define an unmanaged export for a static method. + * Only works with ikvmc compiled code. + */ + +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ ElementType.METHOD }) +public @interface DllExport +{ + String name(); + int ordinal(); +} diff --git a/ikvmc/CompilerClassLoader.cs b/ikvmc/CompilerClassLoader.cs index ff3431d6..65c16638 100644 --- a/ikvmc/CompilerClassLoader.cs +++ b/ikvmc/CompilerClassLoader.cs @@ -3276,6 +3276,11 @@ namespace IKVM.Internal { StaticCompiler.IssueMessage(options, msgId, values); } + + internal void ClearILOnlyFlag() + { + options.pekind &= ~PortableExecutableKinds.ILOnly; + } } struct ResourceItem @@ -3403,6 +3408,7 @@ namespace IKVM.Internal LegacySearchRule = 126, AssemblyLocationIgnored = 127, InterfaceMethodCantBeInternal = 128, + DllExportMustBeStaticMethod = 129, UnknownWarning = 999, // This is where the errors start StartErrors = 4000, @@ -3621,6 +3627,10 @@ namespace IKVM.Internal msg = "ignoring @ikvm.lang.Internal annotation on interface method" + Environment.NewLine + " (\"{0}.{1}{2}\")"; break; + case Message.DllExportMustBeStaticMethod: + msg = "ignoring @ikvm.lang.DllExport annotation on non-static method" + Environment.NewLine + + " (\"{0}.{1}{2}\")"; + break; case Message.UnableToCreateProxy: msg = "unable to create proxy \"{0}\"" + Environment.NewLine + " (\"{1}\")"; diff --git a/openjdk/allsources.lst b/openjdk/allsources.lst index 3c038c1f..985bbfa5 100644 --- a/openjdk/allsources.lst +++ b/openjdk/allsources.lst @@ -12,6 +12,7 @@ ../classpath/ikvm/internal/WeakIdentityMap.java ../classpath/ikvm/io/InputStreamWrapper.java ../classpath/ikvm/lang/CIL.java +../classpath/ikvm/lang/DllExport.java ../classpath/ikvm/lang/Internal.java ../classpath/ikvm/lang/IterableEnumerator.java ../classpath/ikvm/lang/MapEnumerator.java diff --git a/runtime/ClassFile.cs b/runtime/ClassFile.cs index 0555eaa8..2e858585 100644 --- a/runtime/ClassFile.cs +++ b/runtime/ClassFile.cs @@ -2448,8 +2448,15 @@ namespace IKVM.Internal { private Code code; private string[] exceptions; - private object annotationDefault; - private object[][] parameterAnnotations; + private LowFreqData low; + + sealed class LowFreqData + { + internal object annotationDefault; + internal object[][] parameterAnnotations; + internal string DllExportName; + internal int DllExportOrdinal; + } internal Method(ClassFile classFile, ClassFileParseOptions options, BigEndianBinaryReader br) : base(classFile, br) { @@ -2541,16 +2548,20 @@ namespace IKVM.Internal { goto default; } + if(low == null) + { + low = new LowFreqData(); + } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); byte num_parameters = rdr.ReadByte(); - parameterAnnotations = new object[num_parameters][]; + low.parameterAnnotations = new object[num_parameters][]; for(int j = 0; j < num_parameters; j++) { ushort num_annotations = rdr.ReadUInt16(); - parameterAnnotations[j] = new object[num_annotations]; + low.parameterAnnotations[j] = new object[num_annotations]; for(int k = 0; k < num_annotations; k++) { - parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile); + low.parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile); } } if(!rdr.IsAtEnd) @@ -2565,8 +2576,12 @@ namespace IKVM.Internal { goto default; } + if(low == null) + { + low = new LowFreqData(); + } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - annotationDefault = ReadAnnotationElementValue(rdr, classFile); + low.annotationDefault = ReadAnnotationElementValue(rdr, classFile); if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name); @@ -2597,6 +2612,38 @@ namespace IKVM.Internal { flags |= FLAG_HAS_CALLERID; } + if(annot[1].Equals("Likvm/lang/DllExport;")) + { + string name = null; + int? ordinal = null; + for (int j = 2; j < annot.Length; j += 2) + { + if (annot[j].Equals("name") && annot[j + 1] is string) + { + name = (string)annot[j + 1]; + } + else if (annot[j].Equals("ordinal") && annot[j + 1] is int) + { + ordinal = (int)annot[j + 1]; + } + } + if (name != null && ordinal != null) + { + if (!IsStatic) + { + StaticCompiler.IssueMessage(Message.DllExportMustBeStaticMethod, classFile.Name, this.Name, this.Signature); + } + else + { + if (low == null) + { + low = new LowFreqData(); + } + low.DllExportName = name; + low.DllExportOrdinal = ordinal.Value; + } + } + } } break; #endif @@ -2672,7 +2719,7 @@ namespace IKVM.Internal { get { - return parameterAnnotations; + return low == null ? null : low.parameterAnnotations; } } @@ -2680,7 +2727,23 @@ namespace IKVM.Internal { get { - return annotationDefault; + return low == null ? null : low.annotationDefault; + } + } + + internal string DllExportName + { + get + { + return low == null ? null : low.DllExportName; + } + } + + internal int DllExportOrdinal + { + get + { + return low == null ? -1 : low.DllExportOrdinal; } } diff --git a/runtime/DynamicTypeWrapper.cs b/runtime/DynamicTypeWrapper.cs index 19ccc440..59f825a4 100644 --- a/runtime/DynamicTypeWrapper.cs +++ b/runtime/DynamicTypeWrapper.cs @@ -4342,6 +4342,12 @@ namespace IKVM.Internal AttributeHelper.SetEditorBrowsableNever((MethodBuilder)mb); EmitCallerIDStub(methods[i], parameterNames); } + if (m.DllExportName != null) + { + mBuilder.__AddUnmanagedExport(m.DllExportName, m.DllExportOrdinal); + // when you add unmanaged exports, the ILOnly flag MUST NOT be set or the DLL will fail to load + ((CompilerClassLoader)wrapper.GetClassLoader()).ClearILOnlyFlag(); + } #endif // STATIC_COMPILER }