private JsrInliner(ClassFile.Method.Instruction[] codeCopy, InstructionFlags[] flags, ClassFile.Method m, JsrMethodAnalyzer ma) { this.codeCopy = codeCopy; codeLength = codeCopy.Length; this.flags = flags; this.m = m; this.ma = ma; }
private void Add(ClassFile.Method.Instruction instr) { if (codeLength == codeCopy.Length) { Array.Resize(ref codeCopy, codeLength * 2); Array.Resize(ref flags, codeLength * 2); } codeCopy[codeLength++] = instr; }
internal static void InlineJsrs(ClassLoaderWrapper classLoader, MethodWrapper mw, ClassFile classFile, ClassFile.Method m) { JsrInliner inliner; do { ClassFile.Method.Instruction[] codeCopy = (ClassFile.Method.Instruction[])m.Instructions.Clone(); InstructionFlags[] flags = new InstructionFlags[codeCopy.Length]; JsrMethodAnalyzer ma = new JsrMethodAnalyzer(mw, classFile, m, classLoader, flags); inliner = new JsrInliner(codeCopy, flags, m, ma); } while (inliner.InlineJsrs()); }
internal static bool Emit(DynamicTypeWrapper.FinishContext context, ClassFile classFile, int constantPoolIndex, ClassFile.ConstantPoolItemInvokeDynamic cpi, CodeEmitter ilgen) { ClassFile.BootstrapMethod bsm = classFile.GetBootstrapMethod(cpi.BootstrapMethod); if (!IsLambdaMetafactory(classFile, bsm) && !IsLambdaAltMetafactory(classFile, bsm)) { return false; } LambdaMetafactory lmf = context.GetValue<LambdaMetafactory>(constantPoolIndex); if (lmf.ctor == null && !lmf.EmitImpl(context, classFile, cpi, bsm, ilgen)) { #if STATIC_COMPILER if (context.TypeWrapper.GetClassLoader().DisableDynamicBinding) { StaticCompiler.IssueMessage(Message.UnableToCreateLambdaFactory); } #endif return false; } ilgen.Emit(OpCodes.Newobj, lmf.ctor); // the CLR verification rules about type merging mean we have to explicitly cast to the interface type here ilgen.Emit(OpCodes.Castclass, cpi.GetRetType().TypeAsBaseType); return true; }
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 object ReadAnnotationElementValue(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) { try { byte tag = rdr.ReadByte(); switch (tag) { case (byte)'Z': return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()) != 0; case (byte)'B': return (byte)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); case (byte)'C': return (char)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); case (byte)'S': return (short)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); case (byte)'I': return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); case (byte)'F': return classFile.GetConstantPoolConstantFloat(rdr.ReadUInt16()); case (byte)'J': return classFile.GetConstantPoolConstantLong(rdr.ReadUInt16()); case (byte)'D': return classFile.GetConstantPoolConstantDouble(rdr.ReadUInt16()); case (byte)'s': return classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); case (byte)'e': { ushort type_name_index = rdr.ReadUInt16(); ushort const_name_index = rdr.ReadUInt16(); return new object[] { AnnotationDefaultAttribute.TAG_ENUM, classFile.GetConstantPoolUtf8String(utf8_cp, type_name_index), classFile.GetConstantPoolUtf8String(utf8_cp, const_name_index) }; } case (byte)'c': return new object[] { AnnotationDefaultAttribute.TAG_CLASS, classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()) }; case (byte)'@': return ReadAnnotation(rdr, classFile, utf8_cp); case (byte)'[': { ushort num_values = rdr.ReadUInt16(); object[] array = new object[num_values + 1]; array[0] = AnnotationDefaultAttribute.TAG_ARRAY; for (int i = 0; i < num_values; i++) { array[i + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); } return array; } default: throw new ClassFormatError("Invalid tag {0} in annotation element_value", tag); } } catch (NullReferenceException) { } catch (InvalidCastException) { } catch (IndexOutOfRangeException) { } return new object[] { AnnotationDefaultAttribute.TAG_ERROR, "java.lang.IllegalArgumentException", "Wrong type at constant pool index" }; }
private static object[] ReadAnnotations(BigEndianBinaryReader br, ClassFile classFile, string[] utf8_cp) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); ushort num_annotations = rdr.ReadUInt16(); object[] annotations = new object[num_annotations]; for(int i = 0; i < annotations.Length; i++) { annotations[i] = ReadAnnotation(rdr, classFile, utf8_cp); } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (RuntimeVisibleAnnotations attribute has wrong length)", classFile.Name); } return annotations; }
protected override bool IsPInvokeMethod(ClassFile.Method m) { Dictionary<string, IKVM.Internal.MapXml.Class> mapxml = classLoader.GetMapXmlClasses(); if(mapxml != null) { IKVM.Internal.MapXml.Class clazz; if(mapxml.TryGetValue(this.Name, out clazz) && clazz.Methods != null) { foreach(IKVM.Internal.MapXml.Method method in clazz.Methods) { if(method.Name == m.Name && method.Sig == m.Signature) { if(method.Attributes != null) { foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes) { if(StaticCompiler.GetType(classLoader, attr.Type) == JVM.Import(typeof(System.Runtime.InteropServices.DllImportAttribute))) { return true; } } } break; } } } } return base.IsPInvokeMethod(m); }
protected override bool EmitMapXmlMethodPrologueAndOrBody(CodeEmitter ilgen, ClassFile f, ClassFile.Method m) { IKVM.Internal.MapXml.InstructionList prologue = classLoader.GetMethodPrologue(new MethodKey(f.Name, m.Name, m.Signature)); if(prologue != null) { prologue.Emit(classLoader, ilgen); } Dictionary<MethodKey, IKVM.Internal.MapXml.InstructionList> mapxml = classLoader.GetMapXmlMethodBodies(); if(mapxml != null) { IKVM.Internal.MapXml.InstructionList opcodes; if(mapxml.TryGetValue(new MethodKey(f.Name, m.Name, m.Signature), out opcodes)) { opcodes.Emit(classLoader, ilgen); return true; } } return false; }
internal ReplacedMethodWrapper(ClassFile.ConstantPoolItemMI cpi, IKVM.Internal.MapXml.InstructionList code) : base(cpi.GetClassType(), cpi.Name, cpi.Signature, null, cpi.GetRetType(), cpi.GetArgTypes(), Modifiers.Public, MemberFlags.None) { this.code = code; }
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 bool EmitImpl(DynamicTypeWrapper.FinishContext context, ClassFile classFile, ClassFile.ConstantPoolItemInvokeDynamic cpi, ClassFile.BootstrapMethod bsm, CodeEmitter ilgen) { if (HasUnloadable(cpi)) { Fail("cpi has unloadable"); return false; } bool serializable = false; TypeWrapper[] markers = TypeWrapper.EmptyArray; ClassFile.ConstantPoolItemMethodType[] bridges = null; if (bsm.ArgumentCount > 3) { AltFlags flags = (AltFlags)classFile.GetConstantPoolConstantInteger(bsm.GetArgument(3)); serializable = (flags & AltFlags.Serializable) != 0; int argpos = 4; if ((flags & AltFlags.Markers) != 0) { markers = new TypeWrapper[classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++))]; for (int i = 0; i < markers.Length; i++) { if ((markers[i] = classFile.GetConstantPoolClassType(bsm.GetArgument(argpos++))).IsUnloadable) { Fail("unloadable marker"); return false; } } } if ((flags & AltFlags.Bridges) != 0) { bridges = new ClassFile.ConstantPoolItemMethodType[classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++))]; for (int i = 0; i < bridges.Length; i++) { bridges[i] = classFile.GetConstantPoolConstantMethodType(bsm.GetArgument(argpos++)); if (HasUnloadable(bridges[i])) { Fail("unloadable bridge"); 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 (!CheckSupportedInterfaces(context.TypeWrapper, interfaceType, markers, bridges, out methodList)) { Fail("unsupported interface"); return false; } if (serializable && Array.Exists(methodList, delegate(MethodWrapper mw) { return mw.Name == "writeReplace" && mw.Signature == "()Ljava.lang.Object;"; })) { Fail("writeReplace"); return false; } if (!IsSupportedImplMethod(implMethod, context.TypeWrapper, cpi.GetArgTypes(), instantiatedMethodType)) { Fail("implMethod " + implMethod.MemberConstantPoolItem.Class + "::" + implMethod.MemberConstantPoolItem.Name + implMethod.MemberConstantPoolItem.Signature); return false; } TypeWrapper[] implParameters = GetImplParameters(implMethod); CheckConstraints(instantiatedMethodType, samMethodType, cpi.GetArgTypes(), implParameters); if (bridges != null) { foreach (ClassFile.ConstantPoolItemMethodType bridge in bridges) { if (bridge.Signature == samMethodType.Signature) { Fail("bridge signature matches sam"); return false; } if (!CheckConstraints(instantiatedMethodType, bridge, cpi.GetArgTypes(), implParameters)) { Fail("bridge constraints"); 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"); return false; } } MethodWrapper interfaceMethod = null; List<MethodWrapper> methods = new List<MethodWrapper>(); foreach (MethodWrapper mw in methodList) { if (mw.Name == cpi.Name && mw.Signature == samMethodType.Signature) { interfaceMethod = mw; methods.Add(mw); } else if (mw.IsAbstract && !IsObjectMethod(mw)) { methods.Add(mw); } } 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); if (serializable && Array.IndexOf(markers, CoreClasses.java.io.Serializable.Wrapper) == -1) { tb.AddInterfaceImplementation(CoreClasses.java.io.Serializable.Wrapper.TypeAsBaseType); } foreach (TypeWrapper marker in markers) { tb.AddInterfaceImplementation(marker.TypeAsBaseType); } ctor = CreateConstructorAndDispatch(context, cpi, tb, methods, implParameters, samMethodType, implMethod, instantiatedMethodType, serializable); AddDefaultInterfaceMethods(context, methodList, tb); return true; }
private static void EmitDispatch(DynamicTypeWrapper.FinishContext context, TypeWrapper[] args, TypeBuilder tb, MethodWrapper interfaceMethod, TypeWrapper[] implParameters, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, FieldBuilder[] capturedFields) { MethodBuilder mb = interfaceMethod.GetDefineMethodHelper().DefineMethod(context.TypeWrapper, tb, interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); if (interfaceMethod.Name != interfaceMethod.RealName) { tb.DefineMethodOverride(mb, (MethodInfo)interfaceMethod.GetMethod()); } CodeEmitter ilgen = CodeEmitter.Create(mb); for (int i = 0; i < capturedFields.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 = interfaceMethod.GetParameters()[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(); }
private static MethodBuilder CreateConstructorAndDispatch(DynamicTypeWrapper.FinishContext context, ClassFile.ConstantPoolItemInvokeDynamic cpi, TypeBuilder tb, List<MethodWrapper> methods, TypeWrapper[] implParameters, ClassFile.ConstantPoolItemMethodType samMethodType, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, bool serializable) { TypeWrapper[] args = cpi.GetArgTypes(); // 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("arg$" + (i + 1), 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 methods foreach (MethodWrapper mw in methods) { EmitDispatch(context, args, tb, mw, implParameters, implMethod, instantiatedMethodType, capturedFields); } // writeReplace method if (serializable) { MethodBuilder writeReplace = tb.DefineMethod("writeReplace", MethodAttributes.Private, Types.Object, Type.EmptyTypes); ilgen = CodeEmitter.Create(writeReplace); context.TypeWrapper.EmitClassLiteral(ilgen); ilgen.Emit(OpCodes.Ldstr, cpi.GetRetType().Name.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, cpi.Name); ilgen.Emit(OpCodes.Ldstr, samMethodType.Signature.Replace('.', '/')); ilgen.EmitLdc_I4((int)implMethod.Kind); ilgen.Emit(OpCodes.Ldstr, implMethod.Class.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, implMethod.Name); ilgen.Emit(OpCodes.Ldstr, implMethod.Signature.Replace('.', '/')); ilgen.Emit(OpCodes.Ldstr, instantiatedMethodType.Signature.Replace('.', '/')); ilgen.EmitLdc_I4(capturedFields.Length); ilgen.Emit(OpCodes.Newarr, Types.Object); for (int i = 0; i < capturedFields.Length; i++) { ilgen.Emit(OpCodes.Dup); ilgen.EmitLdc_I4(i); ilgen.EmitLdarg(0); ilgen.Emit(OpCodes.Ldfld, capturedFields[i]); if (args[i].IsPrimitive) { Boxer.EmitBox(ilgen, args[i]); } else if (args[i].IsGhost) { args[i].EmitConvSignatureTypeToStackType(ilgen); } ilgen.Emit(OpCodes.Stelem, Types.Object); } MethodWrapper ctorSerializedLambda = ClassLoaderWrapper.LoadClassCritical("java.lang.invoke.SerializedLambda").GetMethodWrapper(StringConstants.INIT, "(Ljava.lang.Class;Ljava.lang.String;Ljava.lang.String;Ljava.lang.String;ILjava.lang.String;Ljava.lang.String;Ljava.lang.String;Ljava.lang.String;[Ljava.lang.Object;)V", false); ctorSerializedLambda.Link(); ctorSerializedLambda.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); if (!context.TypeWrapper.GetClassLoader().NoAutomagicSerialization) { // add .NET serialization interop support Serialization.MarkSerializable(tb); Serialization.AddGetObjectData(tb); } } return ctor; }
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 TypeWrapper GetTypeWrapperCompilerHook(string name) { RemapperTypeWrapper rtw; if(remapped.TryGetValue(name, out rtw)) { return rtw; } else { Jar.Item itemRef; if(classes.TryGetValue(name, out itemRef)) { classes.Remove(name); ClassFile f; try { byte[] buf = itemRef.GetData(); f = new ClassFile(buf, 0, buf.Length, name, ClassFileParseOptions, null); } catch(ClassFormatError x) { StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); return null; } if(f.Name != name) { StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); StaticCompiler.IssueMessage(options, Message.WrongClassName, name, f.Name); return null; } if(options.removeUnusedFields) { f.RemoveUnusedFields(); } if(f.IsPublic && options.privatePackages != null) { foreach(string p in options.privatePackages) { if(f.Name.StartsWith(p)) { f.SetInternal(); break; } } } if(f.IsPublic && options.publicPackages != null) { bool found = false; foreach(string package in options.publicPackages) { if(f.Name.StartsWith(package)) { found = true; break; } } if(!found) { f.SetInternal(); } } if(f.SourceFileAttribute != null) { FileInfo path = itemRef.Path; if(path != null) { string sourceFile = Path.GetFullPath(Path.Combine(path.DirectoryName, f.SourceFileAttribute)); if(File.Exists(sourceFile)) { f.SourcePath = sourceFile; } } if(f.SourcePath == null) { if (options.sourcepath != null) { string package = f.Name; int index = package.LastIndexOf('.'); package = index == -1 ? "" : package.Substring(0, index).Replace('.', '/'); f.SourcePath = Path.GetFullPath(Path.Combine(options.sourcepath + "/" + package, f.SourceFileAttribute)); } else { f.SourcePath = f.SourceFileAttribute; } } } try { TypeWrapper tw = DefineClass(f, null); // we successfully created the type, so we don't need to include the class as a resource if (options.nojarstubs) { itemRef.Remove(); } else { itemRef.MarkAsStub(); } int pos = f.Name.LastIndexOf('.'); if (pos != -1) { string manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name; packages.DefinePackage(f.Name.Substring(0, pos), manifestJar); } return tw; } catch (ClassFormatError x) { StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); } catch (IllegalAccessError x) { StaticCompiler.IssueMessage(options, Message.IllegalAccessError, name, x.Message); } catch (VerifyError x) { StaticCompiler.IssueMessage(options, Message.VerificationError, name, x.Message); } catch (NoClassDefFoundError x) { if ((options.codegenoptions & CodeGenOptions.DisableDynamicBinding) != 0) { StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message); } StaticCompiler.IssueMessage(options, Message.ClassNotFound, x.Message); } catch (RetargetableJavaException x) { StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message); } StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); return null; } else { return null; } } }
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; }
private static bool CheckSupportedInterfaces(TypeWrapper caller, TypeWrapper tw, TypeWrapper[] markers, ClassFile.ConstantPoolItemMethodType[] bridges, out MethodWrapper[] methodList) { // we don't need to check for unloadable, because we already did that while validating the invoke signature if (!IsSupportedInterface(tw, caller)) { methodList = null; return false; } Dictionary<MethodKey, MethodWrapper> methods = new Dictionary<MethodKey,MethodWrapper>(); int abstractMethodCount = 0; int bridgeMethodCount = 0; if (GatherAllInterfaceMethods(tw, bridges, methods, ref abstractMethodCount, ref bridgeMethodCount) && abstractMethodCount == 1) { foreach (TypeWrapper marker in markers) { if (!IsSupportedInterface(marker, caller)) { methodList = null; return false; } if (!GatherAllInterfaceMethods(marker, null, methods, ref abstractMethodCount, ref bridgeMethodCount) || abstractMethodCount != 1) { methodList = null; return false; } } if (bridges != null && bridgeMethodCount != bridges.Length) { methodList = null; return false; } methodList = new MethodWrapper[methods.Count]; methods.Values.CopyTo(methodList, 0); return true; } methodList = null; return false; }
protected override void EmitMapXmlMetadata(TypeBuilder typeBuilder, ClassFile classFile, FieldWrapper[] fields, MethodWrapper[] methods) { Dictionary<string, IKVM.Internal.MapXml.Class> mapxml = classLoader.GetMapXmlClasses(); if(mapxml != null) { IKVM.Internal.MapXml.Class clazz; if(mapxml.TryGetValue(classFile.Name, out clazz)) { if(clazz.Attributes != null) { PublishAttributes(typeBuilder, clazz); } if(clazz.Properties != null) { PublishProperties(typeBuilder, clazz); } if(clazz.Fields != null) { foreach(IKVM.Internal.MapXml.Field field in clazz.Fields) { if(field.Attributes != null) { foreach(FieldWrapper fw in fields) { if(fw.Name == field.Name && fw.Signature == field.Sig) { FieldBuilder fb = fw.GetField() as FieldBuilder; if(fb != null) { foreach(IKVM.Internal.MapXml.Attribute attr in field.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, fb, attr); } } } } } } } if(clazz.Constructors != null) { // HACK this isn't the right place to do this, but for now it suffices foreach(IKVM.Internal.MapXml.Constructor constructor in clazz.Constructors) { // are we adding a new constructor? if(GetMethodWrapper(StringConstants.INIT, constructor.Sig, false) == null) { if(constructor.body == null) { Console.Error.WriteLine("Error: Constructor {0}.<init>{1} in xml remap file doesn't have a body.", clazz.Name, constructor.Sig); continue; } bool setmodifiers = false; MethodAttributes attribs = 0; MapModifiers(constructor.Modifiers, true, out setmodifiers, ref attribs); Type returnType; Type[] parameterTypes; MapSignature(constructor.Sig, out returnType, out parameterTypes); MethodBuilder cb = ReflectUtil.DefineConstructor(typeBuilder, attribs, parameterTypes); if(setmodifiers) { AttributeHelper.SetModifiers(cb, (Modifiers)constructor.Modifiers, false); } CompilerClassLoader.AddDeclaredExceptions(cb, constructor.throws); CodeEmitter ilgen = CodeEmitter.Create(cb); constructor.Emit(classLoader, ilgen); ilgen.DoEmit(); if(constructor.Attributes != null) { foreach(IKVM.Internal.MapXml.Attribute attr in constructor.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, cb, attr); } } } } foreach(IKVM.Internal.MapXml.Constructor constructor in clazz.Constructors) { if(constructor.Attributes != null) { foreach(MethodWrapper mw in methods) { if(mw.Name == "<init>" && mw.Signature == constructor.Sig) { MethodBuilder mb = mw.GetMethod() as MethodBuilder; if(mb != null) { foreach(IKVM.Internal.MapXml.Attribute attr in constructor.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, mb, attr); } } } } } } } if(clazz.Methods != null) { // HACK this isn't the right place to do this, but for now it suffices foreach(IKVM.Internal.MapXml.Method method in clazz.Methods) { // are we adding a new method? if(GetMethodWrapper(method.Name, method.Sig, false) == null) { if(method.body == null) { Console.Error.WriteLine("Error: Method {0}.{1}{2} in xml remap file doesn't have a body.", clazz.Name, method.Name, method.Sig); continue; } bool setmodifiers = false; MethodAttributes attribs = method.MethodAttributes; MapModifiers(method.Modifiers, false, out setmodifiers, ref attribs); Type returnType; Type[] parameterTypes; MapSignature(method.Sig, out returnType, out parameterTypes); MethodBuilder mb = typeBuilder.DefineMethod(method.Name, attribs, returnType, parameterTypes); if(setmodifiers) { AttributeHelper.SetModifiers(mb, (Modifiers)method.Modifiers, false); } if(method.@override != null) { MethodWrapper mw = GetClassLoader().LoadClassByDottedName([email protected]).GetMethodWrapper([email protected], method.Sig, true); mw.Link(); typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod()); } CompilerClassLoader.AddDeclaredExceptions(mb, method.throws); CodeEmitter ilgen = CodeEmitter.Create(mb); method.Emit(classLoader, ilgen); ilgen.DoEmit(); if(method.Attributes != null) { foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, mb, attr); } } } } foreach(IKVM.Internal.MapXml.Method method in clazz.Methods) { if(method.Attributes != null) { foreach(MethodWrapper mw in methods) { if(mw.Name == method.Name && mw.Signature == method.Sig) { MethodBuilder mb = mw.GetMethod() as MethodBuilder; if(mb != null) { foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes) { AttributeHelper.SetCustomAttribute(classLoader, mb, attr); } } } } } } } if(clazz.Interfaces != null) { foreach(IKVM.Internal.MapXml.Interface iface in clazz.Interfaces) { TypeWrapper tw = GetClassLoader().LoadClassByDottedName(iface.Name); // NOTE since this interface won't be part of the list in the ImplementAttribute, // it won't be visible from Java that the type implements this interface. typeBuilder.AddInterfaceImplementation(tw.TypeAsBaseType); if(iface.Methods != null) { foreach(IKVM.Internal.MapXml.Method m in iface.Methods) { MethodWrapper mw = tw.GetMethodWrapper(m.Name, m.Sig, false); if(mw == null) { throw new InvalidOperationException("Method " + m.Name + m.Sig + " not found in interface " + tw.Name); } mw.Link(); MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(this, typeBuilder, tw.Name + "/" + m.Name, MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.CheckAccessOnOverride); AttributeHelper.HideFromJava(mb); typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod()); CodeEmitter ilgen = CodeEmitter.Create(mb); m.Emit(classLoader, ilgen); ilgen.DoEmit(); } } } } } } }
private static bool GatherAllInterfaceMethods(TypeWrapper tw, ClassFile.ConstantPoolItemMethodType[] bridges, Dictionary<MethodKey, MethodWrapper> methods, ref int abstractMethodCount, ref int bridgeMethodCount) { 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)) { if (bridges != null && IsBridge(mw, bridges)) { bridgeMethodCount++; } else { abstractMethodCount++; } } } mw.Link(); if (mw.GetMethod() == null) { return false; } if (current != null && mw.RealName != current.RealName) { return false; } } } foreach (TypeWrapper tw1 in tw.Interfaces) { if (!GatherAllInterfaceMethods(tw1, bridges, methods, ref abstractMethodCount, ref bridgeMethodCount)) { return false; } } return true; }
internal AotTypeWrapper(ClassFile f, CompilerClassLoader loader) : base(f, loader, null) { }
private static bool IsBridge(MethodWrapper mw, ClassFile.ConstantPoolItemMethodType[] bridges) { foreach (ClassFile.ConstantPoolItemMethodType bridge in bridges) { if (bridge.Signature == mw.Signature) { return true; } } return false; }
private static BootstrapMethod[] ReadBootstrapMethods(BigEndianBinaryReader br, ClassFile classFile) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); ushort count = rdr.ReadUInt16(); BootstrapMethod[] bsm = new BootstrapMethod[count]; for(int i = 0; i < bsm.Length; i++) { ushort bsm_index = rdr.ReadUInt16(); if(bsm_index >= classFile.constantpool.Length || !(classFile.constantpool[bsm_index] is ConstantPoolItemMethodHandle)) { throw new ClassFormatError("bootstrap_method_index {0} has bad constant type in class file {1}", bsm_index, classFile.Name); } classFile.MarkLinkRequiredConstantPoolItem(bsm_index); ushort argument_count = rdr.ReadUInt16(); ushort[] args = new ushort[argument_count]; for(int j = 0; j < args.Length; j++) { ushort argument_index = rdr.ReadUInt16(); if(!classFile.IsValidConstant(argument_index)) { throw new ClassFormatError("argument_index {0} has bad constant type in class file {1}", argument_index, classFile.Name); } classFile.MarkLinkRequiredConstantPoolItem(argument_index); args[j] = argument_index; } bsm[i] = new BootstrapMethod(bsm_index, args); } if(!rdr.IsAtEnd) { throw new ClassFormatError("Bad length on BootstrapMethods in class file {0}", classFile.Name); } return bsm; }
private static bool MatchSignatures(MethodWrapper interfaceMethod, ClassFile.ConstantPoolItemMethodType samMethodType) { return interfaceMethod.ReturnType == samMethodType.GetRetType() && MatchTypes(interfaceMethod.GetParameters(), samMethodType.GetArgTypes()); }
private static object ReadAnnotation(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) { string type = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); ushort num_element_value_pairs = rdr.ReadUInt16(); object[] annot = new object[2 + num_element_value_pairs * 2]; annot[0] = AnnotationDefaultAttribute.TAG_ANNOTATION; annot[1] = type; for(int i = 0; i < num_element_value_pairs; i++) { annot[2 + i * 2 + 0] = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); annot[2 + i * 2 + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); } return annot; }
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 && mh.Member != null && IsLambdaMetafactory(mh.Member); }
private TypeWrapper GetTypeWrapperCompilerHook(string name) { RemapperTypeWrapper rtw; if(remapped.TryGetValue(name, out rtw)) { return rtw; } else { ClassItem classdef; if(classes.TryGetValue(name, out classdef)) { classes.Remove(name); ClassFile f; try { ClassFileParseOptions cfp = ClassFileParseOptions.LocalVariableTable; if(this.EmitStackTraceInfo) { cfp |= ClassFileParseOptions.LineNumberTable; } f = new ClassFile(classdef.data, 0, classdef.data.Length, name, cfp); } catch(ClassFormatError x) { StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); return null; } if(options.removeUnusedFields) { f.RemoveUnusedFields(); } if(f.IsPublic && options.privatePackages != null) { foreach(string p in options.privatePackages) { if(f.Name.StartsWith(p)) { f.SetInternal(); break; } } } if(f.IsPublic && options.publicPackages != null) { bool found = false; foreach(string package in options.publicPackages) { if(f.Name.StartsWith(package)) { found = true; break; } } if(!found) { f.SetInternal(); } } if(!f.IsInterface && !f.IsAbstract && !f.IsPublic && !f.IsInternal && !f.IsFinal && !baseClasses.ContainsKey(f.Name) && !options.targetIsModule && options.sharedclassloader == null) { f.SetEffectivelyFinal(); } if(f.SourceFileAttribute != null) { if(classdef.path != null) { string sourceFile = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(classdef.path), f.SourceFileAttribute)); if(File.Exists(sourceFile)) { f.SourcePath = sourceFile; } } if(f.SourcePath == null) { if (options.sourcepath != null) { string package = f.Name; int index = package.LastIndexOf('.'); package = index == -1 ? "" : package.Substring(0, index).Replace('.', '/'); f.SourcePath = Path.GetFullPath(Path.Combine(options.sourcepath + "/" + package, f.SourceFileAttribute)); } else { f.SourcePath = f.SourceFileAttribute; } } } try { TypeWrapper type = DefineClass(f, null); if(f.IKVMAssemblyAttribute != null) { importedStubTypes.Add(f.Name, type); } return type; } catch (ClassFormatError x) { StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); return null; } catch (IllegalAccessError x) { StaticCompiler.IssueMessage(options, Message.IllegalAccessError, name, x.Message); return null; } catch (VerifyError x) { StaticCompiler.IssueMessage(options, Message.VerificationError, name, x.Message); return null; } catch (NoClassDefFoundError x) { StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message); return null; } catch (RetargetableJavaException x) { StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message); return null; } } else { return null; } } }
private static bool IsLambdaAltMetafactory(ClassFile classFile, ClassFile.BootstrapMethod bsm) { ClassFile.ConstantPoolItemMethodHandle mh; AltFlags flags; int argpos = 4; return bsm.ArgumentCount >= 4 && (mh = classFile.GetConstantPoolConstantMethodHandle(bsm.BootstrapMethodIndex)).Kind == ClassFile.RefKind.invokeStatic && mh.Member != null && IsLambdaAltMetafactory(mh.Member) && classFile.GetConstantPoolConstantType(bsm.GetArgument(0)) == ClassFile.ConstantType.MethodType && classFile.GetConstantPoolConstantType(bsm.GetArgument(1)) == ClassFile.ConstantType.MethodHandle && classFile.GetConstantPoolConstantType(bsm.GetArgument(2)) == ClassFile.ConstantType.MethodType && classFile.GetConstantPoolConstantType(bsm.GetArgument(3)) == ClassFile.ConstantType.Integer && ((flags = (AltFlags)classFile.GetConstantPoolConstantInteger(bsm.GetArgument(3))) & ~AltFlags.Mask) == 0 && ((flags & AltFlags.Markers) == 0 || CheckOptionalArgs(classFile, bsm, ClassFile.ConstantType.Class, ref argpos)) && ((flags & AltFlags.Bridges) == 0 || CheckOptionalArgs(classFile, bsm, ClassFile.ConstantType.MethodType, ref argpos)) && argpos == bsm.ArgumentCount; }
internal DynamicPropertyFieldWrapper(TypeWrapper declaringType, ClassFile.Field fld) : base(declaringType, null, fld.Name, fld.Signature, new ExModifiers(fld.Modifiers, fld.IsInternal), null) { getter = GetMethod(fld.PropertyGetter, "()" + fld.Signature, fld.IsStatic); setter = GetMethod(fld.PropertySetter, "(" + fld.Signature + ")V", fld.IsStatic); }
private static bool CheckOptionalArgs(ClassFile classFile, ClassFile.BootstrapMethod bsm, ClassFile.ConstantType type, ref int argpos) { if (bsm.ArgumentCount - argpos < 1) { return false; } if (classFile.GetConstantPoolConstantType(bsm.GetArgument(argpos)) != ClassFile.ConstantType.Integer) { return false; } int count = classFile.GetConstantPoolConstantInteger(bsm.GetArgument(argpos++)); if (count < 0 || bsm.ArgumentCount - argpos < count) { return false; } for (int i = 0; i < count; i++) { if (classFile.GetConstantPoolConstantType(bsm.GetArgument(argpos++)) != type) { return false; } } return true; }