public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { if (prepare_for_load) { throw new NotImplementedException(); } source.Emit(ec); Store(ec); if (leave_copy) { Emit(ec); } }
public virtual void Emit(EmitContext ec) { if (!IsByRef) { Expr.Emit(ec); return; } AddressOp mode = AddressOp.Store; if (ArgType == AType.Ref) { mode |= AddressOp.Load; } IMemoryLocation ml = (IMemoryLocation)Expr; ml.AddressOf(ec, mode); }
protected override void DoEmit(EmitContext ec) { Label label_init = ec.DefineLabel(); ec.Emit(OpCodes.Ldarg_0); ec.Emit(OpCodes.Ldflda, host.PC.Spec); ec.EmitInt((int)Iterator.State.Start); ec.EmitInt((int)Iterator.State.Uninitialized); ec.Emit(OpCodes.Call, TypeManager.int_interlocked_compare_exchange); ec.EmitInt((int)Iterator.State.Uninitialized); ec.Emit(OpCodes.Bne_Un_S, label_init); ec.Emit(OpCodes.Ldarg_0); ec.Emit(OpCodes.Ret); ec.MarkLabel(label_init); new_storey.Emit(ec); ec.Emit(OpCodes.Ret); }
protected override void DoEmit(EmitContext ec) { ILGenerator ig = ec.ig; Label label_init = ig.DefineLabel(); ig.Emit(OpCodes.Ldarg_0); ig.Emit(OpCodes.Ldflda, host.PC.FieldBuilder); IntConstant.EmitInt(ig, (int)Iterator.State.Start); IntConstant.EmitInt(ig, (int)Iterator.State.Uninitialized); ig.Emit(OpCodes.Call, TypeManager.int_interlocked_compare_exchange); IntConstant.EmitInt(ig, (int)Iterator.State.Uninitialized); ig.Emit(OpCodes.Bne_Un_S, label_init); ig.Emit(OpCodes.Ldarg_0); ig.Emit(OpCodes.Ret); ig.MarkLabel(label_init); new_storey.Emit(ec); ig.Emit(OpCodes.Ret); }
public override void Emit(EmitContext ec) { if (delegate_instance_expression == null) { ec.ig.Emit(OpCodes.Ldnull); } else { delegate_instance_expression.Emit(ec); } if (!delegate_method.DeclaringType.IsSealed && delegate_method.IsVirtual && !method_group.IsBase) { ec.ig.Emit(OpCodes.Dup); ec.ig.Emit(OpCodes.Ldvirtftn, delegate_method); } else { ec.ig.Emit(OpCodes.Ldftn, delegate_method); } ec.ig.Emit(OpCodes.Newobj, constructor_method); }
// // Called back from Yield // public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { // Store the new current ec.Emit(OpCodes.Ldarg_0); expr.Emit(ec); ec.Emit(OpCodes.Stfld, IteratorHost.CurrentField.Spec); // store resume program-counter ec.Emit(OpCodes.Ldarg_0); ec.EmitInt(resume_pc); ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec); // mark finally blocks as disabled if (unwind_protect && skip_finally != null) { ec.EmitInt(1); ec.Emit(OpCodes.Stloc, skip_finally); } // Return ok ec.Emit(unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok); ec.MarkLabel(resume_point); }
// // Called back from Yield // public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { // Store the new current ec.Emit(OpCodes.Ldarg_0); expr.Emit(ec); ec.Emit(OpCodes.Stfld, IteratorHost.CurrentField.Spec); // // Guard against being disposed meantime // Label disposed = ec.DefineLabel(); ec.Emit(OpCodes.Ldarg_0); ec.Emit(OpCodes.Ldfld, IteratorHost.DisposingField.Spec); ec.Emit(OpCodes.Brtrue_S, disposed); // // store resume program-counter // ec.Emit(OpCodes.Ldarg_0); ec.EmitInt(resume_pc); ec.Emit(OpCodes.Stfld, IteratorHost.PC.Spec); ec.MarkLabel(disposed); // mark finally blocks as disabled if (unwind_protect && skip_finally != null) { ec.EmitInt(1); ec.Emit(OpCodes.Stloc, skip_finally); } // Return ok ec.Emit(unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok); ec.MarkLabel(resume_point); }
// `dup_args' leaves an extra copy of the arguments on the stack // `omit_args' does not leave any arguments at all. // So, basically, you could make one call with `dup_args' set to true, // and then another with `omit_args' set to true, and the two calls // would have the same set of arguments. However, each argument would // only have been evaluated once. public static void EmitCall (EmitContext ec, bool is_base, Expression instance_expr, MethodBase method, Arguments Arguments, Location loc, bool dup_args, bool omit_args) { ILGenerator ig = ec.ig; bool struct_call = false; bool this_call = false; LocalTemporary this_arg = null; Type decl_type = method.DeclaringType; if (IsMethodExcluded (method, loc)) return; bool is_static = method.IsStatic; if (!is_static){ this_call = instance_expr is This; if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type)) struct_call = true; // // If this is ourselves, push "this" // if (!omit_args) { Type t = null; Type iexpr_type = instance_expr.Type; // // Push the instance expression // if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) { // // Special case: calls to a function declared in a // reference-type with a value-type argument need // to have their value boxed. if (TypeManager.IsStruct (decl_type) || TypeManager.IsGenericParameter (iexpr_type)) { // // If the expression implements IMemoryLocation, then // we can optimize and use AddressOf on the // return. // // If not we have to use some temporary storage for // it. if (instance_expr is IMemoryLocation) { ((IMemoryLocation)instance_expr). AddressOf (ec, AddressOp.LoadStore); } else { LocalTemporary temp = new LocalTemporary (iexpr_type); instance_expr.Emit (ec); temp.Store (ec); temp.AddressOf (ec, AddressOp.Load); } // avoid the overhead of doing this all the time. if (dup_args) t = TypeManager.GetReferenceType (iexpr_type); } else { instance_expr.Emit (ec); // FIXME: should use instance_expr is IMemoryLocation + constraint. // to help JIT to produce better code ig.Emit (OpCodes.Box, instance_expr.Type); t = TypeManager.object_type; } } else { instance_expr.Emit (ec); t = instance_expr.Type; } if (dup_args) { ig.Emit (OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { this_arg = new LocalTemporary (t); this_arg.Store (ec); } } } } if (!omit_args && Arguments != null) Arguments.Emit (ec, dup_args, this_arg); OpCode call_op; if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) { call_op = OpCodes.Call; } else { call_op = OpCodes.Callvirt; #if GMCS_SOURCE if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter)) ig.Emit (OpCodes.Constrained, instance_expr.Type); #endif } if ((method.CallingConvention & CallingConventions.VarArgs) != 0) { Type[] varargs_types = GetVarargsTypes (method, Arguments); ig.EmitCall (call_op, (MethodInfo) method, varargs_types); return; } // // If you have: // this.DoFoo (); // and DoFoo is not virtual, you can omit the callvirt, // because you don't need the null checking behavior. // if (method is MethodInfo) ig.Emit (call_op, (MethodInfo) method); else ig.Emit (call_op, (ConstructorInfo) method); }
/// <remarks> /// is_base tells whether we want to force the use of the `call' /// opcode instead of using callvirt. Call is required to call /// a specific method, while callvirt will always use the most /// recent method in the vtable. /// /// is_static tells whether this is an invocation on a static method /// /// instance_expr is an expression that represents the instance /// it must be non-null if is_static is false. /// /// method is the method to invoke. /// /// Arguments is the list of arguments to pass to the method or constructor. /// </remarks> public static void EmitCall (EmitContext ec, bool is_base, bool is_static, Expression instance_expr, MethodBase method, ArrayList Arguments, Location loc) { ILGenerator ig = ec.ig; bool struct_call = false; Type decl_type = method.DeclaringType; if (!RootContext.StdLib) { // Replace any calls to the system's System.Array type with calls to // the newly created one. if (method == TypeManager.system_int_array_get_length) method = TypeManager.int_array_get_length; else if (method == TypeManager.system_int_array_get_rank) method = TypeManager.int_array_get_rank; else if (method == TypeManager.system_object_array_clone) method = TypeManager.object_array_clone; else if (method == TypeManager.system_int_array_get_length_int) method = TypeManager.int_array_get_length_int; else if (method == TypeManager.system_int_array_get_lower_bound_int) method = TypeManager.int_array_get_lower_bound_int; else if (method == TypeManager.system_int_array_get_upper_bound_int) method = TypeManager.int_array_get_upper_bound_int; else if (method == TypeManager.system_void_array_copyto_array_int) method = TypeManager.void_array_copyto_array_int; } // // This checks the `ConditionalAttribute' on the method, and the // ObsoleteAttribute // TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc); if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0) return; if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0) return; if (!is_static){ if (decl_type.IsValueType) struct_call = true; // // If this is ourselves, push "this" // if (instance_expr == null){ ig.Emit (OpCodes.Ldarg_0); } else { // // Push the instance expression // if (instance_expr.Type.IsValueType){ // // Special case: calls to a function declared in a // reference-type with a value-type argument need // to have their value boxed. struct_call = true; if (decl_type.IsValueType){ // // If the expression implements IMemoryLocation, then // we can optimize and use AddressOf on the // return. // // If not we have to use some temporary storage for // it. if (instance_expr is IMemoryLocation){ ((IMemoryLocation)instance_expr). AddressOf (ec, AddressOp.LoadStore); } else { Type t = instance_expr.Type; instance_expr.Emit (ec); LocalBuilder temp = ig.DeclareLocal (t); ig.Emit (OpCodes.Stloc, temp); ig.Emit (OpCodes.Ldloca, temp); } } else { instance_expr.Emit (ec); ig.Emit (OpCodes.Box, instance_expr.Type); } } else instance_expr.Emit (ec); } } EmitArguments (ec, method, Arguments); if (is_static || struct_call || is_base){ if (method is MethodInfo) { ig.Emit (OpCodes.Call, (MethodInfo) method); } else ig.Emit (OpCodes.Call, (ConstructorInfo) method); } else { if (method is MethodInfo) ig.Emit (OpCodes.Callvirt, (MethodInfo) method); else ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method); } }
public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; if (ec.TypeContainer is Struct){ ig.Emit (OpCodes.Ldarg_0); source.Emit (ec); ig.Emit (OpCodes.Stobj, type); } else { source.Emit (ec); ig.Emit (OpCodes.Starg, 0); } }
// // Implements the IAssignMethod interface for assignments // public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { Expression my_source = source; if (prepare_for_load) { prepared = true; source.Emit (ec); if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } } else if (leave_copy) { source.Emit (ec); temp = new LocalTemporary (this.Type); temp.Store (ec); my_source = temp; } Arguments args = new Arguments (1); args.Add (new Argument (my_source)); Invocation.EmitCall (ec, IsBase, InstanceExpression, spec.Set, args, loc, false, prepared); if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
public void EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; EmitInstance (ec, prepared); source.Emit (ec); if (leave_copy) { ec.Emit (OpCodes.Dup); if (!IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } if ((spec.Modifiers & Modifiers.VOLATILE) != 0) ec.Emit (OpCodes.Volatile); spec.MemberDefinition.SetIsAssigned (); if (IsStatic) ec.Emit (OpCodes.Stsfld, spec); else ec.Emit (OpCodes.Stfld, spec); if (temp != null) { temp.Emit (ec); temp.Release (ec); temp = null; } }
public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; int arg_idx = idx; if (!ec.IsStatic) arg_idx++; if (is_ref) EmitLdArg (ig, arg_idx); source.Emit (ec); if (is_ref) StoreFromPtr (ig, type); else { if (arg_idx <= 255) ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else ig.Emit (OpCodes.Starg, arg_idx); } }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) { if (isCompound) throw new NotImplementedException (); source.Emit (ec); Store (ec); if (leave_copy) Emit (ec); }
public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast) { TypeSpec expr_type = expr.Type; if (expr_type == null && expr.eclass == ExprClass.MethodGroup){ // if we are a method group, emit a warning expr.Emit (null); } if (expr_type == TypeManager.void_type) return null; if (expr_type.Kind == MemberKind.TypeParameter) return ImplicitTypeParameterConversion (expr, target_type); // // from the null type to any reference-type. // NullLiteral nl = expr as NullLiteral; if (nl != null) { return nl.ConvertImplicitly (null, target_type); } if (ImplicitReferenceConversionExists (expr, target_type)) { // // Avoid wrapping implicitly convertible reference type // if (!explicit_cast) return expr; return EmptyCast.Create (expr, target_type); } return ImplicitBoxingConversion (expr, expr_type, target_type); }
public void EmitAssign (EmitContext ec, Expression source) { if (temporary != null){ if (have_temporary) temporary.Emit (ec); else { expr.Emit (ec); ec.ig.Emit (OpCodes.Dup); temporary.Store (ec); have_temporary = true; } } else expr.Emit (ec); source.Emit (ec); StoreFromPtr (ec.ig, type); }
public void EmitAssign (EmitContext ec, Expression source) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; Type t = source.Type; LoadArrayAndArguments (ec); // // The stobj opcode used by value types will need // an address on the stack, not really an array/array // pair // if (rank == 1){ if (t == TypeManager.enum_type || t == TypeManager.decimal_type || (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t))) ig.Emit (OpCodes.Ldelema, t); } source.Emit (ec); if (rank == 1) EmitStoreOpcode (ig, t); else { ModuleBuilder mb = CodeGen.ModuleBuilder; int arg_count = ea.Arguments.Count; Type [] args = new Type [arg_count + 1]; MethodInfo set; for (int i = 0; i < arg_count; i++){ //args [i++] = a.Type; args [i] = TypeManager.int32_type; } args [arg_count] = type; set = mb.GetArrayMethod ( ea.Expr.Type, "Set", CallingConventions.HasThis | CallingConventions.Standard, TypeManager.void_type, args); ig.Emit (OpCodes.Call, set); } }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { HoistedVariable hv = GetHoistedVariable (ec); if (hv != null) { hv.EmitAssign (ec, source, leave_copy, prepare_for_load); return; } New n_source = source as New; if (n_source != null) { if (!n_source.Emit (ec, this)) { if (leave_copy) EmitLoad (ec); return; } } else { if (IsRef) EmitLoad (ec); source.Emit (ec); } if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (IsRef) { temp = new LocalTemporary (Type); temp.Store (ec); } } if (IsRef) StoreFromPtr (ec.ig, type); else Variable.EmitAssign (ec); if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
// // Called back from Yield // public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { ILGenerator ig = ec.ig; // Store the new current ig.Emit (OpCodes.Ldarg_0); expr.Emit (ec); ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder); // store resume program-counter ig.Emit (OpCodes.Ldarg_0); IntConstant.EmitInt (ig, resume_pc); ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder); // mark finally blocks as disabled if (unwind_protect && skip_finally != null) { ig.Emit (OpCodes.Ldc_I4_1); ig.Emit (OpCodes.Stloc, skip_finally); } // Return ok ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok); ig.MarkLabel (resume_point); }
// // Called back from Yield // public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { // Store the new current ec.Emit (OpCodes.Ldarg_0); expr.Emit (ec); ec.Emit (OpCodes.Stfld, IteratorHost.CurrentField.Spec); // // Guard against being disposed meantime // Label disposed = ec.DefineLabel (); ec.Emit (OpCodes.Ldarg_0); ec.Emit (OpCodes.Ldfld, IteratorHost.DisposingField.Spec); ec.Emit (OpCodes.Brtrue_S, disposed); // // store resume program-counter // ec.Emit (OpCodes.Ldarg_0); ec.EmitInt (resume_pc); ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec); ec.MarkLabel (disposed); // mark finally blocks as disabled if (unwind_protect && skip_finally != null) { ec.EmitInt (1); ec.Emit (OpCodes.Stloc, skip_finally); } // Return ok ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok); ec.MarkLabel (resume_point); }
static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast) { Type expr_type = expr.Type; if (expr_type == null && expr.eclass == ExprClass.MethodGroup){ // if we are a method group, emit a warning expr.Emit (null); } if (expr_type == TypeManager.void_type) return null; if (TypeManager.IsGenericParameter (expr_type)) return ImplicitTypeParameterConversion (expr, target_type); // // from the null type to any reference-type. // NullLiteral nl = expr as NullLiteral; if (nl != null) { return nl.ConvertImplicitly(target_type); } if (ImplicitReferenceConversionExists (expr, target_type)) { // // Avoid wrapping implicitly convertible reference type // if (!explicit_cast) return expr; return EmptyCast.Create (expr, target_type); } bool use_class_cast; if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) { if (use_class_cast) return new ClassCast (expr, target_type); else return new BoxedCast (expr, target_type); } return null; }
/// <summary> /// This method emits code for a lookup-based switch statement (non-string) /// Basically it groups the cases into blocks that are at least half full, /// and then spits out individual lookup opcodes for each block. /// It emits the longest blocks first, and short blocks are just /// handled with direct compares. /// </summary> /// <param name="ec"></param> /// <param name="val"></param> /// <returns></returns> void TableSwitchEmit (EmitContext ec, Expression val) { int element_count = Elements.Count; object [] element_keys = new object [element_count]; Elements.Keys.CopyTo (element_keys, 0); Array.Sort (element_keys); // initialize the block list with one element per key var key_blocks = new List<KeyBlock> (element_count); foreach (object key in element_keys) key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); KeyBlock current_kb; // iteratively merge the blocks while they are at least half full // there's probably a really cool way to do this with a tree... while (key_blocks.Count > 1) { var key_blocks_new = new List<KeyBlock> (); current_kb = (KeyBlock) key_blocks [0]; for (int ikb = 1; ikb < key_blocks.Count; ikb++) { KeyBlock kb = (KeyBlock) key_blocks [ikb]; if ((current_kb.Size + kb.Size) * 2 >= KeyBlock.TotalLength (current_kb, kb)) { // merge blocks current_kb.last = kb.last; current_kb.Size += kb.Size; } else { // start a new block key_blocks_new.Add (current_kb); current_kb = kb; } } key_blocks_new.Add (current_kb); if (key_blocks.Count == key_blocks_new.Count) break; key_blocks = key_blocks_new; } // initialize the key lists foreach (KeyBlock kb in key_blocks) kb.element_keys = new List<object> (); // fill the key lists int iBlockCurr = 0; if (key_blocks.Count > 0) { current_kb = (KeyBlock) key_blocks [0]; foreach (object key in element_keys) { bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last : System.Convert.ToInt64 (key) > current_kb.last; if (next_block) current_kb = (KeyBlock) key_blocks [++iBlockCurr]; current_kb.element_keys.Add (key); } } // sort the blocks so we can tackle the largest ones first key_blocks.Sort (); // okay now we can start... Label lbl_end = ec.DefineLabel (); // at the end ;-) Label lbl_default = default_target; Type type_keys = null; if (element_keys.Length > 0) type_keys = element_keys [0].GetType (); // used for conversions TypeSpec compare_type; if (TypeManager.IsEnumType (SwitchType)) compare_type = EnumSpec.GetUnderlyingType (SwitchType); else compare_type = SwitchType; for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock) { KeyBlock kb = ((KeyBlock) key_blocks [iBlock]); lbl_default = (iBlock == 0) ? default_target : ec.DefineLabel (); if (kb.Length <= 2) { foreach (object key in kb.element_keys) { SwitchLabel sl = (SwitchLabel) Elements [key]; if (key is int && (int) key == 0) { val.EmitBranchable (ec, sl.GetILLabel (ec), false); } else { val.Emit (ec); EmitObjectInteger (ec, key); ec.Emit (OpCodes.Beq, sl.GetILLabel (ec)); } } } else { // TODO: if all the keys in the block are the same and there are // no gaps/defaults then just use a range-check. if (compare_type == TypeManager.int64_type || compare_type == TypeManager.uint64_type) { // TODO: optimize constant/I4 cases // check block range (could be > 2^31) val.Emit (ec); EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys)); ec.Emit (OpCodes.Blt, lbl_default); val.Emit (ec); EmitObjectInteger (ec, System.Convert.ChangeType (kb.last, type_keys)); ec.Emit (OpCodes.Bgt, lbl_default); // normalize range val.Emit (ec); if (kb.first != 0) { EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys)); ec.Emit (OpCodes.Sub); } ec.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels! } else { // normalize range val.Emit (ec); int first = (int) kb.first; if (first > 0) { ec.EmitInt (first); ec.Emit (OpCodes.Sub); } else if (first < 0) { ec.EmitInt (-first); ec.Emit (OpCodes.Add); } } // first, build the list of labels for the switch int iKey = 0; int cJumps = kb.Length; Label [] switch_labels = new Label [cJumps]; for (int iJump = 0; iJump < cJumps; iJump++) { object key = kb.element_keys [iKey]; if (System.Convert.ToInt64 (key) == kb.first + iJump) { SwitchLabel sl = (SwitchLabel) Elements [key]; switch_labels [iJump] = sl.GetILLabel (ec); iKey++; } else switch_labels [iJump] = lbl_default; } // emit the switch opcode ec.Emit (OpCodes.Switch, switch_labels); } // mark the default for this block if (iBlock != 0) ec.MarkLabel (lbl_default); } // TODO: find the default case and emit it here, // to prevent having to do the following jump. // make sure to mark other labels in the default section // the last default just goes to the end if (element_keys.Length > 0) ec.Emit (OpCodes.Br, lbl_default); // now emit the code for the sections bool found_default = false; foreach (SwitchSection ss in Sections) { foreach (SwitchLabel sl in ss.Labels) { if (sl.Converted == SwitchLabel.NullStringCase) { ec.MarkLabel (null_target); } else if (sl.Label == null) { ec.MarkLabel (lbl_default); found_default = true; if (!has_null_case) ec.MarkLabel (null_target); } ec.MarkLabel (sl.GetILLabel (ec)); ec.MarkLabel (sl.GetILLabelCode (ec)); } ss.Block.Emit (ec); } if (!found_default) { ec.MarkLabel (lbl_default); if (!has_null_case) { ec.MarkLabel (null_target); } } ec.MarkLabel (lbl_end); }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; Type t = source.Type; prepared = prepare_for_load; if (prepared) { AddressOf (ec, AddressOp.LoadStore); ec.ig.Emit (OpCodes.Dup); } else { LoadArrayAndArguments (ec); } if (rank == 1) { bool is_stobj, has_type_arg; OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); if (!prepared) { // // The stobj opcode used by value types will need // an address on the stack, not really an array/array // pair // if (is_stobj) ig.Emit (OpCodes.Ldelema, t); } source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (this.type); temp.Store (ec); } if (prepared) StoreFromPtr (ig, t); else if (is_stobj) ig.Emit (OpCodes.Stobj, t); else if (has_type_arg) ig.Emit (op, t); else ig.Emit (op); } else { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (this.type); temp.Store (ec); } if (prepared) { StoreFromPtr (ig, t); } else { int arg_count = ea.Arguments.Count; Type [] args = new Type [arg_count + 1]; for (int i = 0; i < arg_count; i++) { //args [i++] = a.Type; args [i] = TypeManager.int32_type; } args [arg_count] = type; MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod ( ea.Expr.Type, "Set", CallingConventions.HasThis | CallingConventions.Standard, TypeManager.void_type, args); ig.Emit (OpCodes.Call, set); } } if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode) { var instance_type = instance.Type; // // Push the instance expression // if ((instance_type.IsStructOrEnum && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) || instance_type.IsGenericParameter || declaringType.IsNullableType) { // // If the expression implements IMemoryLocation, then // we can optimize and use AddressOf on the // return. // // If not we have to use some temporary storage for // it. var iml = instance as IMemoryLocation; if (iml != null) { iml.AddressOf (ec, AddressOp.Load); } else { LocalTemporary temp = new LocalTemporary (instance_type); instance.Emit (ec); temp.Store (ec); temp.AddressOf (ec, AddressOp.Load); } return ReferenceContainer.MakeType (ec.Module, instance_type); } if (instance_type.IsStructOrEnum) { instance.Emit (ec); ec.Emit (OpCodes.Box, instance_type); return ec.BuiltinTypes.Object; } instance.Emit (ec); return instance_type; }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; expr.Emit (ec); if (prepare_for_load) ec.ig.Emit (OpCodes.Dup); source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temporary = new LocalTemporary (expr.Type); temporary.Store (ec); } StoreFromPtr (ec.ig, type); if (temporary != null) { temporary.Emit (ec); temporary.Release (ec); } }
public override void Emit(EmitContext ec) { child.Emit(ec); }
// // source is ignored, because we already have a copy of it from the // LValue resolution and we have already constructed a pre-cached // version of the arguments (ea.set_arguments); // public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; Expression value = set_expr; if (prepared) { Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, true, false); prepared_value = new LocalTemporary (type); prepared_value.Store (ec); source.Emit (ec); prepared_value.Release (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temp = new LocalTemporary (Type); temp.Store (ec); } } else if (leave_copy) { temp = new LocalTemporary (Type); source.Emit (ec); temp.Store (ec); value = temp; } if (!prepared) arguments.Add (new Argument (value)); Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared); if (temp != null) { temp.Emit (ec); temp.Release (ec); } }
// // Called back from Yield // public void MarkYield(EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point) { // Store the new current ec.Emit (OpCodes.Ldarg_0); expr.Emit (ec); ec.Emit (OpCodes.Stfld, IteratorHost.CurrentField.Spec); // store resume program-counter ec.Emit (OpCodes.Ldarg_0); ec.EmitInt (resume_pc); ec.Emit (OpCodes.Stfld, IteratorHost.PC.Spec); // mark finally blocks as disabled if (unwind_protect && skip_finally != null) { ec.EmitInt (1); ec.Emit (OpCodes.Stloc, skip_finally); } // Return ok ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok); ec.MarkLabel (resume_point); }
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { FieldAttributes fa = FieldInfo.Attributes; bool is_static = (fa & FieldAttributes.Static) != 0; bool is_readonly = (fa & FieldAttributes.InitOnly) != 0; ILGenerator ig = ec.ig; if (is_readonly && !ec.IsConstructor){ Report_AssignToReadonly (source); return; } prepared = prepare_for_load; EmitInstance (ec, prepared); source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!FieldInfo.IsStatic) { temp = new LocalTemporary (this.Type); temp.Store (ec); } } FieldBase f = TypeManager.GetField (FieldInfo); if (f != null){ if ((f.ModFlags & Modifiers.VOLATILE) != 0) ig.Emit (OpCodes.Volatile); f.SetAssigned (); } if (is_static) ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ()); else ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ()); if (temp != null) { temp.Emit (ec); temp.Release (ec); temp = null; } }
public void Emit(EmitContext ec, bool conditionalAccess) { Label NullOperatorLabel; Nullable.Unwrap unwrap; if (conditionalAccess && Expression.IsNeverNull(instance)) { conditionalAccess = false; } if (conditionalAccess) { NullOperatorLabel = ec.DefineLabel(); unwrap = instance as Nullable.Unwrap; } else { NullOperatorLabel = new Label(); unwrap = null; } IMemoryLocation instance_address = null; bool conditional_access_dup = false; if (unwrap != null) { unwrap.Store(ec); unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel); } else { if (conditionalAccess && addressRequired) { // // Don't allocate temp variable when instance load is cheap and load and load-address // operate on same memory // instance_address = instance as VariableReference; if (instance_address == null) { instance_address = instance as LocalTemporary; } if (instance_address == null) { EmitLoad(ec, false); ec.Emit(OpCodes.Dup); ec.EmitLoadFromPtr(instance.Type); conditional_access_dup = true; } else { instance.Emit(ec); } } else { EmitLoad(ec, !conditionalAccess); if (conditionalAccess) { conditional_access_dup = !IsInexpensiveLoad(); if (conditional_access_dup) { ec.Emit(OpCodes.Dup); } } } if (conditionalAccess) { if (instance.Type.Kind == MemberKind.TypeParameter) { ec.Emit(OpCodes.Box, instance.Type); } ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel); if (conditional_access_dup) { ec.Emit(OpCodes.Pop); } } } if (conditionalAccess) { if (!ec.ConditionalAccess.Statement) { if (ec.ConditionalAccess.Type.IsNullableType) { Nullable.LiftedNull.Create(ec.ConditionalAccess.Type, Location.Null).Emit(ec); } else { ec.EmitNull(); } } ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel); ec.MarkLabel(NullOperatorLabel); if (instance_address != null) { instance_address.AddressOf(ec, AddressOp.Load); } else if (unwrap != null) { unwrap.Emit(ec); var tmp = ec.GetTemporaryLocal(unwrap.Type); ec.Emit(OpCodes.Stloc, tmp); ec.Emit(OpCodes.Ldloca, tmp); ec.FreeTemporaryLocal(tmp, unwrap.Type); } else if (!conditional_access_dup) { instance.Emit(ec); } } }
public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; VariableInfo vi = VariableInfo; vi.Assigned = true; source.Emit (ec); ig.Emit (OpCodes.Stloc, vi.LocalBuilder); }