Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / IKVM.Reflection / Emit / FieldBuilder.cs
1 /*
2   Copyright (C) 2008-2012 Jeroen Frijters
3
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.
7
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:
11
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.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Runtime.CompilerServices;
27 using IKVM.Reflection.Metadata;
28 using IKVM.Reflection.Writer;
29
30 namespace IKVM.Reflection.Emit
31 {
32         public sealed class FieldBuilder : FieldInfo
33         {
34                 private readonly TypeBuilder typeBuilder;
35                 private readonly string name;
36                 private readonly int pseudoToken;
37                 private FieldAttributes attribs;
38                 private readonly int nameIndex;
39                 private readonly int signature;
40                 private readonly FieldSignature fieldSig;
41
42                 internal FieldBuilder(TypeBuilder type, string name, Type fieldType, CustomModifiers customModifiers, FieldAttributes attribs)
43                 {
44                         this.typeBuilder = type;
45                         this.name = name;
46                         this.pseudoToken = type.ModuleBuilder.AllocPseudoToken();
47                         this.nameIndex = type.ModuleBuilder.Strings.Add(name);
48                         this.fieldSig = FieldSignature.Create(fieldType, customModifiers);
49                         ByteBuffer sig = new ByteBuffer(5);
50                         fieldSig.WriteSig(this.typeBuilder.ModuleBuilder, sig);
51                         this.signature = this.typeBuilder.ModuleBuilder.Blobs.Add(sig);
52                         this.attribs = attribs;
53                         this.typeBuilder.ModuleBuilder.Field.AddVirtualRecord();
54                 }
55
56                 public void SetConstant(object defaultValue)
57                 {
58                         attribs |= FieldAttributes.HasDefault;
59                         typeBuilder.ModuleBuilder.AddConstant(pseudoToken, defaultValue);
60                 }
61
62                 public override object GetRawConstantValue()
63                 {
64                         if (!typeBuilder.IsCreated())
65                         {
66                                 // the .NET FieldBuilder doesn't support this method
67                                 // (since we dont' have a different FieldInfo object after baking, we will support it once we're baked)
68                                 throw new NotSupportedException();
69                         }
70                         return typeBuilder.Module.Constant.GetRawConstantValue(typeBuilder.Module, GetCurrentToken());
71                 }
72
73                 public void __SetDataAndRVA(byte[] data)
74                 {
75                         SetDataAndRvaImpl(data, typeBuilder.ModuleBuilder.initializedData, 0);
76                 }
77
78                 public void __SetReadOnlyDataAndRVA(byte[] data)
79                 {
80                         SetDataAndRvaImpl(data, typeBuilder.ModuleBuilder.methodBodies, unchecked((int)0x80000000));
81                 }
82
83                 private void SetDataAndRvaImpl(byte[] data, ByteBuffer bb, int readonlyMarker)
84                 {
85                         attribs |= FieldAttributes.HasFieldRVA;
86                         FieldRVATable.Record rec = new FieldRVATable.Record();
87                         bb.Align(8);
88                         rec.RVA = bb.Position + readonlyMarker;
89                         rec.Field = pseudoToken;
90                         typeBuilder.ModuleBuilder.FieldRVA.AddRecord(rec);
91                         bb.Write(data);
92                 }
93
94                 public override void __GetDataFromRVA(byte[] data, int offset, int length)
95                 {
96                         throw new NotImplementedException();
97                 }
98
99                 public override int __FieldRVA
100                 {
101                         get { throw new NotImplementedException(); }
102                 }
103
104                 public override bool __TryGetFieldOffset(out int offset)
105                 {
106                         int pseudoTokenOrIndex = pseudoToken;
107                         if (typeBuilder.ModuleBuilder.IsSaved)
108                         {
109                                 pseudoTokenOrIndex = typeBuilder.ModuleBuilder.ResolvePseudoToken(pseudoToken) & 0xFFFFFF;
110                         }
111                         foreach (int i in this.Module.FieldLayout.Filter(pseudoTokenOrIndex))
112                         {
113                                 offset = this.Module.FieldLayout.records[i].Offset;
114                                 return true;
115                         }
116                         offset = 0;
117                         return false;
118                 }
119
120                 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
121                 {
122                         SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
123                 }
124
125                 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
126                 {
127                         Universe u = this.Module.universe;
128                         if (customBuilder.Constructor.DeclaringType == u.System_Runtime_InteropServices_FieldOffsetAttribute)
129                         {
130                                 customBuilder = customBuilder.DecodeBlob(this.Module.Assembly);
131                                 SetOffset((int)customBuilder.GetConstructorArgument(0));
132                         }
133                         else if (customBuilder.Constructor.DeclaringType == u.System_Runtime_InteropServices_MarshalAsAttribute)
134                         {
135                                 FieldMarshal.SetMarshalAsAttribute(typeBuilder.ModuleBuilder, pseudoToken, customBuilder);
136                                 attribs |= FieldAttributes.HasFieldMarshal;
137                         }
138                         else if (customBuilder.Constructor.DeclaringType == u.System_NonSerializedAttribute)
139                         {
140                                 attribs |= FieldAttributes.NotSerialized;
141                         }
142                         else if (customBuilder.Constructor.DeclaringType == u.System_Runtime_CompilerServices_SpecialNameAttribute)
143                         {
144                                 attribs |= FieldAttributes.SpecialName;
145                         }
146                         else
147                         {
148                                 typeBuilder.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
149                         }
150                 }
151
152                 public void SetOffset(int iOffset)
153                 {
154                         FieldLayoutTable.Record rec = new FieldLayoutTable.Record();
155                         rec.Offset = iOffset;
156                         rec.Field = pseudoToken;
157                         typeBuilder.ModuleBuilder.FieldLayout.AddRecord(rec);
158                 }
159
160                 public override FieldAttributes Attributes
161                 {
162                         get { return attribs; }
163                 }
164
165                 public override Type DeclaringType
166                 {
167                         get { return typeBuilder.IsModulePseudoType ? null : typeBuilder; }
168                 }
169
170                 public override string Name
171                 {
172                         get { return name; }
173                 }
174
175                 public override int MetadataToken
176                 {
177                         get { return pseudoToken; }
178                 }
179
180                 public override Module Module
181                 {
182                         get { return typeBuilder.Module; }
183                 }
184
185                 public FieldToken GetToken()
186                 {
187                         return new FieldToken(pseudoToken);
188                 }
189
190                 internal void WriteFieldRecords(MetadataWriter mw)
191                 {
192                         mw.Write((short)attribs);
193                         mw.WriteStringIndex(nameIndex);
194                         mw.WriteBlobIndex(signature);
195                 }
196
197                 internal void FixupToken(int token)
198                 {
199                         typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
200                 }
201
202                 internal override FieldSignature FieldSignature
203                 {
204                         get { return fieldSig; }
205                 }
206
207                 internal override int ImportTo(ModuleBuilder other)
208                 {
209                         return other.ImportMethodOrField(typeBuilder, name, fieldSig);
210                 }
211
212                 internal override int GetCurrentToken()
213                 {
214                         if (typeBuilder.ModuleBuilder.IsSaved)
215                         {
216                                 return typeBuilder.ModuleBuilder.ResolvePseudoToken(pseudoToken);
217                         }
218                         else
219                         {
220                                 return pseudoToken;
221                         }
222                 }
223
224                 internal override bool IsBaked
225                 {
226                         get { return typeBuilder.IsBaked; }
227                 }
228         }
229 }