2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004 Novell, Inc.
13 using System.Collections.Generic;
16 using MetaType = IKVM.Reflection.Type;
17 using IKVM.Reflection;
18 using IKVM.Reflection.Emit;
20 using MetaType = System.Type;
21 using System.Reflection;
22 using System.Reflection.Emit;
28 /// An Emit Context is created for each body of code (from methods,
29 /// properties bodies, indexer bodies or constructor bodies)
31 public class EmitContext : BuilderContext
33 // TODO: Has to be private
34 public readonly ILGenerator ig;
37 /// The value that is allowed to be returned or NULL if there is no
40 readonly TypeSpec return_type;
43 /// Keeps track of the Type to LocalBuilder temporary storage created
44 /// to store structures (used to compute the address of the structure
45 /// value on structure method invocations)
47 Dictionary<TypeSpec, object> temporary_storage;
50 /// The location where we store the return value.
52 public LocalBuilder return_value;
55 /// The location where return has to jump to return the
58 public Label ReturnLabel;
61 /// If we already defined the ReturnLabel
63 public bool HasReturnLabel;
66 /// Current loop begin and end labels.
68 public Label LoopBegin, LoopEnd;
71 /// Default target in a switch statement. Only valid if
74 public Label DefaultTarget;
77 /// If this is non-null, points to the current switch statement
82 /// Whether we are inside an anonymous method.
84 public AnonymousExpression CurrentAnonymousMethod;
86 readonly IMemberContext member_context;
88 DynamicSiteClass dynamic_site_container;
90 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
92 this.member_context = rc;
95 this.return_type = return_type;
98 ig.__CleverExceptionBlockAssistance ();
104 public BuiltinTypes BuiltinTypes {
106 return MemberContext.Module.Compiler.BuiltinTypes;
110 public TypeSpec CurrentType {
111 get { return member_context.CurrentType; }
114 public TypeParameter[] CurrentTypeParameters {
115 get { return member_context.CurrentTypeParameters; }
118 public MemberCore CurrentTypeDefinition {
119 get { return member_context.CurrentMemberDefinition; }
122 public bool IsStatic {
123 get { return member_context.IsStatic; }
126 public bool IsAnonymousStoreyMutateRequired {
128 return CurrentAnonymousMethod != null &&
129 CurrentAnonymousMethod.Storey != null &&
130 CurrentAnonymousMethod.Storey.Mutator != null;
134 public IMemberContext MemberContext {
136 return member_context;
140 public ModuleContainer Module {
142 return member_context.Module;
146 // Has to be used for specific emitter errors only any
147 // possible resolver errors have to be reported during Resolve
148 public Report Report {
150 return member_context.Module.Compiler.Report;
154 public TypeSpec ReturnType {
162 /// This is called immediately before emitting an IL opcode to tell the symbol
163 /// writer to which source line this opcode belongs.
165 public void Mark (Location loc)
167 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
170 SymbolWriter.MarkSequencePoint (ig, loc);
173 public void DefineLocalVariable (string name, LocalBuilder builder)
175 SymbolWriter.DefineLocalVariable (name, builder);
178 public void BeginCatchBlock (TypeSpec type)
180 ig.BeginCatchBlock (type.GetMetaInfo ());
183 public void BeginExceptionBlock ()
185 ig.BeginExceptionBlock ();
188 public void BeginFinallyBlock ()
190 ig.BeginFinallyBlock ();
193 public void BeginScope ()
195 SymbolWriter.OpenScope(ig);
198 public void EndExceptionBlock ()
200 ig.EndExceptionBlock ();
203 public void EndScope ()
205 SymbolWriter.CloseScope(ig);
209 // Creates a nested container in this context for all dynamic compiler generated stuff
211 internal DynamicSiteClass CreateDynamicSite ()
213 if (dynamic_site_container == null) {
214 var mc = member_context.CurrentMemberDefinition as MemberBase;
215 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
217 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
218 dynamic_site_container.CreateType ();
219 dynamic_site_container.DefineType ();
220 dynamic_site_container.ResolveTypeParameters ();
221 dynamic_site_container.Define ();
223 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
224 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
225 CurrentType.MemberCache.AddMember (inflated);
228 return dynamic_site_container;
231 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
233 if (IsAnonymousStoreyMutateRequired)
234 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
236 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
239 public Label DefineLabel ()
241 return ig.DefineLabel ();
244 public void MarkLabel (Label label)
246 ig.MarkLabel (label);
249 public void Emit (OpCode opcode)
254 public void Emit (OpCode opcode, LocalBuilder local)
256 ig.Emit (opcode, local);
259 public void Emit (OpCode opcode, string arg)
261 ig.Emit (opcode, arg);
264 public void Emit (OpCode opcode, double arg)
266 ig.Emit (opcode, arg);
269 public void Emit (OpCode opcode, float arg)
271 ig.Emit (opcode, arg);
274 public void Emit (OpCode opcode, int arg)
276 ig.Emit (opcode, arg);
279 public void Emit (OpCode opcode, byte arg)
281 ig.Emit (opcode, arg);
284 public void Emit (OpCode opcode, Label label)
286 ig.Emit (opcode, label);
289 public void Emit (OpCode opcode, Label[] labels)
291 ig.Emit (opcode, labels);
294 public void Emit (OpCode opcode, TypeSpec type)
296 if (IsAnonymousStoreyMutateRequired)
297 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
299 ig.Emit (opcode, type.GetMetaInfo ());
302 public void Emit (OpCode opcode, FieldSpec field)
304 if (IsAnonymousStoreyMutateRequired)
305 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
307 ig.Emit (opcode, field.GetMetaInfo ());
310 public void Emit (OpCode opcode, MethodSpec method)
312 if (IsAnonymousStoreyMutateRequired)
313 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
315 if (method.IsConstructor)
316 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
318 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
321 // TODO: REMOVE breaks mutator
322 public void Emit (OpCode opcode, MethodInfo method)
324 ig.Emit (opcode, method);
327 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
329 // TODO MemberCache: This should mutate too
330 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
333 public void EmitArrayNew (ArrayContainer ac)
336 Emit (OpCodes.Newarr, ac.Element);
338 if (IsAnonymousStoreyMutateRequired)
339 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
341 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
345 public void EmitArrayAddress (ArrayContainer ac)
348 if (IsAnonymousStoreyMutateRequired)
349 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
351 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
353 Emit (OpCodes.Ldelema, ac.Element);
358 // Emits the right opcode to load from an array
360 public void EmitArrayLoad (ArrayContainer ac)
363 if (IsAnonymousStoreyMutateRequired)
364 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
366 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
370 var type = ac.Element;
371 if (type.Kind == MemberKind.Enum)
372 type = EnumSpec.GetUnderlyingType (type);
374 switch (type.BuiltinType) {
375 case BuiltinTypeSpec.Type.Byte:
376 case BuiltinTypeSpec.Type.Bool:
377 Emit (OpCodes.Ldelem_U1);
379 case BuiltinTypeSpec.Type.SByte:
380 Emit (OpCodes.Ldelem_I1);
382 case BuiltinTypeSpec.Type.Short:
383 Emit (OpCodes.Ldelem_I2);
385 case BuiltinTypeSpec.Type.UShort:
386 case BuiltinTypeSpec.Type.Char:
387 Emit (OpCodes.Ldelem_U2);
389 case BuiltinTypeSpec.Type.Int:
390 Emit (OpCodes.Ldelem_I4);
392 case BuiltinTypeSpec.Type.UInt:
393 Emit (OpCodes.Ldelem_U4);
395 case BuiltinTypeSpec.Type.ULong:
396 case BuiltinTypeSpec.Type.Long:
397 Emit (OpCodes.Ldelem_I8);
399 case BuiltinTypeSpec.Type.Float:
400 Emit (OpCodes.Ldelem_R4);
402 case BuiltinTypeSpec.Type.Double:
403 Emit (OpCodes.Ldelem_R8);
405 case BuiltinTypeSpec.Type.IntPtr:
406 Emit (OpCodes.Ldelem_I);
411 case MemberKind.Struct:
412 Emit (OpCodes.Ldelema, type);
413 Emit (OpCodes.Ldobj, type);
415 case MemberKind.TypeParameter:
416 Emit (OpCodes.Ldelem, type);
418 case MemberKind.PointerType:
419 Emit (OpCodes.Ldelem_I);
422 Emit (OpCodes.Ldelem_Ref);
428 // Emits the right opcode to store to an array
430 public void EmitArrayStore (ArrayContainer ac)
433 if (IsAnonymousStoreyMutateRequired)
434 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
436 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
440 var type = ac.Element;
442 if (type.Kind == MemberKind.Enum)
443 type = EnumSpec.GetUnderlyingType (type);
445 switch (type.BuiltinType) {
446 case BuiltinTypeSpec.Type.Byte:
447 case BuiltinTypeSpec.Type.SByte:
448 case BuiltinTypeSpec.Type.Bool:
449 Emit (OpCodes.Stelem_I1);
451 case BuiltinTypeSpec.Type.Short:
452 case BuiltinTypeSpec.Type.UShort:
453 case BuiltinTypeSpec.Type.Char:
454 Emit (OpCodes.Stelem_I2);
456 case BuiltinTypeSpec.Type.Int:
457 case BuiltinTypeSpec.Type.UInt:
458 Emit (OpCodes.Stelem_I4);
460 case BuiltinTypeSpec.Type.Long:
461 case BuiltinTypeSpec.Type.ULong:
462 Emit (OpCodes.Stelem_I8);
464 case BuiltinTypeSpec.Type.Float:
465 Emit (OpCodes.Stelem_R4);
467 case BuiltinTypeSpec.Type.Double:
468 Emit (OpCodes.Stelem_R8);
473 case MemberKind.Struct:
474 Emit (OpCodes.Stobj, type);
476 case MemberKind.TypeParameter:
477 Emit (OpCodes.Stelem, type);
479 case MemberKind.PointerType:
480 Emit (OpCodes.Stelem_I);
483 Emit (OpCodes.Stelem_Ref);
488 public void EmitInt (int i)
492 ig.Emit (OpCodes.Ldc_I4_M1);
496 ig.Emit (OpCodes.Ldc_I4_0);
500 ig.Emit (OpCodes.Ldc_I4_1);
504 ig.Emit (OpCodes.Ldc_I4_2);
508 ig.Emit (OpCodes.Ldc_I4_3);
512 ig.Emit (OpCodes.Ldc_I4_4);
516 ig.Emit (OpCodes.Ldc_I4_5);
520 ig.Emit (OpCodes.Ldc_I4_6);
524 ig.Emit (OpCodes.Ldc_I4_7);
528 ig.Emit (OpCodes.Ldc_I4_8);
532 if (i >= -128 && i <= 127) {
533 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
535 ig.Emit (OpCodes.Ldc_I4, i);
540 public void EmitLong (long l)
542 if (l >= int.MinValue && l <= int.MaxValue) {
543 EmitInt (unchecked ((int) l));
544 ig.Emit (OpCodes.Conv_I8);
548 if (l >= 0 && l <= uint.MaxValue) {
549 EmitInt (unchecked ((int) l));
550 ig.Emit (OpCodes.Conv_U8);
554 ig.Emit (OpCodes.Ldc_I8, l);
558 // Load the object from the pointer.
560 public void EmitLoadFromPtr (TypeSpec type)
562 if (type.Kind == MemberKind.Enum)
563 type = EnumSpec.GetUnderlyingType (type);
565 switch (type.BuiltinType) {
566 case BuiltinTypeSpec.Type.Int:
567 ig.Emit (OpCodes.Ldind_I4);
569 case BuiltinTypeSpec.Type.UInt:
570 ig.Emit (OpCodes.Ldind_U4);
572 case BuiltinTypeSpec.Type.Short:
573 ig.Emit (OpCodes.Ldind_I2);
575 case BuiltinTypeSpec.Type.UShort:
576 case BuiltinTypeSpec.Type.Char:
577 ig.Emit (OpCodes.Ldind_U2);
579 case BuiltinTypeSpec.Type.Byte:
580 ig.Emit (OpCodes.Ldind_U1);
582 case BuiltinTypeSpec.Type.SByte:
583 case BuiltinTypeSpec.Type.Bool:
584 ig.Emit (OpCodes.Ldind_I1);
586 case BuiltinTypeSpec.Type.ULong:
587 case BuiltinTypeSpec.Type.Long:
588 ig.Emit (OpCodes.Ldind_I8);
590 case BuiltinTypeSpec.Type.Float:
591 ig.Emit (OpCodes.Ldind_R4);
593 case BuiltinTypeSpec.Type.Double:
594 ig.Emit (OpCodes.Ldind_R8);
596 case BuiltinTypeSpec.Type.IntPtr:
597 ig.Emit (OpCodes.Ldind_I);
602 case MemberKind.Struct:
603 case MemberKind.TypeParameter:
604 Emit (OpCodes.Ldobj, type);
606 case MemberKind.PointerType:
607 ig.Emit (OpCodes.Ldind_I);
610 ig.Emit (OpCodes.Ldind_Ref);
616 // The stack contains the pointer and the value of type `type'
618 public void EmitStoreFromPtr (TypeSpec type)
621 type = EnumSpec.GetUnderlyingType (type);
623 switch (type.BuiltinType) {
624 case BuiltinTypeSpec.Type.Int:
625 case BuiltinTypeSpec.Type.UInt:
626 ig.Emit (OpCodes.Stind_I4);
628 case BuiltinTypeSpec.Type.Long:
629 case BuiltinTypeSpec.Type.ULong:
630 ig.Emit (OpCodes.Stind_I8);
632 case BuiltinTypeSpec.Type.Char:
633 case BuiltinTypeSpec.Type.Short:
634 case BuiltinTypeSpec.Type.UShort:
635 ig.Emit (OpCodes.Stind_I2);
637 case BuiltinTypeSpec.Type.Float:
638 ig.Emit (OpCodes.Stind_R4);
640 case BuiltinTypeSpec.Type.Double:
641 ig.Emit (OpCodes.Stind_R8);
643 case BuiltinTypeSpec.Type.Byte:
644 case BuiltinTypeSpec.Type.SByte:
645 case BuiltinTypeSpec.Type.Bool:
646 ig.Emit (OpCodes.Stind_I1);
648 case BuiltinTypeSpec.Type.IntPtr:
649 ig.Emit (OpCodes.Stind_I);
653 if (type.IsStruct || TypeManager.IsGenericParameter (type))
654 Emit (OpCodes.Stobj, type);
656 ig.Emit (OpCodes.Stind_Ref);
660 /// Returns a temporary storage for a variable of type t as
661 /// a local variable in the current body.
663 public LocalBuilder GetTemporaryLocal (TypeSpec t)
665 if (temporary_storage != null) {
667 if (temporary_storage.TryGetValue (t, out o)) {
668 if (o is Stack<LocalBuilder>) {
669 var s = (Stack<LocalBuilder>) o;
670 o = s.Count == 0 ? null : s.Pop ();
672 temporary_storage.Remove (t);
676 return (LocalBuilder) o;
678 return DeclareLocal (t, false);
681 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
683 if (temporary_storage == null) {
684 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
685 temporary_storage.Add (t, b);
690 if (!temporary_storage.TryGetValue (t, out o)) {
691 temporary_storage.Add (t, b);
694 var s = o as Stack<LocalBuilder>;
696 s = new Stack<LocalBuilder> ();
697 s.Push ((LocalBuilder)o);
698 temporary_storage [t] = s;
704 /// ReturnValue creates on demand the LocalBuilder for the
705 /// return value from the function. By default this is not
706 /// used. This is only required when returns are found inside
707 /// Try or Catch statements.
709 /// This method is typically invoked from the Emit phase, so
710 /// we allow the creation of a return label if it was not
711 /// requested during the resolution phase. Could be cleaned
712 /// up, but it would replicate a lot of logic in the Emit phase
713 /// of the code that uses it.
715 public LocalBuilder TemporaryReturn ()
717 if (return_value == null){
718 return_value = DeclareLocal (return_type, false);
719 if (!HasReturnLabel){
720 ReturnLabel = DefineLabel ();
721 HasReturnLabel = true;