public virtual void WriteStoreLocal(StoreLocal s, ExpressionUsage u) { Begin(u); Write(s.Variable.Name + Assign); WriteExpression(s.Value); End(u); }
public void VisitBegin(BeginMethod method) { Log.DebugLine(this, "-----------------------------------"); Log.DebugLine(this, "{0:F}", method.Info.Instructions); // Loop through each try block, int offset = -1; for (int i = 0; i < method.Info.Instructions.TryCatchCollection.Length && offset < 0; ++i) { TryCatch tc = method.Info.Instructions.TryCatchCollection[i]; // and the associated catch blocks, for (int j = 0; j < tc.Catchers.Count && offset < 0; ++j) { CatchBlock cb = tc.Catchers[j]; // if the first instruction in a catch is a store local then the code // is storing a reference to the exception object and we need to check // to see if it's being rethrown. StoreLocal store = method.Info.Instructions[cb.Index] as StoreLocal; if (store != null) { offset = DoCheckCatch(method.Info.Instructions, cb, store.Variable); } } } if (offset >= 0) { Reporter.MethodFailed(method.Info.Method, CheckID, offset, string.Empty); } }
public override void Begin(ref Statement s) { ParentExpression = null; switch (s.StatementType) { case StatementType.VariableDeclaration: { var d = s as VariableDeclaration; for (var var = d.Variable; var != null; var = var.Next) { if (MustCopyType(var.ValueType)) { if (var.OptionalValue == null) { var.OptionalValue = new Default(var.Source, var.ValueType); } else if (MustCopyValue(var.OptionalValue)) { s = new StoreLocal(var.Source, var, var.OptionalValue); var.OptionalValue = new Default(var.Source, var.ValueType); var.SetName(Type.GetUniqueIdentifier(var.Name)); } } } break; } } }
private long?[] DoTransformLocals(int index) { long?[] locals = null; StoreLocal store = m_instructions[index] as StoreLocal; if (store != null) { long?newValue = null; if (m_state.Stack.Count > 0) // may be zero if the stack hasn't been inited yet { newValue = m_state.Stack.Back().Value; } locals = new long?[m_state.Locals.Length]; m_state.Locals.CopyTo(locals, 0); locals[store.Variable] = newValue; } else if (m_instructions[index].Untyped.OpCode.Code == Code.Ldloca || m_instructions[index].Untyped.OpCode.Code == Code.Ldloca_S) { VariableDefinition param = m_instructions[index].Untyped.Operand as VariableDefinition; if (param != null) { locals = new long?[m_state.Locals.Length]; m_state.Locals.CopyTo(locals, 0); locals[param.Index] = null; } } else { locals = m_state.Locals; } return(locals); }
public static bool TryCreateIndirection(Namescope scope, ref Expression e, out Expression s) { if (e.NeedsIndirection()) { var v = new Variable(e.Source, null, scope.GetUniqueIdentifier("ind"), e.ReturnType, VariableType.Indirection); var a = e as AddressOf; var q = e as SequenceOp; if (q?.Right is AddressOf) { a = q.Right as AddressOf; q.Right = a.ActualValue; } s = new StoreLocal(e.Source, v, e.ActualValue); e = new LoadLocal(e.Source, v); if (a != null) { e = new AddressOf(e, a.AddressType); } return(true); } s = null; return(false); }
public void VisitStore(StoreLocal store) { if (store.RealName) { DoAdd(store.Name); } else { Log.DebugLine(this, "no local names"); } }
public void VisitStoreLocal(StoreLocal store) { if (m_offset < 0 && store.Index > 0) { StoreLocal prev = m_info.Instructions[store.Index - 1] as StoreLocal; if (prev != null && prev.Variable == store.Variable) { m_offset = store.Untyped.Offset; Log.DebugLine(this, "Matched at {0:X2}", m_offset); } } }
// stloc.0 V_0 // ldloc.0 V_0 private bool DoStoresLocal(int index) { bool found = false; if (index > 0) { LoadLocal load = m_info.Instructions[index] as LoadLocal; StoreLocal store = m_info.Instructions[index - 1] as StoreLocal; found = load != null && store != null && load.Variable == store.Variable; } return(found); }
public void VisitStoreLocal(StoreLocal store) { if (m_needsCheck) { Log.Indent(); LoadArg load = m_info.Instructions[store.Index - 1] as LoadArg; if (load != null && m_types[load.Arg] != null) { Log.DebugLine(this, "arg{0}: was saved to a local (at {1:X2})", load.Arg, store.Untyped.Offset); m_types[load.Arg] = null; } Log.Unindent(); } }
// ldarg.0 this // stloc.0 V_0 public void VisitStore(StoreLocal store) { if (m_needsCheck && m_offset < 0) { LoadArg load = m_info.Instructions[store.Index - 1] as LoadArg; if (load != null && load.Arg == 0) { m_thisLocals.Add(store.Variable); Log.DebugLine(this, "{0} = this at {1:X2}", store.Name, store.Untyped.Offset); } else { Unused.Value = m_thisLocals.Remove(store.Variable); } } }
public void VisitStore(StoreLocal store) { if (store.Index > 0) { LoadConstantInt load = m_info.Instructions[store.Index - 1] as LoadConstantInt; if (load != null) { if (load.Value < 0 || load.Value > 255) { Log.DebugLine(this, "store at {0:X2}", store.Untyped.Offset); if (m_stores.IndexOf(store.Variable) < 0) { m_stores.Add(store.Variable); } } } } }
// newobj System.Void System.IO.StreamReader::.ctor(System.String) // stloc.1 V_1 private int DoGetNewDisposableLocal(StoreLocal store) { int variable = -1; NewObj obj = m_info.Instructions[store.Index - 1] as NewObj; if (obj != null && obj.Ctor.Name.EndsWith(".ctor")) { TypeDefinition type = Cache.FindType(obj.Ctor.DeclaringType); if (type != null && type.TypeOrBaseImplements("System.IDisposable", Cache)) { m_details = "Type: " + obj.Ctor.DeclaringType.FullName; Log.DebugLine(this, "{0} = new {1}", store.Name, obj.Ctor.DeclaringType.FullName); variable = store.Variable; } } return(variable); }
public void VisitStoreLocal(StoreLocal store) { if (m_offset < 0) { int variable = DoGetNewDisposableLocal(store); if (variable >= 0) { List <int> loads = DoGetDisposableLoads(store.Index + 1, variable); if (loads.Count > 0) { if (DoNeedsDispose(loads, store.Index + 1)) { m_offset = store.Untyped.Offset; Log.DebugLine(this, "no dispose call"); } } } } }
// This method is used by the Transform above and later on when we // need to compute the state for each instruction in a method. public Lattice Transform(int index) { DBC.Pre(index >= 0 && index < m_instructions.Length, "index is oor"); // real code would probably use FastPre StoreLocal store = m_instructions[index] as StoreLocal; if (store != null) { LoadConstantInt load = m_instructions[index - 1] as LoadConstantInt; // test code so we only track constant loads if (load != null) { return(new Lattice(m_instructions, new State(load.Value))); } else { return(new Lattice(m_instructions, Indeterminate)); } } return(this); }
static Expression CreateAssertIndirection(ref Expression e, List <StoreLocal> locals, Namescope scope) { switch (e.ExpressionType) { case ExpressionType.AddressOf: return(CreateAssertIndirection(ref (e as AddressOf).Operand, locals, scope)); case ExpressionType.LoadLocal: case ExpressionType.LoadArgument: case ExpressionType.LoadField: case ExpressionType.LoadElement: case ExpressionType.Invalid: case ExpressionType.Constant: return(e); } var v = new Variable(e.Source, null, scope.GetUniqueIdentifier("assert"), e.ReturnType); var s = new StoreLocal(e.Source, v, e); var l = new LoadLocal(e.Source, v); locals.Add(s); return(e = l); }
private bool DoMatch(CodeBlock lhs, CodeBlock rhs, int count) { Log.DebugLine(this, " lhs: {0} at {1:X2}", lhs.Method, lhs.Instructions[lhs.Index].Untyped.Offset); Log.DebugLine(this, " rhs: {0} at {1:X2}", rhs.Method, rhs.Instructions[rhs.Index].Untyped.Offset); Log.DebugLine(this, " count: {0}", count); for (int i = 0; i < count; ++i) { TypedInstruction left = lhs.Instructions[lhs.Index + i]; TypedInstruction right = rhs.Instructions[rhs.Index + i]; LoadLocal load1 = left as LoadLocal; LoadLocal load2 = right as LoadLocal; LoadLocalAddress load1b = left as LoadLocalAddress; LoadLocalAddress load2b = right as LoadLocalAddress; StoreLocal store1 = left as StoreLocal; StoreLocal store2 = right as StoreLocal; if (load1 != null && load2 != null) { // If we have real names for the local variables (from the mdb file) then // life is good and we can compare the names. If not we're stuck: we can't // simply use the variable index because we'll get false positives. if (!load1.RealName) { Log.DebugLine(this, " can't match local name"); return(false); } // This should be a temporary in which case we can't use the variable index. else if (load1.Name.StartsWith("V_") && load1.Type.FullName != load2.Type.FullName) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, load1.Type.FullName, load2.Type.FullName); return(false); } else if (!load1.Name.StartsWith("V_") && load1.Name != load2.Name) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, load1.Name, load2.Name); return(false); } } else if (load1b != null && load2b != null) { if (!load1b.RealName) { Log.DebugLine(this, " can't match local name"); return(false); } else if (load1b.Name.StartsWith("V_") && load1b.Type.FullName != load2b.Type.FullName) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, load1b.Type.FullName, load2b.Type.FullName); return(false); } else if (!load1b.Name.StartsWith("V_") && load1b.Name != load2b.Name) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, load1b.Name, load2b.Name); return(false); } } else if (store1 != null && store2 != null) { if (!store1.RealName) { Log.DebugLine(this, " can't match local name"); return(false); } else if (store1.Name.StartsWith("V_") && store1.Type.FullName != store2.Type.FullName) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, store1.Type.FullName, store2.Type.FullName); return(false); } else if (!store1.Name.StartsWith("V_") && store1.Name != store2.Name) { Log.DebugLine(this, " {0} != {1} ({2} and {3})", left, right, store1.Name, store2.Name); return(false); } } else if (!left.Untyped.Matches(right.Untyped)) { Log.DebugLine(this, " {0} != {1}", left, right); return(false); } } return(true); }
public Expression CompileNewExpression(AstNew e) { // Implicitly typed arrays if (e.OptionalType == null) { if (e.OptionalArguments != null) { return(Error(e.Source, ErrorCode.E2001, "Array constructors cannot have argument list")); } if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E2002, "Cannot specify size on implicitly typed arrays")); } if (e.OptionalCollectionInitializer == null || e.OptionalCollectionInitializer.Count == 0) { return(Error(e.Source, ErrorCode.E2003, "Must provide non-empty initializer list for implicitly typed arrays")); } var values = new Expression[e.OptionalCollectionInitializer.Count]; for (int i = 0; i < values.Length; i++) { values[i] = CompileExpression(e.OptionalCollectionInitializer[i]); } var et = TryGetImplicitElementType(values); if (et == null) { return(Error(e.Source, ErrorCode.E2004, "No best type found for implicitly typed array")); } for (int i = 0; i < values.Length; i++) { values[i] = CompileImplicitCast(e.Source, et, values[i]); } return(et.IsValueType || et.IsReferenceType ? new NewArray(e.Source, TypeBuilder.GetArray(et), values) : et != DataType.Invalid ? Error(e.Source, ErrorCode.E2080, "Cannot create an implicitly typed array of type " + et.Quote()) : Expression.Invalid); } var dt = NameResolver.GetType(Namescope, e.OptionalType); switch (dt.TypeType) { case TypeType.RefArray: { if (e.OptionalArguments != null) { return(Error(e.Source, ErrorCode.E2005, "Array constructors cannot have argument list")); } var at = dt as RefArrayType; Expression size = null; if (e.OptionalArraySize != null) { size = CompileImplicitCast(e.Source, Essentials.Int, CompileExpression(e.OptionalArraySize)); if (size.IsInvalid) { return(Expression.Invalid); } } if (e.OptionalCollectionInitializer != null) { var values = new Expression[e.OptionalCollectionInitializer.Count]; for (int i = 0; i < values.Length; i++) { values[i] = CompileExpression(e.OptionalCollectionInitializer[i]); } if (size != null) { var c = Compiler.ConstantFolder.TryMakeConstant(size); if (c == null || !c.Value.Equals(values.Length)) { return(Error(size.Source, ErrorCode.E2006, "Inconsistent array size and initializer list length")); } } switch (at.ElementType.BuiltinType) { case BuiltinType.Bool: case BuiltinType.Byte: case BuiltinType.Char: case BuiltinType.Double: case BuiltinType.Int: case BuiltinType.Float: case BuiltinType.Long: case BuiltinType.SByte: case BuiltinType.Short: case BuiltinType.UInt: case BuiltinType.ULong: case BuiltinType.UShort: // Disable warning on primitive types break; default: if (TryGetImplicitElementType(values) == at.ElementType) { Log.Warning3(e.Source, ErrorCode.W2007, "Array can be instantiated as implicitly typed array (new[] { ... })"); } break; } for (int i = 0; i < values.Length; i++) { values[i] = CompileImplicitCast(values[i].Source, at.ElementType, values[i]); } return(new NewArray(e.Source, at, values)); } return(new NewArray(e.Source, at, size)); } case TypeType.Class: case TypeType.Struct: case TypeType.GenericParameter: { if (dt.IsStatic) { return(Error(e.Source, ErrorCode.E2090, "Cannot instantiate static class")); } if (e.OptionalArguments != null || e.OptionalCollectionInitializer != null) { if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E2008, "Object constructors cannot have array size")); } Expression newObject; if (dt.IsStruct && (e.OptionalArguments == null || e.OptionalArguments.Count == 0)) { newObject = new Default(e.Source, dt); } else { dt.PopulateMembers(); Constructor ctor; Expression[] args; if (!TryResolveConstructorOverload(e.Source, dt.Constructors, e.OptionalArguments ?? AstArgument.Empty, out ctor, out args)) { return(e.OptionalArguments != null && e.OptionalArguments.Count > 0 ? (dt.Constructors.Count == 1 ? Error(e.Source, ErrorCode.E2009, "Call to " + (dt + PrintableParameterList(dt.Constructors[0].Parameters)).Quote() + " has some invalid arguments " + PrintableArgumentList(e.OptionalArguments)) : Error(e.Source, ErrorCode.E2009, dt.Quote() + " has no constructors matching the argument list " + PrintableArgumentList(e.OptionalArguments) + NameResolver.SuggestCandidates(dt.Constructors))) : Error(e.Source, ErrorCode.E0000, dt.Quote() + " has no default constructor")); } newObject = new NewObject(e.Source, ctor, args); } if (e.OptionalCollectionInitializer != null && e.OptionalCollectionInitializer.Count > 0) { var var = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("collection"), newObject.ReturnType); CurrentVariableScope.Variables.Add(var.Name, var); Expression root = new StoreLocal(e.Source, var, newObject); // See if it is a member initializer or collection initializer var containsAssignOp = false; foreach (var i in e.OptionalCollectionInitializer) { if (i is AstBinary && (i as AstBinary).IsAssign) { containsAssignOp = true; break; } } if (containsAssignOp) { var initedMembers = new List <string>(); // Assign members foreach (var i in e.OptionalCollectionInitializer) { var binOp = i as AstBinary; if (binOp == null || binOp.Type != AstBinaryType.Assign || !(binOp.Left is AstIdentifier)) { Log.Error(i.Source, ErrorCode.E2077, "Invalid initalizer member declarator"); continue; } var id = (AstIdentifier)binOp.Left; var member = new AstMember(new AstIdentifier(i.Source, var.Name), id); if (binOp.Right is AstArrayInitializer) { var ai = binOp.Right as AstArrayInitializer; var collection = CompileExpression(member); var cvar = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType); CurrentVariableScope.Variables.Add(cvar.Name, cvar); root = new SequenceOp(root, new StoreLocal(collection.Source, cvar, collection)); if (collection.IsInvalid) { continue; } foreach (var ci in ai.Values) { root = new SequenceOp(root, CompileAddToCollection(cvar.Name, ci)); } } else { var assign = CompileAssign(new AstBinary(AstBinaryType.Assign, member, i.Source, binOp.Right)); root = new SequenceOp(root, assign); if (assign.IsInvalid) { continue; } } foreach (var m in initedMembers) { if (m == id.Symbol) { Log.Error(i.Source, ErrorCode.E2078, "Duplicate initialization of member " + id.Symbol.Quote()); break; } } initedMembers.Add(id.Symbol); } } else { // Add to collection foreach (var i in e.OptionalCollectionInitializer) { root = new SequenceOp(root, CompileAddToCollection(var.Name, i)); } } return(new SequenceOp(root, new LoadLocal(e.Source, var))); } if (e.OptionalType is AstBuiltinType && dt.IsStruct) { Log.Warning(e.Source, ErrorCode.W0000, "Redundant 'new' operator on builtin struct initialization"); } return(newObject); } return(Error(e.Source, ErrorCode.E2011, "Must provide argument list for object constructor")); } case TypeType.Delegate: { if (e.OptionalArguments == null) { return(Error(e.Source, ErrorCode.E0000, "Must provide argument list for delegate constructor")); } var args = CompileArgumentList(e.OptionalArguments); if (e.OptionalCollectionInitializer != null) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have collection initializer")); } if (e.OptionalArraySize != null) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have array size")); } if (args.Length != 1 || args[0].ExpressionType != ExpressionType.MethodGroup) { return(Error(e.Source, ErrorCode.E0000, "Delegate construction requires one method argument")); } return(CompileImplicitCast(e.Source, dt, args[0])); } case TypeType.Invalid: return(Expression.Invalid); default: return(Error(e.Source, ErrorCode.E2012, "Instances of type " + dt.Quote() + " cannot be created using 'new' because it is not a class, struct or array type")); } }
public override void Begin(ref Expression e, ExpressionUsage u) { switch (e.ExpressionType) { case ExpressionType.FixOp: { var s = (FixOp)e; GetIndirection(ref s.Operand); break; } case ExpressionType.AddressOf: { var s = (AddressOf)e; switch (s.AddressType) { case AddressType.Out: case AddressType.Ref: GetIndirection(ref s.Operand); break; } break; } case ExpressionType.StoreField: { var s = e as StoreField; OnObject(ref s.Object); break; } case ExpressionType.StoreElement: { var s = e as StoreElement; OnObject(ref s.Array); break; } case ExpressionType.StoreArgument: { Variable var; var s = e as StoreArgument; if (GetIndirection(s.Index, s.Parameter, out var)) { e = new StoreLocal(s.Source, var, s.Value); Begin(ref e, u); } else { VerifyPointer(s.Parameter, s.Value); } break; } case ExpressionType.LoadArgument: { Variable var; var s = e as LoadArgument; if (GetIndirection(s.Index, s.Parameter, out var)) { e = new LoadLocal(s.Source, var); Begin(ref e, u); } break; } case ExpressionType.StoreLocal: { var s = e as StoreLocal; VerifyPointer(s.Variable, s.Value); break; } case ExpressionType.LoadField: { var s = e as LoadField; OnObject(ref s.Object); break; } case ExpressionType.LoadElement: { var s = e as LoadElement; OnObject(ref s.Array); break; } case ExpressionType.AddListener: case ExpressionType.RemoveListener: case ExpressionType.GetProperty: case ExpressionType.SetProperty: case ExpressionType.CallMethod: case ExpressionType.CallDelegate: { var s = (CallExpression)e; OnObject(ref s.Object); if (!s.Function.ReturnType.IsVoid && ( Backend.IsConstrained(s.Function) || s.Object is Base && s.Function.IsVirtual) ) { s.Storage = new Variable(s.Source, Function, Type.GetUniqueIdentifier("ret"), s.Function.ReturnType, VariableType.Indirection); Variables.Add(s.Storage); } break; } case ExpressionType.NewDelegate: { var s = (NewDelegate)e; OnObject(ref s.Object); break; } case ExpressionType.NewArray: { var s = e as NewArray; // Structs with non-trivial copy-ctor cannot be passed through '...' (uInitArray<T>) if (s.Initializers != null && IsNonTrivialStruct(s.ArrayType.ElementType)) { var v = new Variable(s.Source, null, Type.GetUniqueIdentifier("array"), s.ReturnType); e = new StoreLocal(s.Source, v, new NewArray(s.Source, s.ArrayType, new Constant(s.Source, Essentials.Int, s.Initializers.Length))); for (int i = 0; i < s.Initializers.Length; i++) { e = new SequenceOp(e, new StoreElement(s.Source, new LoadLocal(s.Source, v), new Constant(s.Source, Essentials.Int, i), s.Initializers[i])); } e = new SequenceOp(e, new LoadLocal(s.Source, v)); } break; } } }
public override void Begin(ref Expression e, ExpressionUsage u) { CurrentExpression = e; switch (e.ExpressionType) { case ExpressionType.LoadArgument: { var s = e as LoadArgument; if (ParameterVariables[s.Index] != null) { e = new LoadLocal(s.Source, ParameterVariables[s.Index]); } break; } case ExpressionType.StoreArgument: { var s = e as StoreArgument; if (MustCopyType(s.Parameter.Type) && MustCopyValue(s.Value)) { e = Assign(new LoadArgument(s.Source, s.Function, s.Index), s.Value); } else if (ParameterVariables[s.Index] != null) { e = new StoreLocal(s.Source, ParameterVariables[s.Index], s.Value); } break; } case ExpressionType.StoreField: { var s = e as StoreField; OnObject(ref s.Object); if (MustCopyType(s.Field.ReturnType) && MustCopyValue(s.Value)) { e = Assign(new LoadField(s.Source, s.Object, s.Field), s.Value); } break; } case ExpressionType.StoreThis: { var s = e as StoreThis; e = Assign(new This(s.Source, s.ReturnType), s.Value); break; } case ExpressionType.StoreLocal: { var s = e as StoreLocal; if (MustCopyType(s.Variable.ValueType) && MustCopyValue(s.Value)) { e = Assign(new LoadLocal(s.Source, s.Variable), s.Value); } break; } case ExpressionType.StoreElement: { var s = e as StoreElement; if (MustCopyType(s.Array.ReturnType.ElementType) && MustCopyValue(s.Value)) { e = Assign(new LoadElement(s.Source, s.Array, s.Index), s.Value); } break; } case ExpressionType.CallMethod: { var s = e as CallMethod; if (MustCopyBeforeCall(s.Method)) { OnObject(ref s.Object); } break; } case ExpressionType.GetProperty: { var s = e as GetProperty; if (MustCopyBeforeCall(s.Property.GetMethod)) { OnObject(ref s.Object); } break; } case ExpressionType.SetProperty: { var s = e as SetProperty; if (MustCopyBeforeCall(s.Property.SetMethod)) { OnObject(ref s.Object); } break; } case ExpressionType.AddListener: { var s = e as AddListener; if (MustCopyBeforeCall(s.Event.AddMethod)) { OnObject(ref s.Object); } break; } case ExpressionType.RemoveListener: { var s = e as RemoveListener; if (MustCopyBeforeCall(s.Event.RemoveMethod)) { OnObject(ref s.Object); } break; } } ParentExpression = e; }