internal override void Finish() { // TODO we should insert method tracing (if enabled) Type[] paramTypes = this.GetParametersForDefineMethod(); MethodBuilder mbCore = GetMethod() as MethodBuilder; // NOTE sealed types don't have instance methods (only instancehelpers) if(mbCore != null) { CodeEmitter ilgen = CodeEmitter.Create(mbCore); MethodInfo baseMethod = null; if(m.@override != null) { baseMethod = DeclaringType.TypeAsTBD.GetMethod([email protected], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null); if(baseMethod == null) { throw new InvalidOperationException(); } ((TypeBuilder)DeclaringType.TypeAsBaseType).DefineMethodOverride(mbCore, baseMethod); } // TODO we need to support ghost (and other funky?) parameter types if(m.body != null) { // we manually walk the instruction list, because we need to special case the ret instructions IKVM.Internal.MapXml.CodeGenContext context = new IKVM.Internal.MapXml.CodeGenContext(DeclaringType.GetClassLoader()); foreach(IKVM.Internal.MapXml.Instruction instr in m.body.invoke) { if(instr is IKVM.Internal.MapXml.Ret) { this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); } instr.Generate(context, ilgen); } } else { if(m.redirect != null && m.redirect.LineNumber != -1) { ilgen.SetLineNumber((ushort)m.redirect.LineNumber); } int thisOffset = 0; if((m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) == 0) { thisOffset = 1; ilgen.Emit(OpCodes.Ldarg_0); } for(int i = 0; i < paramTypes.Length; i++) { ilgen.Emit(OpCodes.Ldarg, (short)(i + thisOffset)); } if(m.redirect != null) { EmitRedirect(DeclaringType.TypeAsTBD, ilgen); } else { if(baseMethod == null) { throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig); } ilgen.Emit(OpCodes.Call, baseMethod); } this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); ilgen.Emit(OpCodes.Ret); } ilgen.DoEmit(); if(this.DeclaringType.GetClassLoader().EmitStackTraceInfo) { ilgen.EmitLineNumberTable(mbCore); } } // NOTE static methods don't have helpers // NOTE for interface helpers we don't have to do anything, // because they've already been generated in DoLink // (currently this only applies to Comparable.compareTo). if(mbHelper != null && !this.DeclaringType.IsInterface) { CodeEmitter ilgen = CodeEmitter.Create(mbHelper); // check "this" for null if(m.@override != null && m.redirect == null && m.body == null && m.alternateBody == null) { // we're going to be calling the overridden version, so we don't need the null check } else if(!m.NoNullCheck) { ilgen.Emit(OpCodes.Ldarg_0); ilgen.EmitNullCheck(); } if(mbCore != null && (m.@override == null || m.redirect != null) && (m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Private) == 0 && (m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Final) == 0) { // TODO we should have a way to supress this for overridden methods ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Isinst, DeclaringType.TypeAsBaseType); ilgen.Emit(OpCodes.Dup); CodeEmitterLabel skip = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Brfalse_S, skip); for(int i = 0; i < paramTypes.Length; i++) { ilgen.Emit(OpCodes.Ldarg, (short)(i + 1)); } ilgen.Emit(OpCodes.Callvirt, mbCore); this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); ilgen.Emit(OpCodes.Ret); ilgen.MarkLabel(skip); ilgen.Emit(OpCodes.Pop); } foreach(RemapperTypeWrapper overrider in overriders) { RemappedMethodWrapper mw = (RemappedMethodWrapper)overrider.GetMethodWrapper(Name, Signature, false); if(mw.m.redirect == null && mw.m.body == null && mw.m.alternateBody == null) { // the overridden method doesn't actually do anything special (that means it will end // up calling the .NET method it overrides), so we don't need to special case this } else { ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Isinst, overrider.TypeAsTBD); ilgen.Emit(OpCodes.Dup); CodeEmitterLabel skip = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Brfalse_S, skip); for(int i = 0; i < paramTypes.Length; i++) { ilgen.Emit(OpCodes.Ldarg, (short)(i + 1)); } mw.Link(); mw.EmitCallvirtImpl(ilgen, false); this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); ilgen.Emit(OpCodes.Ret); ilgen.MarkLabel(skip); ilgen.Emit(OpCodes.Pop); } } if(m.body != null || m.alternateBody != null) { IKVM.Internal.MapXml.InstructionList body = m.alternateBody == null ? m.body : m.alternateBody; // we manually walk the instruction list, because we need to special case the ret instructions IKVM.Internal.MapXml.CodeGenContext context = new IKVM.Internal.MapXml.CodeGenContext(DeclaringType.GetClassLoader()); foreach(IKVM.Internal.MapXml.Instruction instr in body.invoke) { if(instr is IKVM.Internal.MapXml.Ret) { this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); } instr.Generate(context, ilgen); } } else { if(m.redirect != null && m.redirect.LineNumber != -1) { ilgen.SetLineNumber((ushort)m.redirect.LineNumber); } Type shadowType = ((RemapperTypeWrapper)DeclaringType).shadowType; for(int i = 0; i < paramTypes.Length + 1; i++) { ilgen.Emit(OpCodes.Ldarg, (short)i); } if(m.redirect != null) { EmitRedirect(shadowType, ilgen); } else if(m.@override != null) { MethodInfo baseMethod = shadowType.GetMethod([email protected], BindingFlags.Instance | BindingFlags.Public, null, paramTypes, null); if(baseMethod == null) { throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig); } ilgen.Emit(OpCodes.Callvirt, baseMethod); } else { RemappedMethodWrapper baseMethod = DeclaringType.BaseTypeWrapper.GetMethodWrapper(Name, Signature, true) as RemappedMethodWrapper; if(baseMethod == null || baseMethod.m.@override == null) { throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig); } MethodInfo overrideMethod = shadowType.GetMethod([email protected], BindingFlags.Instance | BindingFlags.Public, null, paramTypes, null); if(overrideMethod == null) { throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig); } ilgen.Emit(OpCodes.Callvirt, overrideMethod); } this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null); ilgen.Emit(OpCodes.Ret); } ilgen.DoEmit(); if(this.DeclaringType.GetClassLoader().EmitStackTraceInfo) { ilgen.EmitLineNumberTable(mbHelper); } } // do we need a helper for non-virtual reflection invocation? if(m.nonvirtualAlternateBody != null || (m.@override != null && overriders.Count > 0)) { RemapperTypeWrapper typeWrapper = (RemapperTypeWrapper)DeclaringType; Type[] argTypes = new Type[paramTypes.Length + 1]; argTypes[0] = typeWrapper.TypeAsSignatureType; this.GetParametersForDefineMethod().CopyTo(argTypes, 1); MethodBuilder mb = typeWrapper.typeBuilder.DefineMethod("nonvirtualhelper/" + this.Name, MethodAttributes.Private | MethodAttributes.Static, this.ReturnTypeForDefineMethod, argTypes); if(m.Attributes != null) { foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes) { AttributeHelper.SetCustomAttribute(DeclaringType.GetClassLoader(), mb, custattr); } } SetParameters(DeclaringType.GetClassLoader(), mb, m.Params); AttributeHelper.HideFromJava(mb); CodeEmitter ilgen = CodeEmitter.Create(mb); if(m.nonvirtualAlternateBody != null) { m.nonvirtualAlternateBody.Emit(DeclaringType.GetClassLoader(), ilgen); } else { Type shadowType = ((RemapperTypeWrapper)DeclaringType).shadowType; MethodInfo baseMethod = shadowType.GetMethod([email protected], BindingFlags.Instance | BindingFlags.Public, null, paramTypes, null); if(baseMethod == null) { throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig); } ilgen.Emit(OpCodes.Ldarg_0); for(int i = 0; i < paramTypes.Length; i++) { ilgen.Emit(OpCodes.Ldarg, (short)(i + 1)); } ilgen.Emit(OpCodes.Call, baseMethod); ilgen.Emit(OpCodes.Ret); } ilgen.DoEmit(); } }
private void DoEmit(CodeEmitter ilgen) { IKVM.Internal.MapXml.CodeGenContext context = new IKVM.Internal.MapXml.CodeGenContext(this.DeclaringType.GetClassLoader()); // we don't want the line numbers from map.xml, so we have our own emit loop for (int i = 0; i < code.invoke.Length; i++) { code.invoke[i].Generate(context, ilgen); } }