Implement mono_gc_alloc_fixed on Boehm to be uncollectable. This matches SGen behavio...
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Rewrite.AstVisitors / CompileVisitor.cs
1 //
2 // CompileVisitor.cs
3 //
4 // Authors:
5 //      Chris Bacon (chrisbacon76@gmail.com)
6 //
7 // Copyright (C) 2010 Chris Bacon
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Text;
33 using Mono.Cecil.Cil;
34 using Mono.CodeContracts.Rewrite.Ast;
35
36 namespace Mono.CodeContracts.Rewrite.AstVisitors {
37         class CompileVisitor : ExprVisitor {
38
39                 public CompileVisitor (ILProcessor il, Dictionary<Expr, Instruction> instructionLookup)
40                         : this (il, instructionLookup, il.Append)
41                 {
42                 }
43
44                 public CompileVisitor (ILProcessor il, Dictionary<Expr, Instruction> instructionLookup, Action<Instruction> fnEmit)
45                 {
46                         this.il = il;
47                         this.instructionLookup = instructionLookup;
48                         this.fnEmit = fnEmit;
49                 }
50
51                 private ILProcessor il;
52                 private Dictionary<Expr, Instruction> instructionLookup;
53                 private Action<Instruction> fnEmit;
54
55                 private void Emit (Expr originalExpr, Instruction inst)
56                 {
57                         Instruction originalInst;
58                         if (this.instructionLookup != null) {
59                                 // TODO: Doesn't handle inherited contracts - need to check what to do in this case.
60                                 //if (this.instructionLookup.TryGetValue (originalExpr, out originalInst)) {
61                                 //      inst.SequencePoint = originalInst.SequencePoint;
62                                 //}
63                         }
64                         this.fnEmit (inst);
65                 }
66
67                 private void Emit (Expr originalExpr, Func<Instruction> fnCreateInstruction)
68                 {
69                         Instruction inst = fnCreateInstruction();
70                         this.Emit (originalExpr, inst);
71                 }
72
73                 private void Emit (Expr originalExpr, Func<IEnumerable<Instruction>> fnCreateInstruction)
74                 {
75                         throw new NotImplementedException ();
76                 }
77
78                 protected override Expr VisitNop (ExprNop e)
79                 {
80                         var instNop = this.il.Create (OpCodes.Nop);
81                         this.Emit (e, instNop);
82                         return e;
83                 }
84
85                 protected override Expr VisitLoadArg (ExprLoadArg e)
86                 {
87                         this.Emit (e, () => {
88                                 int index = e.Index;
89                                 switch (index) {
90                                 case 0:
91                                         return this.il.Create (OpCodes.Ldarg_0);
92                                 case 1:
93                                         return this.il.Create (OpCodes.Ldarg_1);
94                                 case 2:
95                                         return this.il.Create (OpCodes.Ldarg_2);
96                                 case 3:
97                                         return this.il.Create (OpCodes.Ldarg_3);
98                                 default:
99                                         if (e.Index <= 255) {
100                                                 return this.il.Create (OpCodes.Ldarg_S, (byte) index);
101                                         } else {
102                                                 return this.il.Create (OpCodes.Ldarg, index);
103                                         }
104                                 }
105                         });
106                         
107                         return e;
108                 }
109
110                 protected override Expr VisitLoadConstant (ExprLoadConstant e)
111                 {
112                         this.Emit (e, () => {
113                                 object v = e.Value;
114                                 if (v == null) {
115                                         return this.il.Create (OpCodes.Ldnull);
116                                 }
117                                 Type vType = v.GetType ();
118                                 TypeCode vTypeCode = Type.GetTypeCode (vType);
119                                 switch (vTypeCode) {
120                                 case TypeCode.Int32:
121                                         int value = (int) v;
122                                         switch (value) {
123                                         case -1:
124                                                 return this.il.Create (OpCodes.Ldc_I4_M1);
125                                         case 0:
126                                                 return this.il.Create (OpCodes.Ldc_I4_0);
127                                         case 1:
128                                                 return this.il.Create (OpCodes.Ldc_I4_1);
129                                         case 2:
130                                                 return this.il.Create (OpCodes.Ldc_I4_2);
131                                         case 3:
132                                                 return this.il.Create (OpCodes.Ldc_I4_3);
133                                         case 4:
134                                                 return this.il.Create (OpCodes.Ldc_I4_4);
135                                         case 5:
136                                                 return this.il.Create (OpCodes.Ldc_I4_5);
137                                         case 6:
138                                                 return this.il.Create (OpCodes.Ldc_I4_6);
139                                         case 7:
140                                                 return this.il.Create (OpCodes.Ldc_I4_7);
141                                         case 8:
142                                                 return this.il.Create (OpCodes.Ldc_I4_8);
143                                         default:
144                                                 if (value >= -128 && value <= 127) {
145                                                         return this.il.Create (OpCodes.Ldc_I4_S, (sbyte) value);
146                                                 } else {
147                                                         return this.il.Create (OpCodes.Ldc_I4, value);
148                                                 }
149                                         }
150                                 case TypeCode.Single:
151                                         return this.il.Create (OpCodes.Ldc_R4, (float) v);
152                                 case TypeCode.Double:
153                                         return this.il.Create (OpCodes.Ldc_R8, (double) v);
154                                 case TypeCode.String:
155                                         return this.il.Create (OpCodes.Ldstr, (string) v);
156                                 default:
157                                         throw new NotSupportedException ("Cannot handle constant: " + vTypeCode);
158                                 }
159                         });
160
161                         return e;
162                 }
163
164                 private Expr VisitBinary (ExprBinaryOp e, Func<Instruction> fnCreateIl)
165                 {
166                         this.Visit (e.Left);
167                         this.Visit (e.Right);
168                         var inst = fnCreateIl ();
169                         this.Emit (e, inst);
170                         return e;
171                 }
172
173                 protected override Expr VisitCompareLessThan (ExprCompareLessThan e)
174                 {
175                         return this.VisitBinary (e, () => this.il.Create (e.IsSigned ? OpCodes.Clt : OpCodes.Clt_Un));
176                 }
177
178                 protected override Expr VisitCompareGreaterThan (ExprCompareGreaterThan e)
179                 {
180                         return this.VisitBinary (e, () => this.il.Create (e.IsSigned ? OpCodes.Cgt : OpCodes.Cgt_Un));
181                 }
182
183                 protected override Expr VisitCompareEqual (ExprCompareEqual e)
184                 {
185                         return this.VisitBinary (e, () => this.il.Create (OpCodes.Ceq));
186                 }
187
188                 protected override Expr VisitAdd (ExprAdd e)
189                 {
190                         return this.VisitBinary (e, () => {
191                                 if (!e.Overflow) {
192                                         return this.il.Create (OpCodes.Add);
193                                 } else {
194                                         return this.il.Create (e.IsSigned ? OpCodes.Add_Ovf : OpCodes.Add_Ovf_Un);
195                                 }
196                         });
197                 }
198
199                 protected override Expr VisitSub (ExprSub e)
200                 {
201                         return this.VisitBinary (e, () => {
202                                 if (!e.Overflow) {
203                                         return this.il.Create (OpCodes.Sub);
204                                 } else {
205                                         return this.il.Create (e.IsSigned ? OpCodes.Sub_Ovf : OpCodes.Sub_Ovf_Un);
206                                 }
207                         });
208                 }
209
210                 protected override Expr VisitCall (ExprCall e)
211                 {
212                         foreach (var param in e.Parameters) {
213                                 this.Visit (param);
214                         }
215                         var instCall = this.il.Create (OpCodes.Call, e.Method);
216                         this.Emit (e, instCall);
217                         return e;
218                 }
219
220                 protected override Expr VisitReturn (ExprReturn e)
221                 {
222                         var instReturn = this.il.Create (OpCodes.Ret);
223                         this.Emit (e, instReturn);
224                         return e;
225                 }
226
227                 protected override Expr VisitBox (ExprBox e)
228                 {
229                         this.Visit (e.ExprToBox);
230                         var instBox = this.il.Create (OpCodes.Box, e.ReturnType);
231                         this.Emit (e, instBox);
232                         return e;
233                 }
234
235                 protected override Expr VisitConv (ExprConv e)
236                 {
237                         this.Visit (e.ExprToConvert);
238                         Instruction instConv;
239                         switch (e.ConvToType) {
240                         case TypeCode.Int32:
241                                 instConv = this.il.Create (OpCodes.Conv_I4);
242                                 break;
243                         case TypeCode.Int64:
244                                 instConv = this.il.Create (OpCodes.Conv_I8);
245                                 break;
246                         default:
247                                 throw new NotSupportedException ("Cannot conv to: " + e.ConvToType);
248                         }
249                         this.Emit (e, instConv);
250                         return e;
251                 }
252
253         }
254 }