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 TypeSpec[] stack_types;
92 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
94 this.member_context = rc;
97 this.return_type = return_type;
100 ig.__CleverExceptionBlockAssistance ();
106 internal AsyncTaskStorey AsyncTaskStorey {
108 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
112 public BuiltinTypes BuiltinTypes {
114 return MemberContext.Module.Compiler.BuiltinTypes;
118 public TypeSpec CurrentType {
119 get { return member_context.CurrentType; }
122 public TypeParameter[] CurrentTypeParameters {
123 get { return member_context.CurrentTypeParameters; }
126 public MemberCore CurrentTypeDefinition {
127 get { return member_context.CurrentMemberDefinition; }
130 public bool IsStatic {
131 get { return member_context.IsStatic; }
134 public bool IsAnonymousStoreyMutateRequired {
136 return CurrentAnonymousMethod != null &&
137 CurrentAnonymousMethod.Storey != null &&
138 CurrentAnonymousMethod.Storey.Mutator != null;
142 public IMemberContext MemberContext {
144 return member_context;
148 public ModuleContainer Module {
150 return member_context.Module;
154 // Has to be used for specific emitter errors only any
155 // possible resolver errors have to be reported during Resolve
156 public Report Report {
158 return member_context.Module.Compiler.Report;
162 public TypeSpec ReturnType {
168 public int StackHeight {
171 return ig.__StackHeight;
173 throw new NotImplementedException ();
179 // Enabled when tracking stack types during emit phase
181 bool TrackStackTypes {
183 return (flags & Options.AsyncBody) != 0;
190 /// This is called immediately before emitting an IL opcode to tell the symbol
191 /// writer to which source line this opcode belongs.
193 public void Mark (Location loc)
195 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
198 SymbolWriter.MarkSequencePoint (ig, loc);
201 public void DefineLocalVariable (string name, LocalBuilder builder)
203 SymbolWriter.DefineLocalVariable (name, builder);
206 public void BeginCatchBlock (TypeSpec type)
208 ig.BeginCatchBlock (type.GetMetaInfo ());
211 public void BeginExceptionBlock ()
213 ig.BeginExceptionBlock ();
216 public void BeginFinallyBlock ()
218 ig.BeginFinallyBlock ();
221 public void BeginScope ()
223 SymbolWriter.OpenScope(ig);
226 public void EndExceptionBlock ()
228 ig.EndExceptionBlock ();
231 public void EndScope ()
233 SymbolWriter.CloseScope(ig);
237 // Creates a nested container in this context for all dynamic compiler generated stuff
239 internal DynamicSiteClass CreateDynamicSite ()
241 if (dynamic_site_container == null) {
242 var mc = member_context.CurrentMemberDefinition as MemberBase;
243 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
245 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
246 dynamic_site_container.CreateType ();
247 dynamic_site_container.DefineType ();
248 dynamic_site_container.ResolveTypeParameters ();
249 dynamic_site_container.Define ();
251 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
252 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
253 CurrentType.MemberCache.AddMember (inflated);
256 return dynamic_site_container;
259 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
261 if (IsAnonymousStoreyMutateRequired)
262 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
264 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
267 public Label DefineLabel ()
269 return ig.DefineLabel ();
273 // Creates temporary field in current async storey
275 public FieldExpr GetTemporaryField (TypeSpec type)
277 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
278 var fexpr = new FieldExpr (f, Location.Null);
279 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
283 public void MarkLabel (Label label)
285 ig.MarkLabel (label);
288 public void Emit (OpCode opcode)
292 if (TrackStackTypes) {
293 switch (opcode.StackBehaviourPush) {
294 case StackBehaviour.Push0:
297 case StackBehaviour.Pushi:
298 SetStackType (Module.Compiler.BuiltinTypes.Int);
300 case StackBehaviour.Pushi8:
301 SetStackType (Module.Compiler.BuiltinTypes.Long);
303 case StackBehaviour.Pushr4:
304 SetStackType (Module.Compiler.BuiltinTypes.Float);
306 case StackBehaviour.Pushr8:
307 SetStackType (Module.Compiler.BuiltinTypes.Double);
309 case StackBehaviour.Push1:
310 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
312 } else if (opcode.StackBehaviourPop == StackBehaviour.Pop1_pop1) {
315 throw new NotImplementedException (opcode.Name);
318 case StackBehaviour.Push1_push1:
319 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
320 SetStackType (stack_types[StackHeight - 2]);
322 throw new NotImplementedException (opcode.Name);
326 throw new NotImplementedException (opcode.Name);
331 public void Emit (OpCode opcode, LocalBuilder local, TypeSpec type)
333 ig.Emit (opcode, local);
335 if (TrackStackTypes) {
336 if (opcode.StackBehaviourPush == StackBehaviour.Push0) {
338 } else if (opcode.StackBehaviourPush == StackBehaviour.Push1) {
340 } else if (opcode.StackBehaviourPush == StackBehaviour.Pushi) {
341 SetStackType (ReferenceContainer.MakeType (Module, type));
343 throw new NotImplementedException (opcode.Name);
348 public void Emit (OpCode opcode, string arg)
350 ig.Emit (opcode, arg);
352 if (TrackStackTypes) {
353 SetStackType (Module.Compiler.BuiltinTypes.String);
357 public void Emit (OpCode opcode, double arg)
359 ig.Emit (opcode, arg);
361 if (TrackStackTypes) {
362 SetStackType (Module.Compiler.BuiltinTypes.Double);
366 public void Emit (OpCode opcode, float arg)
368 ig.Emit (opcode, arg);
370 if (TrackStackTypes) {
371 SetStackType (Module.Compiler.BuiltinTypes.Float);
375 public void Emit (OpCode opcode, Label label)
377 ig.Emit (opcode, label);
380 public void Emit (OpCode opcode, Label[] labels)
382 ig.Emit (opcode, labels);
385 public void Emit (OpCode opcode, TypeSpec type)
387 if (IsAnonymousStoreyMutateRequired)
388 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
390 ig.Emit (opcode, type.GetMetaInfo ());
392 if (TrackStackTypes) {
393 switch (opcode.StackBehaviourPush) {
394 case StackBehaviour.Push0:
397 case StackBehaviour.Pushi:
398 SetStackType (ReferenceContainer.MakeType (Module, type));
400 case StackBehaviour.Push1:
404 if (opcode == OpCodes.Box) {
405 SetStackType (Module.Compiler.BuiltinTypes.Object);
406 } else if (opcode == OpCodes.Castclass) {
409 throw new NotImplementedException (opcode.Name);
416 public void Emit (OpCode opcode, FieldSpec field)
418 if (IsAnonymousStoreyMutateRequired)
419 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
421 ig.Emit (opcode, field.GetMetaInfo ());
423 if (TrackStackTypes) {
424 switch (opcode.StackBehaviourPush) {
425 case StackBehaviour.Push0:
428 case StackBehaviour.Push1:
429 SetStackType (field.MemberType);
431 case StackBehaviour.Pushi:
432 SetStackType (ReferenceContainer.MakeType (Module, field.MemberType));
435 throw new NotImplementedException ();
440 public void Emit (OpCode opcode, MethodSpec method)
442 if (IsAnonymousStoreyMutateRequired)
443 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
445 if (method.IsConstructor)
446 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
448 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
450 if (TrackStackTypes) {
452 // Don't bother with ldftn/Ldvirtftn they can never appear on open stack
454 if (method.IsConstructor) {
455 if (opcode == OpCodes.Newobj)
456 SetStackType (method.DeclaringType);
458 if (method.ReturnType.Kind != MemberKind.Void) {
459 SetStackType (method.ReturnType);
465 // TODO: REMOVE breaks mutator
466 public void Emit (OpCode opcode, MethodInfo method)
468 ig.Emit (opcode, method);
471 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
473 // TODO MemberCache: This should mutate too
474 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
477 public void EmitArrayNew (ArrayContainer ac)
480 var type = IsAnonymousStoreyMutateRequired ?
481 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
484 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
486 if (IsAnonymousStoreyMutateRequired)
487 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
489 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
492 if (TrackStackTypes) {
497 public void EmitArrayAddress (ArrayContainer ac)
500 if (IsAnonymousStoreyMutateRequired)
501 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
503 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
505 if (TrackStackTypes) {
506 SetStackType (ReferenceContainer.MakeType (Module, ac.Element));
509 var type = IsAnonymousStoreyMutateRequired ?
510 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
513 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
515 if (TrackStackTypes) {
516 SetStackType (ReferenceContainer.MakeType (Module, type));
522 // Emits the right opcode to load from an array
524 public void EmitArrayLoad (ArrayContainer ac)
527 if (IsAnonymousStoreyMutateRequired)
528 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
530 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
532 if (TrackStackTypes) {
533 SetStackType (ac.Element);
540 var type = ac.Element;
541 if (type.Kind == MemberKind.Enum)
542 type = EnumSpec.GetUnderlyingType (type);
544 switch (type.BuiltinType) {
545 case BuiltinTypeSpec.Type.Byte:
546 case BuiltinTypeSpec.Type.Bool:
547 ig.Emit (OpCodes.Ldelem_U1);
549 case BuiltinTypeSpec.Type.SByte:
550 ig.Emit (OpCodes.Ldelem_I1);
552 case BuiltinTypeSpec.Type.Short:
553 ig.Emit (OpCodes.Ldelem_I2);
555 case BuiltinTypeSpec.Type.UShort:
556 case BuiltinTypeSpec.Type.Char:
557 ig.Emit (OpCodes.Ldelem_U2);
559 case BuiltinTypeSpec.Type.Int:
560 ig.Emit (OpCodes.Ldelem_I4);
562 case BuiltinTypeSpec.Type.UInt:
563 ig.Emit (OpCodes.Ldelem_U4);
565 case BuiltinTypeSpec.Type.ULong:
566 case BuiltinTypeSpec.Type.Long:
567 ig.Emit (OpCodes.Ldelem_I8);
569 case BuiltinTypeSpec.Type.Float:
570 ig.Emit (OpCodes.Ldelem_R4);
572 case BuiltinTypeSpec.Type.Double:
573 ig.Emit (OpCodes.Ldelem_R8);
575 case BuiltinTypeSpec.Type.IntPtr:
576 ig.Emit (OpCodes.Ldelem_I);
580 case MemberKind.Struct:
581 if (IsAnonymousStoreyMutateRequired)
582 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
584 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
585 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
587 case MemberKind.TypeParameter:
588 if (IsAnonymousStoreyMutateRequired)
589 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
591 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
593 case MemberKind.PointerType:
594 ig.Emit (OpCodes.Ldelem_I);
597 ig.Emit (OpCodes.Ldelem_Ref);
603 if (TrackStackTypes) {
609 // Emits the right opcode to store to an array
611 public void EmitArrayStore (ArrayContainer ac)
614 if (IsAnonymousStoreyMutateRequired)
615 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
617 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
621 var type = ac.Element;
623 if (type.Kind == MemberKind.Enum)
624 type = EnumSpec.GetUnderlyingType (type);
626 switch (type.BuiltinType) {
627 case BuiltinTypeSpec.Type.Byte:
628 case BuiltinTypeSpec.Type.SByte:
629 case BuiltinTypeSpec.Type.Bool:
630 Emit (OpCodes.Stelem_I1);
632 case BuiltinTypeSpec.Type.Short:
633 case BuiltinTypeSpec.Type.UShort:
634 case BuiltinTypeSpec.Type.Char:
635 Emit (OpCodes.Stelem_I2);
637 case BuiltinTypeSpec.Type.Int:
638 case BuiltinTypeSpec.Type.UInt:
639 Emit (OpCodes.Stelem_I4);
641 case BuiltinTypeSpec.Type.Long:
642 case BuiltinTypeSpec.Type.ULong:
643 Emit (OpCodes.Stelem_I8);
645 case BuiltinTypeSpec.Type.Float:
646 Emit (OpCodes.Stelem_R4);
648 case BuiltinTypeSpec.Type.Double:
649 Emit (OpCodes.Stelem_R8);
654 case MemberKind.Struct:
655 Emit (OpCodes.Stobj, type);
657 case MemberKind.TypeParameter:
658 Emit (OpCodes.Stelem, type);
660 case MemberKind.PointerType:
661 Emit (OpCodes.Stelem_I);
664 Emit (OpCodes.Stelem_Ref);
669 public void EmitInt (int i)
673 if (TrackStackTypes) {
674 SetStackType (Module.Compiler.BuiltinTypes.Int);
678 void EmitIntConstant (int i)
682 ig.Emit (OpCodes.Ldc_I4_M1);
686 ig.Emit (OpCodes.Ldc_I4_0);
690 ig.Emit (OpCodes.Ldc_I4_1);
694 ig.Emit (OpCodes.Ldc_I4_2);
698 ig.Emit (OpCodes.Ldc_I4_3);
702 ig.Emit (OpCodes.Ldc_I4_4);
706 ig.Emit (OpCodes.Ldc_I4_5);
710 ig.Emit (OpCodes.Ldc_I4_6);
714 ig.Emit (OpCodes.Ldc_I4_7);
718 ig.Emit (OpCodes.Ldc_I4_8);
722 if (i >= -128 && i <= 127) {
723 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
725 ig.Emit (OpCodes.Ldc_I4, i);
730 public void EmitLong (long l)
732 if (l >= int.MinValue && l <= int.MaxValue) {
733 EmitIntConstant (unchecked ((int) l));
734 ig.Emit (OpCodes.Conv_I8);
735 } else if (l >= 0 && l <= uint.MaxValue) {
736 EmitIntConstant (unchecked ((int) l));
737 ig.Emit (OpCodes.Conv_U8);
739 ig.Emit (OpCodes.Ldc_I8, l);
742 if (TrackStackTypes) {
743 SetStackType (Module.Compiler.BuiltinTypes.Long);
748 // Load the object from the pointer.
750 public void EmitLoadFromPtr (TypeSpec type)
752 if (type.Kind == MemberKind.Enum)
753 type = EnumSpec.GetUnderlyingType (type);
755 switch (type.BuiltinType) {
756 case BuiltinTypeSpec.Type.Int:
757 ig.Emit (OpCodes.Ldind_I4);
759 case BuiltinTypeSpec.Type.UInt:
760 ig.Emit (OpCodes.Ldind_U4);
762 case BuiltinTypeSpec.Type.Short:
763 ig.Emit (OpCodes.Ldind_I2);
765 case BuiltinTypeSpec.Type.UShort:
766 case BuiltinTypeSpec.Type.Char:
767 ig.Emit (OpCodes.Ldind_U2);
769 case BuiltinTypeSpec.Type.Byte:
770 ig.Emit (OpCodes.Ldind_U1);
772 case BuiltinTypeSpec.Type.SByte:
773 case BuiltinTypeSpec.Type.Bool:
774 ig.Emit (OpCodes.Ldind_I1);
776 case BuiltinTypeSpec.Type.ULong:
777 case BuiltinTypeSpec.Type.Long:
778 ig.Emit (OpCodes.Ldind_I8);
780 case BuiltinTypeSpec.Type.Float:
781 ig.Emit (OpCodes.Ldind_R4);
783 case BuiltinTypeSpec.Type.Double:
784 ig.Emit (OpCodes.Ldind_R8);
786 case BuiltinTypeSpec.Type.IntPtr:
787 ig.Emit (OpCodes.Ldind_I);
791 case MemberKind.Struct:
792 case MemberKind.TypeParameter:
793 if (IsAnonymousStoreyMutateRequired)
794 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
796 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
798 case MemberKind.PointerType:
799 ig.Emit (OpCodes.Ldind_I);
802 ig.Emit (OpCodes.Ldind_Ref);
808 if (TrackStackTypes) {
809 // TODO: test for async when `this' can be used inside structs
814 public void EmitNull ()
816 ig.Emit (OpCodes.Ldnull);
818 if (TrackStackTypes) {
819 SetStackType (Module.Compiler.BuiltinTypes.Object);
823 public void EmitArgumentAddress (int pos)
828 if (pos > byte.MaxValue)
829 ig.Emit (OpCodes.Ldarga, pos);
831 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
833 if (TrackStackTypes) {
835 // Should never be reached, all parameters are hoisted into class
837 throw new NotImplementedException ();
841 public void EmitArgumentLoad (int pos)
847 case 0: ig.Emit (OpCodes.Ldarg_0); break;
848 case 1: ig.Emit (OpCodes.Ldarg_1); break;
849 case 2: ig.Emit (OpCodes.Ldarg_2); break;
850 case 3: ig.Emit (OpCodes.Ldarg_3); break;
852 if (pos > byte.MaxValue)
853 ig.Emit (OpCodes.Ldarg, pos);
855 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
859 if (TrackStackTypes) {
861 // Should never be reached, all parameters are hoisted into class
863 throw new NotImplementedException ();
867 public void EmitArgumentStore (int pos)
872 if (pos > byte.MaxValue)
873 ig.Emit (OpCodes.Starg, pos);
875 ig.Emit (OpCodes.Starg_S, (byte) pos);
879 // The stack contains the pointer and the value of type `type'
881 public void EmitStoreFromPtr (TypeSpec type)
884 type = EnumSpec.GetUnderlyingType (type);
886 switch (type.BuiltinType) {
887 case BuiltinTypeSpec.Type.Int:
888 case BuiltinTypeSpec.Type.UInt:
889 ig.Emit (OpCodes.Stind_I4);
891 case BuiltinTypeSpec.Type.Long:
892 case BuiltinTypeSpec.Type.ULong:
893 ig.Emit (OpCodes.Stind_I8);
895 case BuiltinTypeSpec.Type.Char:
896 case BuiltinTypeSpec.Type.Short:
897 case BuiltinTypeSpec.Type.UShort:
898 ig.Emit (OpCodes.Stind_I2);
900 case BuiltinTypeSpec.Type.Float:
901 ig.Emit (OpCodes.Stind_R4);
903 case BuiltinTypeSpec.Type.Double:
904 ig.Emit (OpCodes.Stind_R8);
906 case BuiltinTypeSpec.Type.Byte:
907 case BuiltinTypeSpec.Type.SByte:
908 case BuiltinTypeSpec.Type.Bool:
909 ig.Emit (OpCodes.Stind_I1);
911 case BuiltinTypeSpec.Type.IntPtr:
912 ig.Emit (OpCodes.Stind_I);
917 case MemberKind.Struct:
918 case MemberKind.TypeParameter:
919 if (IsAnonymousStoreyMutateRequired)
920 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
922 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
925 ig.Emit (OpCodes.Stind_Ref);
930 public void EmitThis ()
932 ig.Emit (OpCodes.Ldarg_0);
934 if (TrackStackTypes) {
936 // Using CurrentTypeOnStack as a placeholder for CurrentType to allow
937 // optimizations based on `this' presence
939 SetStackType (InternalType.CurrentTypeOnStack);
944 // Returns actual stack types when stack types tracing is enabled
946 public TypeSpec[] GetStackTypes ()
948 TypeSpec[] types = new TypeSpec[StackHeight];
949 Array.Copy (stack_types, types, types.Length);
954 /// Returns a temporary storage for a variable of type t as
955 /// a local variable in the current body.
957 public LocalBuilder GetTemporaryLocal (TypeSpec t)
959 if (temporary_storage != null) {
961 if (temporary_storage.TryGetValue (t, out o)) {
962 if (o is Stack<LocalBuilder>) {
963 var s = (Stack<LocalBuilder>) o;
964 o = s.Count == 0 ? null : s.Pop ();
966 temporary_storage.Remove (t);
970 return (LocalBuilder) o;
972 return DeclareLocal (t, false);
975 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
977 if (temporary_storage == null) {
978 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
979 temporary_storage.Add (t, b);
984 if (!temporary_storage.TryGetValue (t, out o)) {
985 temporary_storage.Add (t, b);
988 var s = o as Stack<LocalBuilder>;
990 s = new Stack<LocalBuilder> ();
991 s.Push ((LocalBuilder)o);
992 temporary_storage [t] = s;
997 void SetStackType (TypeSpec type)
1000 throw new ArgumentNullException ("type");
1002 if (stack_types == null) {
1003 stack_types = new TypeSpec[8];
1004 } else if (StackHeight > stack_types.Length) {
1005 Array.Resize (ref stack_types, stack_types.Length * 2);
1008 stack_types[StackHeight - 1] = type;
1012 /// ReturnValue creates on demand the LocalBuilder for the
1013 /// return value from the function. By default this is not
1014 /// used. This is only required when returns are found inside
1015 /// Try or Catch statements.
1017 /// This method is typically invoked from the Emit phase, so
1018 /// we allow the creation of a return label if it was not
1019 /// requested during the resolution phase. Could be cleaned
1020 /// up, but it would replicate a lot of logic in the Emit phase
1021 /// of the code that uses it.
1023 public LocalBuilder TemporaryReturn ()
1025 if (return_value == null){
1026 return_value = DeclareLocal (return_type, false);
1027 if (!HasReturnLabel){
1028 ReturnLabel = DefineLabel ();
1029 HasReturnLabel = true;
1033 return return_value;