2
Copyright (C) 2002-2009 Jeroen Frijters
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
12
1. The origin of this software must not be misrepresented; you must not
13
claim that you wrote the original software. If you use this software
14
in a product, an acknowledgment in the product documentation would be
15
appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
26
using System.Collections.Generic;
27
using IKVM.Reflection;
28
using IKVM.Reflection.Emit;
29
using Type = IKVM.Reflection.Type;
30
using System.Diagnostics;
31
using System.Security;
32
using System.Security.Permissions;
33
using IKVM.Attributes;
35
namespace IKVM.Internal
37
sealed class AotTypeWrapper : DynamicTypeWrapper
39
private FieldInfo ghostRefField;
40
private MethodBuilder ghostIsInstanceMethod;
41
private MethodBuilder ghostIsInstanceArrayMethod;
42
private MethodBuilder ghostCastMethod;
43
private MethodBuilder ghostCastArrayMethod;
44
private TypeBuilder typeBuilderGhostInterface;
45
private Annotation annotation;
46
private Type enumType;
47
private MethodWrapper[] replacedMethods;
48
private WorkaroundBaseClass workaroundBaseClass;
50
internal AotTypeWrapper(ClassFile f, CompilerClassLoader loader)
55
protected override Type GetBaseTypeForDefineType()
57
TypeWrapper baseTypeWrapper = BaseTypeWrapper;
58
if (this.IsPublic && this.IsAbstract && baseTypeWrapper.IsPublic && baseTypeWrapper.IsAbstract)
61
// if the current class widens access on an abstract base class method,
62
// we need to inject an artificial base class to workaround a C# compiler bug
63
List<MethodWrapper> methods = null;
64
foreach (MethodWrapper mw in GetMethods())
66
if (!mw.IsStatic && mw.IsPublic)
68
MethodWrapper baseMethod = baseTypeWrapper.GetMethodWrapper(mw.Name, mw.Signature, true);
69
if (baseMethod != null && baseMethod.IsAbstract && baseMethod.IsProtected)
73
methods = new List<MethodWrapper>();
75
methods.Add(baseMethod);
81
string name = "__WorkaroundBaseClass__." + Name;
82
while (!classLoader.ReserveName(name))
86
TypeWrapperFactory context = classLoader.GetTypeWrapperFactory();
87
TypeBuilder typeBuilder = context.ModuleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Abstract, base.GetBaseTypeForDefineType());
88
AttributeHelper.HideFromJava(typeBuilder);
89
AttributeHelper.SetEditorBrowsableNever(typeBuilder);
90
workaroundBaseClass = new WorkaroundBaseClass(this, typeBuilder, methods.ToArray());
91
List<MethodWrapper> constructors = new List<MethodWrapper>();
92
foreach (MethodWrapper mw in baseTypeWrapper.GetMethods())
94
if (ReferenceEquals(mw.Name, StringConstants.INIT) && mw.IsAccessibleFrom(baseTypeWrapper, this, this))
96
constructors.Add(new ConstructorForwarder(context, typeBuilder, mw));
99
replacedMethods = constructors.ToArray();
103
return base.GetBaseTypeForDefineType();
106
internal override void Finish()
109
if (workaroundBaseClass != null)
111
workaroundBaseClass.Finish();
115
private sealed class WorkaroundBaseClass
117
private readonly AotTypeWrapper wrapper;
118
private readonly TypeBuilder typeBuilder;
119
private readonly MethodWrapper[] methods;
120
private MethodBuilder baseSerializationCtor;
122
internal WorkaroundBaseClass(AotTypeWrapper wrapper, TypeBuilder typeBuilder, MethodWrapper[] methods)
124
this.wrapper = wrapper;
125
this.typeBuilder = typeBuilder;
126
this.methods = methods;
129
internal MethodBuilder GetSerializationConstructor()
131
if (baseSerializationCtor == null)
133
baseSerializationCtor = Serialization.AddAutomagicSerializationToWorkaroundBaseClass(typeBuilder, wrapper.BaseTypeWrapper.GetSerializationConstructor());
135
return baseSerializationCtor;
138
internal void Finish()
140
if (!typeBuilder.IsCreated())
142
foreach (MethodWrapper mw in methods)
144
MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(wrapper, typeBuilder, mw.Name, MethodAttributes.FamORAssem | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.CheckAccessOnOverride);
145
AttributeHelper.HideFromJava(mb);
146
CodeEmitter ilgen = CodeEmitter.Create(mb);
147
ilgen.EmitThrow("java.lang.AbstractMethodError");
150
typeBuilder.CreateType();
155
private sealed class ConstructorForwarder : MethodWrapper
157
private readonly TypeWrapperFactory context;
158
private readonly TypeBuilder typeBuilder;
159
private readonly MethodWrapper ctor;
160
private MethodBuilder constructorBuilder;
162
internal ConstructorForwarder(TypeWrapperFactory context, TypeBuilder typeBuilder, MethodWrapper ctor)
163
: base(ctor.DeclaringType, ctor.Name, ctor.Signature, null, null, null, ctor.Modifiers, MemberFlags.None)
165
this.context = context;
166
this.typeBuilder = typeBuilder;
170
protected override void DoLinkMethod()
173
DefineMethodHelper dmh = ctor.GetDefineMethodHelper();
174
constructorBuilder = dmh.DefineConstructor(context, typeBuilder, MethodAttributes.PrivateScope);
175
AttributeHelper.HideFromJava(constructorBuilder);
176
CodeEmitter ilgen = CodeEmitter.Create(constructorBuilder);
177
ilgen.Emit(OpCodes.Ldarg_0);
178
for (int i = 1; i <= dmh.ParameterCount; i++)
182
ctor.EmitCall(ilgen);
183
ilgen.Emit(OpCodes.Ret);
187
internal override void EmitCall(CodeEmitter ilgen)
189
ilgen.Emit(OpCodes.Call, constructorBuilder);
193
internal override bool IsGhost
197
return classLoader.IsGhost(this);
201
internal override bool IsMapUnsafeException
205
return classLoader.IsMapUnsafeException(this);
209
internal override Type TypeAsBaseType
213
return typeBuilderGhostInterface != null ? typeBuilderGhostInterface : base.TypeAsBaseType;
217
internal void GetParameterNamesFromXml(string methodName, string methodSig, string[] parameterNames)
219
IKVM.Internal.MapXml.Param[] parameters = classLoader.GetXmlMapParameters(Name, methodName, methodSig);
220
if(parameters != null)
222
for(int i = 0; i < parameters.Length; i++)
224
if(parameters[i].Name != null)
226
parameterNames[i] = parameters[i].Name;
232
internal void AddXmlMapParameterAttributes(MethodBuilder method, string className, string methodName, string methodSig, ref ParameterBuilder[] pbs)
234
IKVM.Internal.MapXml.Param[] parameters = classLoader.GetXmlMapParameters(className, methodName, methodSig);
235
if(parameters != null)
239
// let's hope that the parameters array is the right length
240
pbs = GetParameterBuilders(method, parameters.Length, null);
242
for(int i = 0; i < pbs.Length; i++)
244
if(parameters[i].Attributes != null)
246
foreach(IKVM.Internal.MapXml.Attribute attr in parameters[i].Attributes)
248
AttributeHelper.SetCustomAttribute(classLoader, pbs[i], attr);
255
private void AddParameterMetadata(MethodBuilder method, MethodWrapper mw)
257
ParameterBuilder[] pbs;
258
if((mw.DeclaringType.IsPublic && (mw.IsPublic || mw.IsProtected)) || classLoader.EmitDebugInfo)
260
string[] parameterNames = new string[mw.GetParameters().Length];
261
GetParameterNamesFromXml(mw.Name, mw.Signature, parameterNames);
262
GetParameterNamesFromSig(mw.Signature, parameterNames);
263
pbs = GetParameterBuilders(method, parameterNames.Length, parameterNames);
267
pbs = GetParameterBuilders(method, mw.GetParameters().Length, null);
269
if((mw.Modifiers & Modifiers.VarArgs) != 0 && pbs.Length > 0)
271
AttributeHelper.SetParamArrayAttribute(pbs[pbs.Length - 1]);
273
AddXmlMapParameterAttributes(method, Name, mw.Name, mw.Signature, ref pbs);
276
protected override void AddMapXmlFields(ref FieldWrapper[] fields)
278
Dictionary<string, IKVM.Internal.MapXml.Class> mapxml = classLoader.GetMapXmlClasses();
281
IKVM.Internal.MapXml.Class clazz;
282
if(mapxml.TryGetValue(this.Name, out clazz))
284
if(clazz.Fields != null)
286
foreach(IKVM.Internal.MapXml.Field field in clazz.Fields)
288
// are we adding a new field?
290
foreach(FieldWrapper fw in fields)
292
if(fw.Name == field.Name && fw.Signature == field.Sig)
300
FieldWrapper[] newFields = new FieldWrapper[fields.Length + 1];
301
Array.Copy(fields, newFields, fields.Length);
303
fields[fields.Length - 1] = FieldWrapper.Create(this, null, null, field.Name, field.Sig, new ExModifiers((Modifiers)field.Modifiers, false));
311
protected override bool EmitMapXmlMethodPrologueAndOrBody(CodeEmitter ilgen, ClassFile f, ClassFile.Method m)
313
IKVM.Internal.MapXml.InstructionList prologue = classLoader.GetMethodPrologue(new MethodKey(f.Name, m.Name, m.Signature));
316
prologue.Emit(classLoader, ilgen);
318
Dictionary<MethodKey, IKVM.Internal.MapXml.InstructionList> mapxml = classLoader.GetMapXmlMethodBodies();
321
IKVM.Internal.MapXml.InstructionList opcodes;
322
if(mapxml.TryGetValue(new MethodKey(f.Name, m.Name, m.Signature), out opcodes))
324
opcodes.Emit(classLoader, ilgen);
331
private void PublishAttributes(TypeBuilder typeBuilder, IKVM.Internal.MapXml.Class clazz)
333
foreach(IKVM.Internal.MapXml.Attribute attr in clazz.Attributes)
335
AttributeHelper.SetCustomAttribute(classLoader, typeBuilder, attr);
339
private static bool CheckPropertyArgs(Type[] args1, Type[] args2)
341
if(args1.Length == args2.Length)
343
for(int i = 0; i < args1.Length; i++)
345
if(args1[i] != args2[i])
355
private static MethodAttributes GetPropertyMethodAttributes(MethodWrapper mw, bool final)
357
MethodAttributes attribs = MethodAttributes.HideBySig;
360
attribs |= MethodAttributes.Static;
364
// NOTE in order for IntelliSense to consider the property a "real" property,
365
// the getter and setter methods need to have substantially the same method attributes,
366
// so we may need to look at our peer to determine whether we should be final
367
// or not (and vice versa).
368
attribs |= MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.CheckAccessOnOverride;
371
attribs |= MethodAttributes.Final;
374
// TODO what happens if accessibility doesn't match our peer?
377
attribs |= MethodAttributes.Public;
379
else if(mw.IsProtected)
381
attribs |= MethodAttributes.FamORAssem;
383
else if(mw.IsPrivate)
385
attribs |= MethodAttributes.Private;
389
attribs |= MethodAttributes.Assembly;
394
private void PublishProperties(TypeBuilder typeBuilder, IKVM.Internal.MapXml.Class clazz)
396
foreach(IKVM.Internal.MapXml.Property prop in clazz.Properties)
398
TypeWrapper typeWrapper = GetClassLoader().RetTypeWrapperFromSigNoThrow(prop.Sig);
399
TypeWrapper[] propargs = GetClassLoader().ArgTypeWrapperListFromSigNoThrow(prop.Sig);
400
Type[] indexer = new Type[propargs.Length];
401
for(int i = 0; i < propargs.Length; i++)
403
indexer[i] = propargs[i].TypeAsSignatureType;
405
PropertyBuilder propbuilder = typeBuilder.DefineProperty(prop.Name, PropertyAttributes.None, typeWrapper.TypeAsSignatureType, indexer);
406
AttributeHelper.HideFromJava(propbuilder);
407
if(prop.Attributes != null)
409
foreach(IKVM.Internal.MapXml.Attribute attr in prop.Attributes)
411
AttributeHelper.SetCustomAttribute(classLoader, propbuilder, attr);
414
MethodWrapper getter = null;
415
MethodWrapper setter = null;
416
if(prop.getter != null)
418
getter = GetMethodWrapper(prop.getter.Name, prop.getter.Sig, true);
421
Console.Error.WriteLine("Warning: getter not found for {0}::{1}", clazz.Name, prop.Name);
424
if(prop.setter != null)
426
setter = GetMethodWrapper(prop.setter.Name, prop.setter.Sig, true);
429
Console.Error.WriteLine("Warning: setter not found for {0}::{1}", clazz.Name, prop.Name);
432
bool final = (getter != null && getter.IsFinal) || (setter != null && setter.IsFinal);
435
MethodWrapper mw = getter;
436
if(!CheckPropertyArgs(mw.GetParametersForDefineMethod(), indexer) || mw.ReturnType != typeWrapper)
438
Console.Error.WriteLine("Warning: ignoring invalid property getter for {0}::{1}", clazz.Name, prop.Name);
442
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
443
if(mb == null || mb.DeclaringType != typeBuilder || (!mb.IsFinal && final))
445
mb = typeBuilder.DefineMethod("get_" + prop.Name, GetPropertyMethodAttributes(mw, final), typeWrapper.TypeAsSignatureType, indexer);
446
AttributeHelper.HideFromJava(mb);
447
CodeEmitter ilgen = CodeEmitter.Create(mb);
450
for(int i = 0; i < indexer.Length; i++)
458
ilgen.Emit(OpCodes.Ldarg_0);
459
for(int i = 0; i < indexer.Length; i++)
461
ilgen.EmitLdarg(i + 1);
463
mw.EmitCallvirt(ilgen);
465
ilgen.Emit(OpCodes.Ret);
468
propbuilder.SetGetMethod(mb);
473
MethodWrapper mw = setter;
474
Type[] args = new Type[indexer.Length + 1];
475
indexer.CopyTo(args, 0);
476
args[args.Length - 1] = typeWrapper.TypeAsSignatureType;
477
if(!CheckPropertyArgs(args, mw.GetParametersForDefineMethod()))
479
Console.Error.WriteLine("Warning: ignoring invalid property setter for {0}::{1}", clazz.Name, prop.Name);
483
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
484
if(mb == null || mb.DeclaringType != typeBuilder || (!mb.IsFinal && final))
486
mb = typeBuilder.DefineMethod("set_" + prop.Name, GetPropertyMethodAttributes(mw, final), mw.ReturnTypeForDefineMethod, args);
487
AttributeHelper.HideFromJava(mb);
488
CodeEmitter ilgen = CodeEmitter.Create(mb);
491
for(int i = 0; i <= indexer.Length; i++)
499
ilgen.Emit(OpCodes.Ldarg_0);
500
for(int i = 0; i <= indexer.Length; i++)
502
ilgen.EmitLdarg(i + 1);
504
mw.EmitCallvirt(ilgen);
506
ilgen.Emit(OpCodes.Ret);
509
propbuilder.SetSetMethod(mb);
515
protected override bool IsPInvokeMethod(ClassFile.Method m)
517
Dictionary<string, IKVM.Internal.MapXml.Class> mapxml = classLoader.GetMapXmlClasses();
520
IKVM.Internal.MapXml.Class clazz;
521
if(mapxml.TryGetValue(this.Name, out clazz) && clazz.Methods != null)
523
foreach(IKVM.Internal.MapXml.Method method in clazz.Methods)
525
if(method.Name == m.Name && method.Sig == m.Signature)
527
if(method.Attributes != null)
529
foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes)
531
if(StaticCompiler.GetType(classLoader, attr.Type) == JVM.Import(typeof(System.Runtime.InteropServices.DllImportAttribute)))
542
return base.IsPInvokeMethod(m);
545
private static void MapModifiers(MapXml.MapModifiers mapmods, bool isConstructor, out bool setmodifiers, ref MethodAttributes attribs)
547
setmodifiers = false;
548
Modifiers modifiers = (Modifiers)mapmods;
549
if((modifiers & Modifiers.Public) != 0)
551
attribs |= MethodAttributes.Public;
553
else if((modifiers & Modifiers.Protected) != 0)
555
attribs |= MethodAttributes.FamORAssem;
557
else if((modifiers & Modifiers.Private) != 0)
559
attribs |= MethodAttributes.Private;
563
attribs |= MethodAttributes.Assembly;
565
if((modifiers & Modifiers.Static) != 0)
567
attribs |= MethodAttributes.Static;
568
if((modifiers & Modifiers.Final) != 0)
573
else if(!isConstructor)
575
// NOTE we're abusing the MethodAttributes.NewSlot and Modifiers.Final combination to mean non-virtual
576
if((modifiers & Modifiers.Final) != 0 && (attribs & MethodAttributes.NewSlot) != 0 && (attribs & MethodAttributes.Virtual) == 0)
578
// remove NewSlot, because it doesn't make sense on a non-virtual method
579
attribs &= ~MethodAttributes.NewSlot;
583
attribs |= MethodAttributes.Virtual;
584
if((modifiers & Modifiers.Final) != 0)
586
attribs |= MethodAttributes.Final;
588
else if((modifiers & Modifiers.Abstract) != 0)
590
attribs |= MethodAttributes.Abstract;
594
if((modifiers & Modifiers.Synchronized) != 0)
596
throw new NotImplementedException();
600
private void MapSignature(string sig, out Type returnType, out Type[] parameterTypes)
602
returnType = GetClassLoader().RetTypeWrapperFromSigNoThrow(sig).TypeAsSignatureType;
603
TypeWrapper[] parameterTypeWrappers = GetClassLoader().ArgTypeWrapperListFromSigNoThrow(sig);
604
parameterTypes = new Type[parameterTypeWrappers.Length];
605
for(int i = 0; i < parameterTypeWrappers.Length; i++)
607
parameterTypes[i] = parameterTypeWrappers[i].TypeAsSignatureType;
611
protected override void EmitMapXmlMetadata(TypeBuilder typeBuilder, ClassFile classFile, FieldWrapper[] fields, MethodWrapper[] methods)
613
Dictionary<string, IKVM.Internal.MapXml.Class> mapxml = classLoader.GetMapXmlClasses();
616
IKVM.Internal.MapXml.Class clazz;
617
if(mapxml.TryGetValue(classFile.Name, out clazz))
619
if(clazz.Attributes != null)
621
PublishAttributes(typeBuilder, clazz);
623
if(clazz.Properties != null)
625
PublishProperties(typeBuilder, clazz);
627
if(clazz.Fields != null)
629
foreach(IKVM.Internal.MapXml.Field field in clazz.Fields)
631
if(field.Attributes != null)
633
foreach(FieldWrapper fw in fields)
635
if(fw.Name == field.Name && fw.Signature == field.Sig)
637
FieldBuilder fb = fw.GetField() as FieldBuilder;
640
foreach(IKVM.Internal.MapXml.Attribute attr in field.Attributes)
642
AttributeHelper.SetCustomAttribute(classLoader, fb, attr);
650
if(clazz.Constructors != null)
652
// HACK this isn't the right place to do this, but for now it suffices
653
foreach(IKVM.Internal.MapXml.Constructor constructor in clazz.Constructors)
655
// are we adding a new constructor?
656
if(GetMethodWrapper(StringConstants.INIT, constructor.Sig, false) == null)
658
if(constructor.body == null)
660
Console.Error.WriteLine("Error: Constructor {0}.<init>{1} in xml remap file doesn't have a body.", clazz.Name, constructor.Sig);
663
bool setmodifiers = false;
664
MethodAttributes attribs = 0;
665
MapModifiers(constructor.Modifiers, true, out setmodifiers, ref attribs);
667
Type[] parameterTypes;
668
MapSignature(constructor.Sig, out returnType, out parameterTypes);
669
MethodBuilder cb = ReflectUtil.DefineConstructor(typeBuilder, attribs, parameterTypes);
672
AttributeHelper.SetModifiers(cb, (Modifiers)constructor.Modifiers, false);
674
CompilerClassLoader.AddDeclaredExceptions(cb, constructor.throws);
675
CodeEmitter ilgen = CodeEmitter.Create(cb);
676
constructor.Emit(classLoader, ilgen);
678
if(constructor.Attributes != null)
680
foreach(IKVM.Internal.MapXml.Attribute attr in constructor.Attributes)
682
AttributeHelper.SetCustomAttribute(classLoader, cb, attr);
687
foreach(IKVM.Internal.MapXml.Constructor constructor in clazz.Constructors)
689
if(constructor.Attributes != null)
691
foreach(MethodWrapper mw in methods)
693
if(mw.Name == "<init>" && mw.Signature == constructor.Sig)
695
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
698
foreach(IKVM.Internal.MapXml.Attribute attr in constructor.Attributes)
700
AttributeHelper.SetCustomAttribute(classLoader, mb, attr);
708
if(clazz.Methods != null)
710
// HACK this isn't the right place to do this, but for now it suffices
711
foreach(IKVM.Internal.MapXml.Method method in clazz.Methods)
713
// are we adding a new method?
714
if(GetMethodWrapper(method.Name, method.Sig, false) == null)
716
if(method.body == null)
718
Console.Error.WriteLine("Error: Method {0}.{1}{2} in xml remap file doesn't have a body.", clazz.Name, method.Name, method.Sig);
721
bool setmodifiers = false;
722
MethodAttributes attribs = method.MethodAttributes;
723
MapModifiers(method.Modifiers, false, out setmodifiers, ref attribs);
725
Type[] parameterTypes;
726
MapSignature(method.Sig, out returnType, out parameterTypes);
727
MethodBuilder mb = typeBuilder.DefineMethod(method.Name, attribs, returnType, parameterTypes);
730
AttributeHelper.SetModifiers(mb, (Modifiers)method.Modifiers, false);
732
if(method.@override != null)
734
MethodWrapper mw = GetClassLoader().LoadClassByDottedName(method.@override.Class).GetMethodWrapper(method.@override.Name, method.Sig, true);
736
typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod());
738
CompilerClassLoader.AddDeclaredExceptions(mb, method.throws);
739
CodeEmitter ilgen = CodeEmitter.Create(mb);
740
method.Emit(classLoader, ilgen);
742
if(method.Attributes != null)
744
foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes)
746
AttributeHelper.SetCustomAttribute(classLoader, mb, attr);
751
foreach(IKVM.Internal.MapXml.Method method in clazz.Methods)
753
if(method.Attributes != null)
755
foreach(MethodWrapper mw in methods)
757
if(mw.Name == method.Name && mw.Signature == method.Sig)
759
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
762
foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes)
764
AttributeHelper.SetCustomAttribute(classLoader, mb, attr);
772
if(clazz.Interfaces != null)
774
foreach(IKVM.Internal.MapXml.Interface iface in clazz.Interfaces)
776
TypeWrapper tw = GetClassLoader().LoadClassByDottedName(iface.Name);
777
// NOTE since this interface won't be part of the list in the ImplementAttribute,
778
// it won't be visible from Java that the type implements this interface.
779
typeBuilder.AddInterfaceImplementation(tw.TypeAsBaseType);
780
if(iface.Methods != null)
782
foreach(IKVM.Internal.MapXml.Method m in iface.Methods)
784
MethodWrapper mw = tw.GetMethodWrapper(m.Name, m.Sig, false);
787
throw new InvalidOperationException("Method " + m.Name + m.Sig + " not found in interface " + tw.Name);
790
MethodBuilder mb = mw.GetDefineMethodHelper().DefineMethod(this, typeBuilder, tw.Name + "/" + m.Name, MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.CheckAccessOnOverride);
791
AttributeHelper.HideFromJava(mb);
792
typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod());
793
CodeEmitter ilgen = CodeEmitter.Create(mb);
794
m.Emit(classLoader, ilgen);
804
protected override MethodBuilder DefineGhostMethod(string name, MethodAttributes attribs, MethodWrapper mw)
806
if(typeBuilderGhostInterface != null)
808
return mw.GetDefineMethodHelper().DefineMethod(this, typeBuilderGhostInterface, name, attribs);
813
protected override void FinishGhost(TypeBuilder typeBuilder, MethodWrapper[] methods)
815
if(typeBuilderGhostInterface != null)
817
// TODO consider adding methods from base interface and java.lang.Object as well
818
for(int i = 0; i < methods.Length; i++)
821
if(!methods[i].IsStatic)
823
TypeWrapper[] args = methods[i].GetParameters();
824
MethodBuilder stub = methods[i].GetDefineMethodHelper().DefineMethod(this, typeBuilder, methods[i].Name, MethodAttributes.Public);
825
AddParameterMetadata(stub, methods[i]);
826
AttributeHelper.SetModifiers(stub, methods[i].Modifiers, methods[i].IsInternal);
827
CodeEmitter ilgen = CodeEmitter.Create(stub);
828
CodeEmitterLabel end = ilgen.DefineLabel();
829
TypeWrapper[] implementers = classLoader.GetGhostImplementers(this);
830
ilgen.Emit(OpCodes.Ldarg_0);
831
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
832
ilgen.Emit(OpCodes.Dup);
833
ilgen.Emit(OpCodes.Isinst, typeBuilderGhostInterface);
834
CodeEmitterLabel label = ilgen.DefineLabel();
835
ilgen.EmitBrfalse(label);
836
ilgen.Emit(OpCodes.Castclass, typeBuilderGhostInterface);
837
for(int k = 0; k < args.Length; k++)
839
ilgen.EmitLdarg(k + 1);
841
ilgen.Emit(OpCodes.Callvirt, (MethodInfo)methods[i].GetMethod());
843
ilgen.MarkLabel(label);
844
for(int j = 0; j < implementers.Length; j++)
846
ilgen.Emit(OpCodes.Dup);
847
ilgen.Emit(OpCodes.Isinst, implementers[j].TypeAsTBD);
848
label = ilgen.DefineLabel();
849
ilgen.EmitBrfalse(label);
850
ilgen.Emit(OpCodes.Castclass, implementers[j].TypeAsTBD);
851
for(int k = 0; k < args.Length; k++)
853
ilgen.EmitLdarg(k + 1);
855
MethodWrapper mw = implementers[j].GetMethodWrapper(methods[i].Name, methods[i].Signature, true);
856
mw.EmitCallvirt(ilgen);
858
ilgen.MarkLabel(label);
860
// we need to do a null check (null fails all the isinst checks)
861
ilgen.EmitNullCheck();
862
ilgen.EmitThrow("java.lang.IncompatibleClassChangeError", Name);
863
ilgen.MarkLabel(end);
864
ilgen.Emit(OpCodes.Ret);
868
// HACK create a scope to enable reuse of "implementers" name
873
CodeEmitterLocal local;
874
// add implicit conversions for all the ghost implementers
875
TypeWrapper[] implementers = classLoader.GetGhostImplementers(this);
876
for(int i = 0; i < implementers.Length; i++)
878
mb = typeBuilder.DefineMethod("op_Implicit", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, TypeAsSignatureType, new Type[] { implementers[i].TypeAsSignatureType });
879
AttributeHelper.HideFromJava(mb);
880
ilgen = CodeEmitter.Create(mb);
881
local = ilgen.DeclareLocal(TypeAsSignatureType);
882
ilgen.Emit(OpCodes.Ldloca, local);
883
ilgen.Emit(OpCodes.Ldarg_0);
884
ilgen.Emit(OpCodes.Stfld, ghostRefField);
885
ilgen.Emit(OpCodes.Ldloca, local);
886
ilgen.Emit(OpCodes.Ldobj, TypeAsSignatureType);
887
ilgen.Emit(OpCodes.Ret);
890
// Implement the "IsInstance" method
891
mb = ghostIsInstanceMethod;
892
AttributeHelper.HideFromJava(mb);
893
ilgen = CodeEmitter.Create(mb);
894
CodeEmitterLabel end = ilgen.DefineLabel();
895
for(int i = 0; i < implementers.Length; i++)
897
ilgen.Emit(OpCodes.Ldarg_0);
898
ilgen.Emit(OpCodes.Isinst, implementers[i].TypeAsTBD);
899
CodeEmitterLabel label = ilgen.DefineLabel();
900
ilgen.EmitBrfalse(label);
901
ilgen.Emit(OpCodes.Ldc_I4_1);
903
ilgen.MarkLabel(label);
905
ilgen.Emit(OpCodes.Ldarg_0);
906
ilgen.Emit(OpCodes.Isinst, typeBuilderGhostInterface);
907
ilgen.Emit(OpCodes.Ldnull);
908
ilgen.Emit(OpCodes.Cgt_Un);
909
ilgen.MarkLabel(end);
910
ilgen.Emit(OpCodes.Ret);
912
// Implement the "IsInstanceArray" method
913
mb = ghostIsInstanceArrayMethod;
914
AttributeHelper.HideFromJava(mb);
915
ilgen = CodeEmitter.Create(mb);
916
CodeEmitterLocal localType = ilgen.DeclareLocal(Types.Type);
917
CodeEmitterLocal localRank = ilgen.DeclareLocal(Types.Int32);
918
ilgen.Emit(OpCodes.Ldarg_0);
919
CodeEmitterLabel skip = ilgen.DefineLabel();
920
ilgen.EmitBrtrue(skip);
921
ilgen.Emit(OpCodes.Ldc_I4_0);
922
ilgen.Emit(OpCodes.Ret);
923
ilgen.MarkLabel(skip);
924
ilgen.Emit(OpCodes.Ldarg_0);
925
ilgen.Emit(OpCodes.Call, Compiler.getTypeMethod);
926
ilgen.Emit(OpCodes.Stloc, localType);
927
ilgen.Emit(OpCodes.Ldarg_1);
928
ilgen.Emit(OpCodes.Stloc, localRank);
929
skip = ilgen.DefineLabel();
931
CodeEmitterLabel iter = ilgen.DefineLabel();
932
ilgen.MarkLabel(iter);
933
ilgen.Emit(OpCodes.Ldloc, localType);
934
ilgen.Emit(OpCodes.Callvirt, Types.Type.GetMethod("GetElementType"));
935
ilgen.Emit(OpCodes.Stloc, localType);
936
ilgen.Emit(OpCodes.Ldloc, localRank);
937
ilgen.Emit(OpCodes.Ldc_I4_1);
938
ilgen.Emit(OpCodes.Sub);
939
ilgen.Emit(OpCodes.Stloc, localRank);
940
ilgen.Emit(OpCodes.Ldloc, localRank);
941
CodeEmitterLabel typecheck = ilgen.DefineLabel();
942
ilgen.EmitBrfalse(typecheck);
943
ilgen.MarkLabel(skip);
944
ilgen.Emit(OpCodes.Ldloc, localType);
945
ilgen.Emit(OpCodes.Callvirt, Types.Type.GetMethod("get_IsArray"));
946
ilgen.EmitBrtrue(iter);
947
ilgen.Emit(OpCodes.Ldc_I4_0);
948
ilgen.Emit(OpCodes.Ret);
949
ilgen.MarkLabel(typecheck);
950
for(int i = 0; i < implementers.Length; i++)
952
ilgen.Emit(OpCodes.Ldtoken, implementers[i].TypeAsTBD);
953
ilgen.Emit(OpCodes.Call, Types.Type.GetMethod("GetTypeFromHandle"));
954
ilgen.Emit(OpCodes.Ldloc, localType);
955
ilgen.Emit(OpCodes.Callvirt, Types.Type.GetMethod("IsAssignableFrom"));
956
CodeEmitterLabel label = ilgen.DefineLabel();
957
ilgen.EmitBrfalse(label);
958
ilgen.Emit(OpCodes.Ldc_I4_1);
959
ilgen.Emit(OpCodes.Ret);
960
ilgen.MarkLabel(label);
962
ilgen.Emit(OpCodes.Ldtoken, typeBuilderGhostInterface);
963
ilgen.Emit(OpCodes.Call, Types.Type.GetMethod("GetTypeFromHandle"));
964
ilgen.Emit(OpCodes.Ldloc, localType);
965
ilgen.Emit(OpCodes.Callvirt, Types.Type.GetMethod("IsAssignableFrom"));
966
skip = ilgen.DefineLabel();
967
ilgen.EmitBrfalse(skip);
968
ilgen.Emit(OpCodes.Ldc_I4_1);
969
ilgen.Emit(OpCodes.Ret);
970
ilgen.MarkLabel(skip);
971
ilgen.Emit(OpCodes.Ldarg_0);
972
ilgen.Emit(OpCodes.Ldtoken, typeBuilder);
973
ilgen.Emit(OpCodes.Ldarg_1);
974
ilgen.Emit(OpCodes.Call, StaticCompiler.GetRuntimeType("IKVM.Runtime.GhostTag").GetMethod("IsGhostArrayInstance", BindingFlags.NonPublic | BindingFlags.Static));
975
ilgen.Emit(OpCodes.Ret);
978
// Implement the "Cast" method
979
mb = ghostCastMethod;
980
AttributeHelper.HideFromJava(mb);
981
ilgen = CodeEmitter.Create(mb);
982
end = ilgen.DefineLabel();
983
for(int i = 0; i < implementers.Length; i++)
985
ilgen.Emit(OpCodes.Ldarg_0);
986
ilgen.Emit(OpCodes.Isinst, implementers[i].TypeAsTBD);
987
ilgen.EmitBrtrue(end);
989
ilgen.Emit(OpCodes.Ldarg_0);
990
ilgen.Emit(OpCodes.Castclass, typeBuilderGhostInterface);
991
ilgen.Emit(OpCodes.Pop);
992
ilgen.MarkLabel(end);
993
local = ilgen.DeclareLocal(TypeAsSignatureType);
994
ilgen.Emit(OpCodes.Ldloca, local);
995
ilgen.Emit(OpCodes.Ldarg_0);
996
ilgen.Emit(OpCodes.Stfld, ghostRefField);
997
ilgen.Emit(OpCodes.Ldloca, local);
998
ilgen.Emit(OpCodes.Ldobj, TypeAsSignatureType);
999
ilgen.Emit(OpCodes.Ret);
1001
// Add "ToObject" methods
1002
mb = typeBuilder.DefineMethod("ToObject", MethodAttributes.HideBySig | MethodAttributes.Public, Types.Object, Type.EmptyTypes);
1003
AttributeHelper.HideFromJava(mb);
1004
ilgen = CodeEmitter.Create(mb);
1005
ilgen.Emit(OpCodes.Ldarg_0);
1006
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1007
ilgen.Emit(OpCodes.Ret);
1010
// Implement the "CastArray" method
1011
// NOTE unlike "Cast" this doesn't return anything, it just throws a ClassCastException if the
1012
// cast is unsuccessful. Also, because of the complexity of this test, we call IsInstanceArray
1013
// instead of reimplementing the check here.
1014
mb = ghostCastArrayMethod;
1015
AttributeHelper.HideFromJava(mb);
1016
ilgen = CodeEmitter.Create(mb);
1017
end = ilgen.DefineLabel();
1018
ilgen.Emit(OpCodes.Ldarg_0);
1019
ilgen.EmitBrfalse(end);
1020
ilgen.Emit(OpCodes.Ldarg_0);
1021
ilgen.Emit(OpCodes.Ldarg_1);
1022
ilgen.Emit(OpCodes.Call, ghostIsInstanceArrayMethod);
1023
ilgen.EmitBrtrue(end);
1024
ilgen.Emit(OpCodes.Ldarg_0);
1025
ilgen.Emit(OpCodes.Ldtoken, typeBuilder);
1026
ilgen.Emit(OpCodes.Ldarg_1);
1027
ilgen.Emit(OpCodes.Call, StaticCompiler.GetRuntimeType("IKVM.Runtime.GhostTag").GetMethod("ThrowClassCastException", BindingFlags.NonPublic | BindingFlags.Static));
1028
ilgen.MarkLabel(end);
1029
ilgen.Emit(OpCodes.Ret);
1032
// Implement the "Equals" method
1033
mb = typeBuilder.DefineMethod("Equals", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual, Types.Boolean, new Type[] { Types.Object });
1034
AttributeHelper.HideFromJava(mb);
1035
ilgen = CodeEmitter.Create(mb);
1036
ilgen.Emit(OpCodes.Ldarg_0);
1037
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1038
ilgen.Emit(OpCodes.Ldarg_1);
1039
ilgen.Emit(OpCodes.Ceq);
1040
ilgen.Emit(OpCodes.Ret);
1043
// Implement the "GetHashCode" method
1044
mb = typeBuilder.DefineMethod("GetHashCode", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual, Types.Int32, Type.EmptyTypes);
1045
AttributeHelper.HideFromJava(mb);
1046
ilgen = CodeEmitter.Create(mb);
1047
ilgen.Emit(OpCodes.Ldarg_0);
1048
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1049
ilgen.Emit(OpCodes.Callvirt, Types.Object.GetMethod("GetHashCode"));
1050
ilgen.Emit(OpCodes.Ret);
1053
// Implement the "op_Equality" method
1054
mb = typeBuilder.DefineMethod("op_Equality", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, Types.Boolean, new Type[] { typeBuilder, typeBuilder });
1055
AttributeHelper.HideFromJava(mb);
1056
ilgen = CodeEmitter.Create(mb);
1057
ilgen.EmitLdarga(0);
1058
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1059
ilgen.EmitLdarga(1);
1060
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1061
ilgen.Emit(OpCodes.Ceq);
1062
ilgen.Emit(OpCodes.Ret);
1065
// Implement the "op_Inequality" method
1066
mb = typeBuilder.DefineMethod("op_Inequality", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, Types.Boolean, new Type[] { typeBuilder, typeBuilder });
1067
AttributeHelper.HideFromJava(mb);
1068
ilgen = CodeEmitter.Create(mb);
1069
ilgen.EmitLdarga(0);
1070
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1071
ilgen.EmitLdarga(1);
1072
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
1073
ilgen.Emit(OpCodes.Ceq);
1074
ilgen.Emit(OpCodes.Ldc_I4_0);
1075
ilgen.Emit(OpCodes.Ceq);
1076
ilgen.Emit(OpCodes.Ret);
1082
protected override void FinishGhostStep2()
1084
if(typeBuilderGhostInterface != null)
1086
typeBuilderGhostInterface.CreateType();
1090
protected override TypeBuilder DefineGhostType(string mangledTypeName, TypeAttributes typeAttribs)
1092
typeAttribs &= ~(TypeAttributes.Interface | TypeAttributes.Abstract);
1093
typeAttribs |= TypeAttributes.Class | TypeAttributes.Sealed;
1094
TypeBuilder typeBuilder = classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineType(mangledTypeName, typeAttribs, Types.ValueType);
1095
AttributeHelper.SetGhostInterface(typeBuilder);
1096
AttributeHelper.SetModifiers(typeBuilder, Modifiers, IsInternal);
1097
ghostRefField = typeBuilder.DefineField("__<ref>", Types.Object, FieldAttributes.Public | FieldAttributes.SpecialName);
1098
typeBuilderGhostInterface = typeBuilder.DefineNestedType("__Interface", TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.NestedPublic);
1099
AttributeHelper.HideFromJava(typeBuilderGhostInterface);
1100
ghostIsInstanceMethod = typeBuilder.DefineMethod("IsInstance", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, Types.Boolean, new Type[] { Types.Object });
1101
ghostIsInstanceMethod.DefineParameter(1, ParameterAttributes.None, "obj");
1102
ghostIsInstanceArrayMethod = typeBuilder.DefineMethod("IsInstanceArray", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, Types.Boolean, new Type[] { Types.Object, Types.Int32 });
1103
ghostIsInstanceArrayMethod.DefineParameter(1, ParameterAttributes.None, "obj");
1104
ghostIsInstanceArrayMethod.DefineParameter(2, ParameterAttributes.None, "rank");
1105
ghostCastMethod = typeBuilder.DefineMethod("Cast", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, typeBuilder, new Type[] { Types.Object });
1106
ghostCastMethod.DefineParameter(1, ParameterAttributes.None, "obj");
1107
ghostCastArrayMethod = typeBuilder.DefineMethod("CastArray", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, Types.Void, new Type[] { Types.Object, Types.Int32 });
1108
ghostCastArrayMethod.DefineParameter(1, ParameterAttributes.None, "obj");
1109
ghostCastArrayMethod.DefineParameter(2, ParameterAttributes.None, "rank");
1113
internal override FieldInfo GhostRefField
1117
return ghostRefField;
1121
internal override void EmitCheckcast(TypeWrapper context, CodeEmitter ilgen)
1125
ilgen.Emit(OpCodes.Dup);
1126
ilgen.Emit(OpCodes.Call, ghostCastMethod);
1127
ilgen.Emit(OpCodes.Pop);
1129
else if(IsGhostArray)
1131
ilgen.Emit(OpCodes.Dup);
1132
TypeWrapper tw = this;
1137
tw = tw.ElementTypeWrapper;
1139
ilgen.EmitLdc_I4(rank);
1140
ilgen.Emit(OpCodes.Call, ghostCastArrayMethod);
1141
ilgen.Emit(OpCodes.Castclass, ArrayTypeWrapper.MakeArrayType(Types.Object, rank));
1145
base.EmitCheckcast(context, ilgen);
1149
internal override void EmitInstanceOf(TypeWrapper context, CodeEmitter ilgen)
1153
ilgen.Emit(OpCodes.Call, ghostIsInstanceMethod);
1155
else if(IsGhostArray)
1157
ilgen.Emit(OpCodes.Call, ghostIsInstanceArrayMethod);
1161
base.EmitInstanceOf(context, ilgen);
1165
internal void SetAnnotation(Annotation annotation)
1167
this.annotation = annotation;
1170
internal override Annotation Annotation
1178
internal void SetEnumType(Type enumType)
1180
this.enumType = enumType;
1183
internal override Type EnumType
1191
private sealed class ReplacedMethodWrapper : MethodWrapper
1193
private IKVM.Internal.MapXml.InstructionList code;
1195
internal ReplacedMethodWrapper(TypeWrapper tw, string name, string sig, IKVM.Internal.MapXml.InstructionList code)
1196
: base(tw, name, sig, null, null, null, Modifiers.Public, MemberFlags.None)
1201
internal ReplacedMethodWrapper(ClassFile.ConstantPoolItemMI cpi, IKVM.Internal.MapXml.InstructionList code)
1202
: base(cpi.GetClassType(), cpi.Name, cpi.Signature, null, cpi.GetRetType(), cpi.GetArgTypes(), Modifiers.Public, MemberFlags.None)
1207
protected override void DoLinkMethod()
1211
private void DoEmit(CodeEmitter ilgen)
1213
IKVM.Internal.MapXml.CodeGenContext context = new IKVM.Internal.MapXml.CodeGenContext(this.DeclaringType.GetClassLoader());
1214
// we don't want the line numbers from map.xml, so we have our own emit loop
1215
for (int i = 0; i < code.invoke.Length; i++)
1217
code.invoke[i].Generate(context, ilgen);
1221
internal override void EmitCall(CodeEmitter ilgen)
1226
internal override void EmitCallvirt(CodeEmitter ilgen)
1231
internal override void EmitNewobj(CodeEmitter ilgen)
1237
internal override MethodWrapper[] GetReplacedMethodsFor(MethodWrapper mw)
1239
IKVM.Internal.MapXml.ReplaceMethodCall[] replacedMethods = ((CompilerClassLoader)GetClassLoader()).GetReplacedMethodsFor(mw);
1240
MethodWrapper[] baseReplacedMethodWrappers = base.GetReplacedMethodsFor(mw);
1241
if (replacedMethods != null || baseReplacedMethodWrappers != null || this.replacedMethods != null)
1243
List<MethodWrapper> list = new List<MethodWrapper>();
1244
if (replacedMethods != null)
1246
for (int i = 0; i < replacedMethods.Length; i++)
1248
list.Add(new ReplacedMethodWrapper(GetClassLoader().LoadClassByDottedName(replacedMethods[i].Class), replacedMethods[i].Name, replacedMethods[i].Sig, replacedMethods[i].code));
1251
if (baseReplacedMethodWrappers != null)
1253
list.AddRange(baseReplacedMethodWrappers);
1255
if (this.replacedMethods != null)
1257
list.AddRange(this.replacedMethods);
1259
return list.ToArray();
1264
internal override bool IsFastClassLiteralSafe
1266
get { return true; }
1269
internal MethodWrapper ReplaceMethodWrapper(MethodWrapper mw)
1271
if (replacedMethods != null)
1273
foreach (MethodWrapper r in replacedMethods)
1275
if (mw.DeclaringType == r.DeclaringType
1276
&& mw.Name == r.Name
1277
&& mw.Signature == r.Signature)
1286
internal override MethodBase GetBaseSerializationConstructor()
1288
if (workaroundBaseClass != null)
1290
return workaroundBaseClass.GetSerializationConstructor();
1294
return base.GetBaseSerializationConstructor();