private bool ValidateAndSetMap(IKVM.Internal.MapXml.Root map)
		{
			bool valid = true;
			if (map.assembly != null)
			{
				if (map.assembly.Classes != null)
				{
					foreach (IKVM.Internal.MapXml.Class c in map.assembly.Classes)
					{
						if (c.Fields != null)
						{
							foreach (IKVM.Internal.MapXml.Field f in c.Fields)
							{
								ValidateNameSig("field", c.Name, f.Name, f.Sig, ref valid, true);
							}
						}
						if (c.Methods != null)
						{
							foreach (IKVM.Internal.MapXml.Method m in c.Methods)
							{
								ValidateNameSig("method", c.Name, m.Name, m.Sig, ref valid, false);
							}
						}
						if (c.Constructors != null)
						{
							foreach (IKVM.Internal.MapXml.Constructor ctor in c.Constructors)
							{
								ValidateNameSig("constructor", c.Name, "<init>", ctor.Sig, ref valid, false);
							}
						}
						if (c.Properties != null)
						{
							foreach (IKVM.Internal.MapXml.Property prop in c.Properties)
							{
								ValidateNameSig("property", c.Name, prop.Name, prop.Sig, ref valid, false);
								ValidatePropertyGetterSetter("getter", c.Name, prop.Name, prop.getter, ref valid);
								ValidatePropertyGetterSetter("setter", c.Name, prop.Name, prop.setter, ref valid);
							}
						}
					}
				}
			}
			this.map = map;
			return valid;
		}
				internal RemappedMethodWrapper(RemapperTypeWrapper typeWrapper, IKVM.Internal.MapXml.Method m, IKVM.Internal.MapXml.Root map, bool inherited)
					: base(typeWrapper, m.Name, m.Sig, (Modifiers)m.Modifiers)
				{
					this.m = m;
					this.map = map;
					this.inherited = inherited;
				}
		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;
		}
Example #4
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);
							}
						}
					}
				}
			}
			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;
		}