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();
}
}