private static void EmitClassLiteral(CompilerClassLoader ccl) { TypeBuilder tb = ccl.GetTypeWrapperFactory().ModuleBuilder.DefineType("ikvm.internal.ClassLiteral`1", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Class | TypeAttributes.BeforeFieldInit); GenericTypeParameterBuilder typeParam = tb.DefineGenericParameters("T")[0]; Type classType = CoreClasses.java.lang.Class.Wrapper.TypeAsSignatureType; classLiteralField = tb.DefineField("Value", classType, FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly); CodeEmitter ilgen = CodeEmitter.Create(ReflectUtil.DefineTypeInitializer(tb)); ilgen.Emit(OpCodes.Ldtoken, typeParam); ilgen.Emit(OpCodes.Call, Types.Type.GetMethod("GetTypeFromHandle", new Type[] { Types.RuntimeTypeHandle })); MethodWrapper mw = CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("<init>", "(Lcli.System.Type;)V", false); mw.Link(); mw.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Stsfld, classLiteralField); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); classLiteralType = tb.CreateType(); }
internal static void Create(CompilerClassLoader loader, string proxy) { string[] interfaces = proxy.Split(','); TypeWrapper[] wrappers = new TypeWrapper[interfaces.Length]; for (int i = 0; i < interfaces.Length; i++) { try { wrappers[i] = loader.LoadClassByDottedNameFast(interfaces[i]); } catch (RetargetableJavaException) { } if (wrappers[i] == null) { StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, "unable to load interface " + interfaces[i]); return; } } Create(loader, proxy, wrappers); }
internal void AddReference(CompilerClassLoader ccl) { peerReferences.Add(ccl); }
internal static void Create(CompilerClassLoader ccl) { EmitClassLiteral(ccl); }
internal AotTypeWrapper(ClassFile f, CompilerClassLoader loader) : base(f, loader, null) { }
private void AddInternalsVisibleToAttribute(CompilerClassLoader ccl) { internalsVisibleTo.Add(ccl); AssemblyBuilder asm = ccl.assemblyBuilder; AssemblyName asmName = asm.GetName(); string name = asmName.Name; byte[] pubkey = asmName.GetPublicKey(); if (pubkey == null && asmName.KeyPair != null) { pubkey = asmName.KeyPair.PublicKey; } if (pubkey != null && pubkey.Length != 0) { StringBuilder sb = new StringBuilder(name); sb.Append(", PublicKey="); foreach (byte b in pubkey) { sb.AppendFormat("{0:X2}", b); } name = sb.ToString(); } AttributeHelper.SetInternalsVisibleToAttribute(this.assemblyBuilder, name); }
private static void CreateStaticInitializer(TypeBuilder tb, List<ProxyMethod> methods, CompilerClassLoader loader) { CodeEmitter ilgen = CodeEmitter.Create(ReflectUtil.DefineTypeInitializer(tb, loader)); CodeEmitterLocal callerID = ilgen.DeclareLocal([email protected]); TypeBuilder tbCallerID = DynamicTypeWrapper.FinishContext.EmitCreateCallerID(tb, ilgen); ilgen.Emit(OpCodes.Stloc, callerID); // HACK we shouldn't create the nested type here (the outer type must be created first) tbCallerID.CreateType(); ilgen.BeginExceptionBlock(); foreach (ProxyMethod method in methods) { method.mw.DeclaringType.EmitClassLiteral(ilgen); ilgen.Emit(OpCodes.Ldstr, method.mw.Name); TypeWrapper[] parameters = method.mw.GetParameters(); ilgen.EmitLdc_I4(parameters.Length); ilgen.Emit(OpCodes.Newarr, CoreClasses.java.lang.Class.Wrapper.TypeAsArrayType); for (int i = 0; i < parameters.Length; i++) { ilgen.Emit(OpCodes.Dup); ilgen.EmitLdc_I4(i); parameters[i].EmitClassLiteral(ilgen); ilgen.Emit(OpCodes.Stelem_Ref); } if (javaLangClass_getMethod.HasCallerID) { ilgen.Emit(OpCodes.Ldloc, callerID); } javaLangClass_getMethod.EmitCallvirt(ilgen); ilgen.Emit(OpCodes.Stsfld, method.fb); } CodeEmitterLabel label = ilgen.DefineLabel(); ilgen.EmitLeave(label); ilgen.BeginCatchBlock(javaLangNoSuchMethodException.TypeAsExceptionType); javaLangThrowable_getMessage.EmitCallvirt(ilgen); javaLangNoClassDefFoundErrorConstructor.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Throw); ilgen.EndExceptionBlock(); ilgen.MarkLabel(label); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); }
private static void AddExportMapEntry(Dictionary<string, List<string>> map, CompilerClassLoader ccl, string name) { string assemblyName = ccl.assemblyBuilder.FullName; List<string> list; if (!map.TryGetValue(assemblyName, out list)) { list = new List<string>(); map.Add(assemblyName, list); } if (list != null) // if list is null, we already have a wildcard export for this assembly { list.Add(name); } }
private static void CreateNoFail(CompilerClassLoader loader, TypeWrapper[] interfaces, List<ProxyMethod> methods) { DynamicClassLoader factory = (DynamicClassLoader)loader.GetTypeWrapperFactory(); TypeBuilder tb = factory.DefineProxy(proxyClass, interfaces); AttributeHelper.SetImplementsAttribute(tb, interfaces); CreateConstructor(tb); for (int i = 0; i < methods.Count; i++) { methods[i].fb = tb.DefineField("m" + i, javaLangReflectMethod.TypeAsSignatureType, FieldAttributes.Private | FieldAttributes.Static); } foreach (ProxyMethod method in methods) { CreateMethod(loader, tb, method); } CreateStaticInitializer(tb, methods); }
private static void CreateMethod(CompilerClassLoader loader, TypeBuilder tb, ProxyMethod pm) { MethodBuilder mb = pm.mw.GetDefineMethodHelper().DefineMethod(loader.GetTypeWrapperFactory(), tb, pm.mw.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final); List<string> exceptions = new List<string>(); foreach (TypeWrapper tw in pm.exceptions) { exceptions.Add(tw.Name); } AttributeHelper.SetThrowsAttribute(mb, exceptions.ToArray()); CodeEmitter ilgen = CodeEmitter.Create(mb); ilgen.BeginExceptionBlock(); ilgen.Emit(OpCodes.Ldarg_0); invocationHandlerField.EmitGet(ilgen); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Ldsfld, pm.fb); TypeWrapper[] parameters = pm.mw.GetParameters(); if (parameters.Length == 0) { ilgen.Emit(OpCodes.Ldnull); } else { ilgen.Emit_Ldc_I4(parameters.Length); ilgen.Emit(OpCodes.Newarr, Types.Object); for (int i = 0; i < parameters.Length; i++) { ilgen.Emit(OpCodes.Dup); ilgen.Emit_Ldc_I4(i); ilgen.Emit(OpCodes.Ldarg, (short)i); if (parameters[i].IsNonPrimitiveValueType) { parameters[i].EmitBox(ilgen); } else if (parameters[i].IsPrimitive) { Boxer.EmitBox(ilgen, parameters[i]); } ilgen.Emit(OpCodes.Stelem_Ref); } } invokeMethod.EmitCallvirt(ilgen); TypeWrapper returnType = pm.mw.ReturnType; CodeEmitterLocal returnValue = null; if (returnType != PrimitiveTypeWrapper.VOID) { returnValue = ilgen.DeclareLocal(returnType.TypeAsSignatureType); if (returnType.IsNonPrimitiveValueType) { returnType.EmitUnbox(ilgen); } else if (returnType.IsPrimitive) { Boxer.EmitUnbox(ilgen, returnType); } else if (returnType != CoreClasses.java.lang.Object.Wrapper) { ilgen.EmitCastclass(returnType.TypeAsSignatureType); } ilgen.Emit(OpCodes.Stloc, returnValue); } CodeEmitterLabel returnLabel = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Leave, returnLabel); // TODO consider using a filter here (but we would need to add filter support to CodeEmitter) ilgen.BeginCatchBlock(Types.Exception); ilgen.Emit_Ldc_I4(0); ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(Types.Exception)); CodeEmitterLocal exception = ilgen.DeclareLocal(Types.Exception); ilgen.Emit(OpCodes.Stloc, exception); CodeEmitterLabel rethrow = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Ldloc, exception); errorClass.EmitInstanceOf(null, ilgen); ilgen.Emit(OpCodes.Brtrue, rethrow); ilgen.Emit(OpCodes.Ldloc, exception); runtimeExceptionClass.EmitInstanceOf(null, ilgen); ilgen.Emit(OpCodes.Brtrue, rethrow); foreach (TypeWrapper tw in pm.exceptions) { ilgen.Emit(OpCodes.Ldloc, exception); tw.EmitInstanceOf(null, ilgen); ilgen.Emit(OpCodes.Brtrue, rethrow); } ilgen.Emit(OpCodes.Ldloc, exception); undeclaredThrowableExceptionConstructor.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Throw); ilgen.MarkLabel(rethrow); ilgen.Emit(OpCodes.Rethrow); ilgen.EndExceptionBlock(); ilgen.MarkLabel(returnLabel); if (returnValue != null) { ilgen.Emit(OpCodes.Ldloc, returnValue); } ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); }
private static void Add(CompilerClassLoader loader, Dictionary<string, TypeWrapper[]> exceptions, MethodWrapper mw) { string signature = mw.Signature; TypeWrapper[] newExceptionTypes = LoadTypes(loader, mw.GetDeclaredExceptions()); TypeWrapper[] curExceptionTypes; if (exceptions.TryGetValue(signature, out curExceptionTypes)) { exceptions[signature] = Merge(newExceptionTypes, curExceptionTypes); } else { exceptions.Add(signature, newExceptionTypes); } }
private static List<ProxyMethod> CheckAndCollect(CompilerClassLoader loader, TypeWrapper[] interfaces) { List<MethodWrapper> methods = new List<MethodWrapper>(); // The java.lang.Object methods precede any interface methods. methods.Add(equalsMethod); methods.Add(hashCodeMethod); methods.Add(toStringMethod); // Add the interfaces methods in order. foreach (TypeWrapper tw in interfaces) { if (!tw.IsInterface) { throw new ProxyException(tw.Name + " is not an interface"); } if (tw.IsRemapped) { // TODO handle java.lang.Comparable throw new ProxyException(tw.Name + " is a remapped interface (not currently supported)"); } foreach (MethodWrapper mw in GetInterfaceMethods(tw)) { // Check for duplicates if (!MethodExists(methods, mw)) { methods.Add(mw); } } } // TODO verify restrictions // Collect declared exceptions. Dictionary<string, TypeWrapper[]> exceptions = new Dictionary<string, TypeWrapper[]>(); foreach (MethodWrapper mw in methods) { Add(loader, exceptions, mw); } // Build the definitive proxy method list. List<ProxyMethod> proxyMethods = new List<ProxyMethod>(); foreach (MethodWrapper mw in methods) { proxyMethods.Add(new ProxyMethod(mw, exceptions[mw.Signature])); } return proxyMethods; }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { try { if(IsCoreAssembly(reference)) { JVM.CoreAssembly = reference; } references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { if(asmref.FullName != runtimeAssemblyName.FullName) { Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible IKVM.Runtime version ({1})", reference.Location, asmref.Version); Console.Error.WriteLine(" Current runtime: {0}", runtimeAssemblyName.FullName); Console.Error.WriteLine(" Referenced assembly runtime: {0}", asmref.FullName); return 1; } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible (signed) IKVM.Runtime version", reference.Location); Console.Error.WriteLine(" Current runtime: {0}", runtimeAssemblyName.FullName); Console.Error.WriteLine(" Referenced assembly runtime: {0}", asmref.FullName); return 1; } } } } } catch(Exception x) { Console.Error.WriteLine("Error: invalid reference: {0} ({1})", reference.Location, x.Message); return 1; } } List<object> assemblyAnnotations = new List<object>(); Dictionary<string, string> baseClasses = new Dictionary<string, string>(); Tracer.Info(Tracer.Compiler, "Parsing class files"); foreach(KeyValuePair<string, byte[]> kv in options.classes) { ClassFile f; try { byte[] buf = kv.Value; f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None); if(!f.IsInterface && f.SuperClass != null) { baseClasses[f.SuperClass] = f.SuperClass; } // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if(f.Name == "assembly" && f.Annotations != null) { assemblyAnnotations.AddRange(f.Annotations); } } catch(ClassFormatError) { continue; } if(options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach(ClassFile.Method m in f.Methods) { if(m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; break; } } } } Dictionary<string, byte[]> h = new Dictionary<string, byte[]>(); // HACK remove "assembly" type that exists only as a placeholder for assembly attributes options.classes.Remove("assembly"); foreach(KeyValuePair<string, byte[]> kv in options.classes) { string name = kv.Key; bool excluded = false; for(int j = 0; j < options.classesToExclude.Length; j++) { if(Regex.IsMatch(name, options.classesToExclude[j])) { excluded = true; break; } } if(h.ContainsKey(name)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, name); excluded = true; } if(!excluded) { h[name] = kv.Value; } } options.classes = null; if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { Console.Error.WriteLine("Error: main class cannot be specified for library or module"); return 1; } if(options.target != PEFileKinds.Dll && options.mainClass == null) { Console.Error.WriteLine("Error: no main method found"); return 1; } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { Console.Error.WriteLine("Error: properties cannot be specified for library or module"); return 1; } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = options.assembly + ".netmodule"; } else { options.path = options.assembly + ".dll"; } } else { options.path = options.assembly + ".exe"; } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path); } if(options.targetIsModule) { if(options.classLoader != null) { Console.Error.WriteLine("Error: cannot specify assembly class loader for modules"); return 1; } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = new FileInfo(options.path).Name; } if(options.target == PEFileKinds.Dll && !options.path.ToLower().EndsWith(".dll") && !options.targetIsModule) { Console.Error.WriteLine("Error: library output file must end with .dll"); return 1; } if(options.target != PEFileKinds.Dll && !options.path.ToLower().EndsWith(".exe")) { Console.Error.WriteLine("Error: executable output file must end with .exe"); return 1; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { referencedAssemblies[i] = AssemblyClassLoader.FromAssembly(references[i]); } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h); loader.baseClasses = baseClasses; loader.assemblyAnnotations = assemblyAnnotations; loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); using(FileStream fs = File.Open(options.remapfile, FileMode.Open)) { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root.filename = new FileInfo(fs.Name).Name; if (!loader.ValidateAndSetMap((IKVM.Internal.MapXml.Root)ser.Deserialize(rdr))) { return 1; } } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); loader.EmitRemappedTypes(); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { Console.Error.WriteLine("Error: bootstrap classes missing and core assembly not found"); return 1; } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { Console.Error.WriteLine("Error: all referenced assemblies must be strong named, to be able to sign the output assembly"); return 1; } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { // TODO we really should support binding redirects here to allow different revisions to be mixed if(asmref.FullName != runtimeAssemblyName.FullName) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } } } } List<object> assemblyAnnotations = new List<object>(); Dictionary<string, string> baseClasses = new Dictionary<string, string>(); Tracer.Info(Tracer.Compiler, "Parsing class files"); foreach(KeyValuePair<string, ClassItem> kv in options.classes) { ClassFile f; try { byte[] buf = kv.Value.data; f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None); if(!f.IsInterface && f.SuperClass != null) { baseClasses[f.SuperClass] = f.SuperClass; } // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if(f.Name == "assembly" && f.Annotations != null) { assemblyAnnotations.AddRange(f.Annotations); } } catch(ClassFormatError) { continue; } if(options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach(ClassFile.Method m in f.Methods) { if(m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; break; } } } } Dictionary<string, ClassItem> h = new Dictionary<string, ClassItem>(); // HACK remove "assembly" type that exists only as a placeholder for assembly attributes options.classes.Remove("assembly"); foreach(KeyValuePair<string, ClassItem> kv in options.classes) { string name = kv.Key; bool excluded = false; for(int j = 0; j < options.classesToExclude.Length; j++) { if(Regex.IsMatch(name, options.classesToExclude[j])) { excluded = true; break; } } if(h.ContainsKey(name)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, name); excluded = true; } if(!excluded) { h[name] = kv.Value; } } options.classes = null; if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { throw new FatalCompilerErrorException(Message.MainClassRequiresExe); } if(options.target != PEFileKinds.Dll && options.mainClass == null) { throw new FatalCompilerErrorException(Message.ExeRequiresMainClass); } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { throw new FatalCompilerErrorException(Message.PropertiesRequireExe); } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = options.assembly + ".netmodule"; } else { options.path = options.assembly + ".dll"; } } else { options.path = options.assembly + ".exe"; } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path); } if(options.targetIsModule) { if(options.classLoader != null) { throw new FatalCompilerErrorException(Message.ModuleCannotHaveClassLoader); } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = new FileInfo(options.path).Name; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { AssemblyClassLoader acl = AssemblyClassLoader.FromAssembly(references[i]); if (acl.MainAssembly != references[i]) { StaticCompiler.IssueMessage(options, Message.NonPrimaryAssemblyReference, references[i].GetName().Name, acl.MainAssembly.GetName().Name); } if (Array.IndexOf(referencedAssemblies, acl) != -1) { StaticCompiler.IssueMessage(options, Message.DuplicateAssemblyReference, acl.MainAssembly.FullName); } referencedAssemblies[i] = acl; } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h); loader.baseClasses = baseClasses; loader.assemblyAnnotations = assemblyAnnotations; loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); FileStream fs; try { fs = File.OpenRead(options.remapfile); } catch(Exception x) { throw new FatalCompilerErrorException(Message.ErrorReadingFile, options.remapfile, x.Message); } try { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root map; try { map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr); } catch(InvalidOperationException x) { throw new FatalCompilerErrorException(Message.ErrorParsingMapFile, options.remapfile, x.Message); } if(!loader.ValidateAndSetMap(map)) { return 1; } } finally { fs.Close(); } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { throw new FatalCompilerErrorException(Message.BootstrapClassesMissing); } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { throw new FatalCompilerErrorException(Message.StrongNameRequiresStrongNamedRefs); } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }
private static void Create(CompilerClassLoader loader, string proxy, TypeWrapper[] interfaces) { List<ProxyMethod> methods; try { methods = CheckAndCollect(loader, interfaces); } catch (RetargetableJavaException x) { StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, x.Message); return; } catch (ProxyException x) { StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, x.Message); return; } CreateNoFail(loader, interfaces, methods); }
private void AddInternalsVisibleToAttribute(CompilerClassLoader ccl) { internalsVisibleTo.Add(ccl); AssemblyBuilder asm = ccl.assemblyBuilder; AssemblyName asmName = asm.GetName(); string name = asmName.Name; byte[] pubkey = asmName.GetPublicKey(); if (pubkey == null && asmName.KeyPair != null) { pubkey = asmName.KeyPair.PublicKey; } if (pubkey != null && pubkey.Length != 0) { StringBuilder sb = new StringBuilder(name); sb.Append(", PublicKey="); foreach (byte b in pubkey) { sb.AppendFormat("{0:X2}", b); } name = sb.ToString(); } CustomAttributeBuilder cab = new CustomAttributeBuilder(JVM.Import(typeof(InternalsVisibleToAttribute)).GetConstructor(new Type[] { Types.String }), new object[] { name }); this.assemblyBuilder.SetCustomAttribute(cab); }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { // TODO we really should support binding redirects here to allow different revisions to be mixed if(asmref.FullName != runtimeAssemblyName.FullName) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } } } } Tracer.Info(Tracer.Compiler, "Parsing class files"); // map the class names to jar entries Dictionary<string, Jar.Item> h = new Dictionary<string, Jar.Item>(); List<string> classNames = new List<string>(); foreach (Jar jar in options.jars) { if (options.IsResourcesJar(jar)) { continue; } foreach (Jar.Item item in jar) { string name = item.Name; if (name.EndsWith(".class", StringComparison.Ordinal) && name.Length > 6 && name.IndexOf('.') == name.Length - 6) { string className = name.Substring(0, name.Length - 6).Replace('/', '.'); if (h.ContainsKey(className)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, className); Jar.Item itemRef = h[className]; if ((options.classesJar != -1 && itemRef.Jar == options.jars[options.classesJar]) || jar != itemRef.Jar) { // the previous class stays, because it was either in an earlier jar or we're processing the classes.jar // which contains the classes loaded from the file system (where the first encountered class wins) continue; } else { // we have a jar that contains multiple entries with the same name, the last one wins h.Remove(className); classNames.Remove(className); } } h.Add(className, item); classNames.Add(className); } } } if (options.assemblyAttributeAnnotations == null) { // look for "assembly" type that acts as a placeholder for assembly attributes Jar.Item assemblyType; if (h.TryGetValue("assembly", out assemblyType)) { try { byte[] buf = assemblyType.GetData(); ClassFile f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if (f.Name == "assembly" && f.Annotations != null) { options.assemblyAttributeAnnotations = f.Annotations; // HACK remove "assembly" type that exists only as a placeholder for assembly attributes h.Remove(f.Name); assemblyType.Remove(); StaticCompiler.IssueMessage(Message.LegacyAssemblyAttributesFound); } } catch (ClassFormatError) { } } } // now look for a main method if (options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach (string className in classNames) { try { byte[] buf = h[className].GetData(); ClassFile f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); if (f.Name == className) { foreach (ClassFile.Method m in f.Methods) { if (m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; goto break_outer; } } } } catch (ClassFormatError) { } } break_outer: ; } if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { throw new FatalCompilerErrorException(Message.MainClassRequiresExe); } if(options.target != PEFileKinds.Dll && options.mainClass == null) { throw new FatalCompilerErrorException(Message.ExeRequiresMainClass); } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { throw new FatalCompilerErrorException(Message.PropertiesRequireExe); } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".netmodule"); } else { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".dll"); } } else { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".exe"); } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path.ToString()); } if(options.targetIsModule) { if(options.classLoader != null) { throw new FatalCompilerErrorException(Message.ModuleCannotHaveClassLoader); } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = options.path.Name; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { AssemblyClassLoader acl = AssemblyClassLoader.FromAssembly(references[i]); if (Array.IndexOf(referencedAssemblies, acl) != -1) { StaticCompiler.IssueMessage(options, Message.DuplicateAssemblyReference, acl.MainAssembly.FullName); } referencedAssemblies[i] = acl; } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h, compilingCoreAssembly); loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); FileStream fs; try { fs = options.remapfile.OpenRead(); } catch(Exception x) { throw new FatalCompilerErrorException(Message.ErrorReadingFile, options.remapfile, x.Message); } try { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root map; try { map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr); } catch(InvalidOperationException x) { throw new FatalCompilerErrorException(Message.ErrorParsingMapFile, options.remapfile, x.Message); } if(!loader.ValidateAndSetMap(map)) { return 1; } } finally { fs.Close(); } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { AssemblyClassLoader.PreloadExportedAssemblies(asm); JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { throw new FatalCompilerErrorException(Message.BootstrapClassesMissing); } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { throw new FatalCompilerErrorException(Message.StrongNameRequiresStrongNamedRefs); } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }
internal RemapperTypeWrapper(CompilerClassLoader classLoader, IKVM.Internal.MapXml.Class c, IKVM.Internal.MapXml.Root map) : base((Modifiers)c.Modifiers, c.Name) { this.classLoader = classLoader; this.baseTypeWrapper = GetBaseWrapper(c); classDef = c; bool baseIsSealed = false; shadowType = StaticCompiler.Universe.GetType(c.Shadows, true); classLoader.SetRemappedType(shadowType, this); Type baseType = shadowType; Type baseInterface = null; if(baseType.IsInterface) { baseInterface = baseType; } TypeAttributes attrs = TypeAttributes.Public; if((c.Modifiers & IKVM.Internal.MapXml.MapModifiers.Interface) == 0) { attrs |= TypeAttributes.Class; if(baseType.IsSealed) { baseIsSealed = true; attrs |= TypeAttributes.Abstract | TypeAttributes.Sealed; } } else { attrs |= TypeAttributes.Interface | TypeAttributes.Abstract; baseType = null; } if((c.Modifiers & IKVM.Internal.MapXml.MapModifiers.Abstract) != 0) { attrs |= TypeAttributes.Abstract; } string name = c.Name.Replace('/', '.'); typeBuilder = classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(name, attrs, baseIsSealed ? Types.Object : baseType); if(c.Attributes != null) { foreach(IKVM.Internal.MapXml.Attribute custattr in c.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, typeBuilder, custattr); } } if(baseInterface != null) { typeBuilder.AddInterfaceImplementation(baseInterface); } if(classLoader.EmitStackTraceInfo) { AttributeHelper.SetSourceFile(typeBuilder, Path.GetFileName(classLoader.options.remapfile)); } if(baseIsSealed) { AttributeHelper.SetModifiers(typeBuilder, (Modifiers)c.Modifiers, false); } if(c.scope == IKVM.Internal.MapXml.Scope.Public) { // FXBUG we would like to emit an attribute with a Type argument here, but that doesn't work because // of a bug in SetCustomAttribute that causes type arguments to be serialized incorrectly (if the type // is in the same assembly). Normally we use AttributeHelper.FreezeDry to get around this, but that doesn't // work in this case (no attribute is emitted at all). So we work around by emitting a string instead AttributeHelper.SetRemappedClass(classLoader.assemblyBuilder, name, shadowType); AttributeHelper.SetRemappedType(typeBuilder, shadowType); } List<MethodWrapper> methods = new List<MethodWrapper>(); if(c.Constructors != null) { foreach(IKVM.Internal.MapXml.Constructor m in c.Constructors) { methods.Add(new RemappedConstructorWrapper(this, m)); } } if(c.Methods != null) { foreach(IKVM.Internal.MapXml.Method m in c.Methods) { methods.Add(new RemappedMethodWrapper(this, m, map, false)); } } // add methods from our super classes (e.g. Throwable should have Object's methods) if(!this.IsFinal && !this.IsInterface && this.BaseTypeWrapper != null) { foreach(MethodWrapper mw in BaseTypeWrapper.GetMethods()) { RemappedMethodWrapper rmw = mw as RemappedMethodWrapper; if(rmw != null && (rmw.IsPublic || rmw.IsProtected)) { if(!FindMethod(methods, rmw.Name, rmw.Signature)) { methods.Add(new RemappedMethodWrapper(this, rmw.XmlMethod, map, true)); } } } } SetMethods(methods.ToArray()); }
private static void CreateNoFail(CompilerClassLoader loader, TypeWrapper[] interfaces, List<ProxyMethod> methods) { bool ispublic = true; Type[] interfaceTypes = new Type[interfaces.Length]; for (int i = 0; i < interfaceTypes.Length; i++) { ispublic &= interfaces[i].IsPublic; interfaceTypes[i] = interfaces[i].TypeAsBaseType; } TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Sealed; attr |= ispublic ? TypeAttributes.NestedPublic : TypeAttributes.NestedAssembly; DynamicClassLoader factory = (DynamicClassLoader)loader.GetTypeWrapperFactory(); TypeBuilder tb = factory.DefineProxy(TypeNameUtil.GetProxyNestedName(interfaces), attr, proxyClass.TypeAsBaseType, interfaceTypes); AttributeHelper.SetImplementsAttribute(tb, interfaces); // we apply an InnerClass attribute to avoid the CompiledTypeWrapper heuristics for figuring out the modifiers AttributeHelper.SetInnerClass(tb, null, ispublic ? Modifiers.Public | Modifiers.Final : Modifiers.Final); CreateConstructor(tb); for (int i = 0; i < methods.Count; i++) { methods[i].fb = tb.DefineField("m" + i, javaLangReflectMethod.TypeAsSignatureType, FieldAttributes.Private | FieldAttributes.Static); } foreach (ProxyMethod method in methods) { CreateMethod(loader, tb, method); } CreateStaticInitializer(tb, methods, loader); }