protected internal override void VisitLdFlda(LdFlda inst) { base.VisitLdFlda(inst); // Get display class info if (!IsDisplayClassFieldAccess(inst, out _, out DisplayClass displayClass, out IField field)) { return; } // We want the specialized version, so that display-class type parameters are // substituted with the type parameters from the use-site. var fieldType = field.Type; // However, use the unspecialized member definition to make reference comparisons in dictionary possible. field = (IField)field.MemberDefinition; if (!displayClass.Variables.TryGetValue(field, out var v)) { context.Step($"Introduce captured variable for {field.FullName}", inst); // Introduce a fresh variable for the display class field. Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition); v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, fieldType, field.Name); v.HasInitialValue = true; v.CaptureScope = displayClass.CaptureScope; inst.ReplaceWith(new LdLoca(v).WithILRange(inst)); displayClass.Variables.Add(field, v); } else { context.Step($"Reuse captured variable {v.Name} for {field.FullName}", inst); inst.ReplaceWith(new LdLoca(v).WithILRange(inst)); } }
protected internal override void VisitLdFlda(LdFlda inst) { base.VisitLdFlda(inst); // Get display class info if (!IsDisplayClassFieldAccess(inst, out _, out DisplayClass displayClass, out IField field)) return; var keyField = (IField)field.MemberDefinition; var v = displayClass.VariablesToDeclare[keyField]; context.Step($"Replace {field.Name} with captured variable {v.Name}", inst); ILVariable variable = v.GetOrDeclare(); inst.ReplaceWith(new LdLoca(variable).WithILRange(inst)); // add captured variable to all descendant functions from the declaring function to this use-site function foreach (var f in currentFunctions) { if (f == variable.Function) break; f.CapturedVariables.Add(variable); } }
/// <code> /// stloc s(ldflda) /// stloc s2(ldobj(ldflda(ldloc s))) /// stloc l(ldloc s2) /// stobj (ldflda(ldloc s), binary.add(ldloc s2, ldc.i4 1)) /// --> /// stloc l(compound.op.old(ldobj(ldflda(ldflda)), ldc.i4 1)) /// </code> bool TransformCSharp4PostIncDecOperatorOnAddress(Block block, int i) { var baseFieldAddress = block.Instructions[i] as StLoc; var fieldValue = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; var fieldValueCopyToLocal = block.Instructions.ElementAtOrDefault(i + 2) as StLoc; var stobj = block.Instructions.ElementAtOrDefault(i + 3) as StObj; if (baseFieldAddress == null || fieldValue == null || fieldValueCopyToLocal == null || stobj == null) { return(false); } if (baseFieldAddress.Variable.Kind != VariableKind.StackSlot || fieldValue.Variable.Kind != VariableKind.StackSlot || fieldValueCopyToLocal.Variable.Kind != VariableKind.Local) { return(false); } IType t; IField targetField; ILInstruction targetFieldLoad, baseFieldAddressLoad2; if (!fieldValue.Value.MatchLdObj(out targetFieldLoad, out t)) { return(false); } ILInstruction baseAddress; if (baseFieldAddress.Value is LdFlda) { IField targetField2; ILInstruction baseFieldAddressLoad3; if (!targetFieldLoad.MatchLdFlda(out baseFieldAddressLoad2, out targetField) || !baseFieldAddressLoad2.MatchLdLoc(baseFieldAddress.Variable)) { return(false); } if (!stobj.Target.MatchLdFlda(out baseFieldAddressLoad3, out targetField2) || !baseFieldAddressLoad3.MatchLdLoc(baseFieldAddress.Variable) || !IsSameMember(targetField, targetField2)) { return(false); } baseAddress = new LdFlda(baseFieldAddress.Value, targetField); } else if (baseFieldAddress.Value is LdElema) { if (!targetFieldLoad.MatchLdLoc(baseFieldAddress.Variable) || !stobj.Target.MatchLdLoc(baseFieldAddress.Variable)) { return(false); } baseAddress = baseFieldAddress.Value; } else { return(false); } BinaryNumericInstruction binary = stobj.Value as BinaryNumericInstruction; if (binary == null || !binary.Left.MatchLdLoc(fieldValue.Variable) || !binary.Right.MatchLdcI4(1) || (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)) { return(false); } context.Step($"TransformCSharp4PostIncDecOperatorOnAddress", baseFieldAddress); var assignment = new CompoundAssignmentInstruction(binary, new LdObj(baseAddress, t), binary.Right, t, CompoundAssignmentType.EvaluatesToOldValue); stobj.ReplaceWith(new StLoc(fieldValueCopyToLocal.Variable, assignment)); block.Instructions.RemoveAt(i + 2); block.Instructions.RemoveAt(i + 1); return(true); }