/// <summary> /// Creates a fresh local var of the given Type and adds it to the /// Bpl Implementation /// </summary> /// <param name="typeReference"> The type of the new variable </param> /// <returns> A fresh Variable with automatic generated name and location </returns> public Bpl.Variable CreateFreshLocal(ITypeReference typeReference) { Bpl.IToken loc = Bpl.Token.NoToken; // Helper Variables do not have a location Bpl.Type t = TranslationHelper.CciTypeToBoogie(typeReference); Bpl.LocalVariable v = new Bpl.LocalVariable(loc, new Bpl.TypedIdent(loc, TranslationHelper.GenerateTempVarName(), t)); ILocalDefinition dummy = new LocalDefinition(); // Creates a dummy entry for the Dict, since only locals in the dict are translated to boogie localVarMap.Add(dummy, v); return v; }
private INamedTypeDefinition GenerateTypeA(IUnitNamespace rootNamespace) { var nt = Host.NameTable; var typeA = new NamespaceTypeDefinition { ContainingUnitNamespace = rootNamespace, Name = nt.GetNameFor("A"), InternFactory = Host.InternFactory, IsClass = true }; var typeParameter = new GenericTypeParameter { Name = nt.GetNameFor("T"), InternFactory = Host.InternFactory, DefiningType = typeA, }; typeA.GenericParameters.Add(typeParameter); var baseGetMethod = new MethodDefinition { Name = nt.GetNameFor("Get"), IsCil = true, IsVirtual = true, Visibility = TypeMemberVisibility.Assembly, Type = typeParameter, ContainingTypeDefinition = typeA, InternFactory = Host.InternFactory, IsNewSlot = true }; typeA.Methods.Add(baseGetMethod); var il = new ILGenerator(Host); var localVar = new LocalDefinition { Type = typeParameter, Name = nt.GetNameFor("local1"), }; // tricky moment, ILGeneratorMethodBody fills internal collection of local vars only in constructor. // lines below should not be swapped il.AddVariableToCurrentScope(localVar); var body = new ILGeneratorMethodBody(il, true, 1) {MethodDefinition = baseGetMethod}; baseGetMethod.Body = body; il.Emit(OperationCode.Ldloca, localVar); il.Emit(OperationCode.Initobj, typeParameter); il.Emit(OperationCode.Ldloc_0); il.Emit(OperationCode.Ret); return typeA; }
protected override void VisitDeclarationSyntax(DeclarationSyntax pNode) { Visit(pNode.Value); var isTuple = pNode.Value.Type.IsTuple; for (int i = 0; i < pNode.Variables.Count; i++) { if (!SyntaxHelper.IsDiscard(pNode.Variables[i])) { if (_locals.IsVariableDefinedInScope(pNode.Variables[i].Value)) { CompilerErrors.IdentifierAlreadyDeclared(pNode.Variables[i], pNode.Span); } else { //We do not allow variables to have the same names as types //This makes it easier to check for "static" method/fields if (SmallTypeCache.IsTypeDefined(pNode.Variables[i].Value)) { CompilerErrors.ValueDefinedAsType(pNode.Variables[i], pNode.Variables[i].Span); } else { //For tuple types we set the individual variables to the tuple field type... not the tuple itself var t = isTuple ? pNode.Value.Type.GetFieldType(i) : pNode.Value.Type; //Report expression errors and change the type to Undefined so we don't get further no expression errors if (pNode.Value.Type == SmallTypeCache.NoValue) { CompilerErrors.ExpressionNoValue(pNode.Value.Span); t = SmallTypeCache.Undefined; } pNode.Variables[i].SetType(t); _locals.DefineVariableInScope(pNode.Variables[i].Value, LocalDefinition.Create(pNode.IsConst, pNode.Variables[i].Type)); } } } } //Check that we are declaring the proper number of variables if (isTuple && pNode.Value.Type.GetFieldCount() != pNode.Variables.Count) { CompilerErrors.DeclarationCountMismatch(pNode.Value.Type.GetFieldCount(), pNode.Variables.Count, pNode.Span); } }
protected override void RewriteStoreField(IOperation op) { var fieldReference = op.Value as IFieldReference; Contract.Assert(fieldReference != null); if (fieldReference.ContainingType.IsEnum == false) { var storeFieldCounter = new FieldReference() { Name = base.host.NameTable.GetNameFor(MemberHelper.GetMemberSignature(fieldReference, NameFormattingOptions.None) + "$$storeCount"), Type = base.host.PlatformType.SystemInt64, InternFactory = base.host.InternFactory, ContainingType = fieldReference.ContainingType, IsStatic = false }; // save the variable that is on the top of stack var name = "XXX_" + fieldReference.Name.ToString(); var def = new LocalDefinition { Name = base.host.NameTable.GetNameFor(name), Type = fieldReference.Type }; if (base.methodBody.LocalVariables == null) { base.methodBody.LocalVariables = new List <ILocalDefinition>(1); } base.methodBody.LocalVariables.Add(def); // store top-of-stack into a local. This is the value the stfld uses generator.Emit(OperationCode.Stloc, def); base.generator.Emit(OperationCode.Dup); // load "this" onto stack base.generator.Emit(OperationCode.Dup); // load "this" onto stack base.generator.Emit(OperationCode.Ldfld, storeFieldCounter); // load field$$storeCount onto stack base.generator.Emit(OperationCode.Ldc_I4_1); // load 1 onto stack base.generator.Emit(OperationCode.Conv_I8); // convert to int64 base.generator.Emit(OperationCode.Add); // add field$storeCount + 1 base.generator.Emit(OperationCode.Stfld, storeFieldCounter); // store result of add to field$$storeCount // restore the var we saved from the local generator.Emit(OperationCode.Ldloc, def); } // now do the original stfld base.RewriteStoreField(op); }
void EmitDisposeAndClean(CodeGenerator cg) { // enumerator.Dispose() if (_disposeMethod != null) { // TODO: if (enumerator != null) if (_enumeratorLoc.Type.IsValueType) { _enumeratorLoc.EmitLoadAddress(cg.Builder); } else { _enumeratorLoc.EmitLoad(cg.Builder); } cg.EmitCall(ILOpCode.Callvirt, _disposeMethod) .Expect(SpecialType.System_Void); } //// enumerator = null; //if (!_enumeratorLoc.Type.IsValueType) //{ // cg.Builder.EmitNullConstant(); // cg.Builder.EmitLocalStore(_enumeratorLoc); //} // if (_aliasedValueLoc != null) { cg.ReturnTemporaryLocal(_aliasedValueLoc); _aliasedValueLoc = null; } cg.ReturnTemporaryLocal(_enumeratorLoc); _enumeratorLoc = null; // unbind _moveNextMethod = null; _disposeMethod = null; _currentValue = null; _currentKey = null; _current = null; _iterator_next = null; }
protected override LocalDefinition DeclareLocalInternal( Microsoft.Cci.ITypeReference type, object identity, string name, bool isCompilerGenerated, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray <TypedConstant> dynamicTransformFlags) { LocalDefinition local; if (identity != null) { int slot = this.getPreviousLocalSlot(identity, type, constraints); if (slot >= 0) { Debug.Assert(this.allLocals[slot].Identity == null); local = new LocalDefinition( identity: identity, name: name, type: type, slot: slot, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals[slot] = local; return(local); } } local = new LocalDefinition( identity: identity, name: name, type: type, slot: this.allLocals.Count, isCompilerGenerated: isCompilerGenerated, constraints: constraints, isDynamic: isDynamic, dynamicTransformFlags: dynamicTransformFlags); this.allLocals.Add(local); return(local); }
protected override void VisitMemberAccessSyntax(MemberAccessSyntax pNode) { Visit(pNode.Identifier); //Save current local definitions //Mark the current type we are on so error messages can be more descriptive var l = _locals; using (var t = Store.AddValue("__Type", pNode.Identifier.Type)) { //If field doesn't exist or something went wrong, stop checking things to reduce redundant errors if (CurrentType != SmallTypeCache.Undefined) { //For methods and arrays we need to allow existing variables, but member access should only allow the struct's fields if (NeedToCopyLocals(pNode.Value)) { _locals = _locals.Copy(); } else { _locals = new ScopeCache <LocalDefinition>(); } //Namespaces return a null type if (CurrentType != null) { _locals.AddScope(); foreach (var f in CurrentType.GetFields()) { if (!_locals.IsVariableDefinedInScope(f.Name)) { _locals.DefineVariableInScope(f.Name, LocalDefinition.Create(false, f.Type)); } } } Visit(pNode.Value); } } //Restore local definitions Namespace = null; _locals = l; }
public void Dispose() { if (_loc != null) { _cg.ReturnTemporaryLocal(_loc); _loc = null; } else if (_tempName != null) { // <temporary>.RemoveKey(name) Debug.Assert(_cg.TemporalLocalsPlace != null); _cg.TemporalLocalsPlace.EmitLoad(_cg.Builder); _cg.EmitIntStringKey(_tempName); _cg.EmitPop(_cg.EmitCall(System.Reflection.Metadata.ILOpCode.Callvirt, _cg.CoreMethods.PhpArray.RemoveKey_IntStringKey)); _tempName = null; } }
private static void EmitUnicodeStringMarshalling(List <ILocalDefinition> locals, ILGenerator ilGenerator, IMethodReference getOffsetToStringData, ITypeReference stringType) { var pinnedLocal = new LocalDefinition { IsPinned = true, Type = stringType }; locals.Add(pinnedLocal); var nullCaseLabel = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Stloc, pinnedLocal); ilGenerator.Emit(OperationCode.Ldloc, pinnedLocal); ilGenerator.Emit(OperationCode.Conv_I); ilGenerator.Emit(OperationCode.Dup); ilGenerator.Emit(OperationCode.Brfalse_S, nullCaseLabel); ilGenerator.Emit(OperationCode.Call, getOffsetToStringData); ilGenerator.Emit(OperationCode.Add); ilGenerator.MarkLabel(nullCaseLabel); }
public LoadInterfaceMethodDataAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { if (context.GetConstantInReg("rcx") is {} castConstant && castConstant.Value is NewSafeCastResult castResult && context.GetConstantInReg("rdx") is {} interfaceConstant && interfaceConstant.Value is TypeDefinition interfaceType && context.GetConstantInReg("r8") is {} slotConstant && slotConstant.Value is int slot && context.Actions.FirstOrDefault(a => a is LocateSpecificInterfaceOffsetAction) is LocateSpecificInterfaceOffsetAction locator ) { _invokedOn = castResult.original; _interfaceType = interfaceType; _slotNumber = slot; resolvedMethod = SharedState.VirtualMethodsBySlot[(ushort)(locator._matchingInterfaceOffset.offset + _slotNumber)]; _resultConstant = context.MakeConstant(typeof(MethodDefinition), resolvedMethod, reg: "rax"); } }
private void PostprocessNonBlittableArrayArguments(IMethodDefinition methodDefinition, List <ILocalDefinition> locals, Dictionary <IParameterDefinition, ILocalDefinition> paramToLocalMap, ILGenerator ilGenerator) { bool hasReturnValue = methodDefinition.Type != this.host.PlatformType.SystemVoid; if (IsAnyParameterNonBlittableArray(methodDefinition)) { var retLocal = new LocalDefinition { IsPinned = false, Type = methodDefinition.Type }; if (hasReturnValue) { locals.Add(retLocal); ilGenerator.Emit(OperationCode.Stloc, retLocal); } var exitLabel = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Leave, exitLabel); ilGenerator.BeginFinallyBlock(); foreach (var elem in methodDefinition.Parameters) { ILocalDefinition t; if (paramToLocalMap.TryGetValue(elem, out t)) { ilGenerator.Emit(OperationCode.Ldloc, t); ilGenerator.Emit(OperationCode.Call, this.stringArrayMarshallingEpilog); // TODO: Generalize for other array types } } ilGenerator.Emit(OperationCode.Endfinally); ilGenerator.EndTryBody(); ilGenerator.MarkLabel(exitLabel); if (hasReturnValue) { ilGenerator.Emit(OperationCode.Ldloc, retLocal); } } }
private void PreprocessNonBlittableArrayArguments(List <ILocalDefinition> locals, Dictionary <IParameterDefinition, ILocalDefinition> paramToLocalMap, ILGenerator ilGenerator, int argumentCount, Func <int, IParameterDefinition> parameterProvider) { bool beginTryBody = false; for (int i = 0; i < argumentCount; ++i) { var parameter = parameterProvider(i); var arrayType = parameter.Type.ResolvedType as IArrayType; if (arrayType != null) { if (TypeHelper.TypesAreEquivalent(arrayType.ElementType, this.host.PlatformType.SystemString)) { var intPtrArrayType = new VectorTypeReference { ElementType = this.host.PlatformType.SystemIntPtr, Rank = 1 }.ResolvedArrayType; Ldarg(ilGenerator, parameter, i); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); // I guess this breaks in large gc array mode ilGenerator.Emit(OperationCode.Newarr, intPtrArrayType); // IntPtr[] var intPtrArray = new LocalDefinition { IsPinned = false, Type = intPtrArrayType }; locals.Add(intPtrArray); paramToLocalMap.Add(parameter, intPtrArray); ilGenerator.Emit(OperationCode.Stloc, intPtrArray); beginTryBody = true; } } } if (beginTryBody) { ilGenerator.BeginTryBody(); } }
public override ILocalDefinition Rewrite(ILocalDefinition localDefinition) { if (localDefinition.MethodDefinition != this.moveNext) // might happen to visit an already replaced local { return(localDefinition); } ILocalDefinition loc; if (!this.localTable.TryGetValue(localDefinition, out loc)) { loc = new LocalDefinition() { MethodDefinition = this.iterator, Name = localDefinition.Name, Type = localDefinition.Type, }; this.localTable.Add(localDefinition, loc); } return(loc); }
private void AddExpressionTemp(LocalDefinition temp) { // in some cases like stack locals, there is no slot allocated. if (temp == null) { return; } ArrayBuilder <LocalDefinition> exprTemps = _expressionTemps; if (exprTemps == null) { exprTemps = ArrayBuilder <LocalDefinition> .GetInstance(); _expressionTemps = exprTemps; } Debug.Assert(!exprTemps.Contains(temp)); exprTemps.Add(temp); }
private ILocalDefinition GetOrCreateLocal(int depth, ITypeReference type) { Contract.Requires(0 <= depth); Contract.Requires(type != null); ILocalDefinition local; var key = KeyForLocal(depth, type); if (this.createdLocals.TryGetValue(key, out local)) { return(local); } local = new LocalDefinition() { Name = this.host.NameTable.GetNameFor(NameForLocal(depth, type)), MethodDefinition = this.methodDefinition, Type = type, }; this.createdLocals.Add(key, local); return(local); }
public GraphRandomStateGenerator(IModule module, PeReader.DefaultHost host, Log.Log logger, CfgManipulator cfgManipulator, Helper helperClass, Graph.Graph graph, MethodCfg methodCfg, bool debugging) { this.module = module; this.host = host; this.logger = logger; this.cfgManipulator = cfgManipulator; this.helperClass = helperClass; this.graph = graph; this.methodCfg = methodCfg; this.debugging = debugging; // add local random generator variable this.tempRandomLocal = new LocalDefinition(); this.tempRandomLocal.IsReference = false; this.tempRandomLocal.IsPinned = false; this.tempRandomLocal.IsModified = false; this.tempRandomLocal.Type = this.helperClass.systemRandom; this.tempRandomLocal.MethodDefinition = methodCfg.method; cfgManipulator.addLocalVariable(this.tempRandomLocal); }
public CallVirtualMethodAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var inReg = context.GetOperandInRegister(Utils.GetRegisterNameNew(instruction.MemoryBase)); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) { return; } var classReadFrom = klass.backingType; var readOffset = instruction.MemoryDisplacement; Called = Utils.GetMethodFromReadKlassOffset((int)readOffset); if (Called == null) { return; } CalledOn = context.GetLocalInReg("rcx"); }
private static EncLocalInfo GetLocalInfo( IReadOnlyDictionary <SyntaxNode, int> declaratorToIndex, LocalDefinition localDef) { // Local symbol will be null for short-lived temporaries. var local = (LocalSymbol)localDef.Identity; if ((object)local != null) { var syntaxRefs = local.DeclaringSyntaxReferences; Debug.Assert(!syntaxRefs.IsDefault); if (!syntaxRefs.IsDefaultOrEmpty) { var syntax = syntaxRefs[0].GetSyntax(); var offset = declaratorToIndex[syntax]; return(new EncLocalInfo(offset, localDef.Type, localDef.Constraints, (int)local.TempKind)); } } return(new EncLocalInfo(localDef.Type, localDef.Constraints)); }
void EmitDisposeAndClean(CodeGenerator cg) { // enumerator.Dispose() if (_disposeMethod != null) { // TODO: if (enumerator != null) if (_enumeratorLoc.Type.IsValueType) { cg.Builder.EmitLocalAddress(_enumeratorLoc); } else { cg.Builder.EmitLocalLoad(_enumeratorLoc); } cg.EmitCall(CallOpCode(_disposeMethod, (TypeSymbol)_enumeratorLoc.Type), _disposeMethod) .Expect(SpecialType.System_Void); } //// enumerator = null; //if (!_enumeratorLoc.Type.IsValueType) //{ // cg.Builder.EmitNullConstant(); // cg.Builder.EmitLocalStore(_enumeratorLoc); //} // cg.ReturnTemporaryLocal(_enumeratorLoc); _enumeratorLoc = null; // unbind _moveNextMethod = null; _disposeMethod = null; _currentValue = null; _currentKey = null; _current = null; }
static void AddAllRecipes() { string[] itemHashes = File.ReadAllLines("ItemHashes.txt"); // Item hash text file dump, one item hash per line FunctionDefinition function = CreateFunction(@"_\kyle873\AddAllRecipes.script", "AddAllRecipes"); Label endLabel = cg.DefineLabel(); ParameterDefinition gi = CreateParam(function, "gameInstance", function, gameInstance); LocalDefinition type = CreateLocal(function, "type", function, stringNative); LocalDefinition amount = CreateLocal(function, "amount", function, stringNative); OpAssign(amount, "1"); foreach (string hash in itemHashes.Where(h => h.Contains("Recipe"))) { OpAssign(type, hash); OpCall(endLabel, giveItem, gi, type, amount); } cg.MarkLabel(endLabel); cg.Emit(Opcode.Nop); function.Code.AddRange(cg.GetCode()); }
internal void EmitPrepare(CodeGenerator cg) { if (_currentValue != null && _aliasedValues && _currentValue.ReturnType == cg.CoreTypes.PhpAlias && cg.GeneratorStateMachineMethod == null) { _aliasedValueLoc = cg.GetTemporaryLocal(_currentValue.ReturnType, immediateReturn: false); cg.Builder.EmitNullConstant(); cg.Builder.EmitLocalStore(_aliasedValueLoc); } var nextedge = NextBlock.NextEdge as ForeachMoveNextEdge; if (_currentKey == null && nextedge.KeyVariable != null && !IsAPairValue(_current.ReturnType, out _, out _)) { // KeyVariable will be iterated from 1 _synthesizedIndexLoc = cg.GetTemporaryLocal(cg.CoreTypes.Long, true, immediateReturn: false); // Template: KeyVariable = 0; cg.Builder.EmitLongConstant(0L); _synthesizedIndexLoc.EmitStore(); } }
private static void EmitBlittableTypeArrayMarshalling(List <ILocalDefinition> locals, ILGenerator ilGenerator, IArrayType arrayType) { var nullCaseLabel = new ILGeneratorLabel(); // [0] T& pinned x var pinnedLocal = new LocalDefinition { IsPinned = true, IsReference = true, Type = arrayType.ElementType }; // [1] T[] V_1, var duplicatearray = new LocalDefinition { IsPinned = false, Type = arrayType }; locals.Add(pinnedLocal); locals.Add(duplicatearray); ilGenerator.Emit(OperationCode.Dup); ilGenerator.Emit(OperationCode.Stloc, duplicatearray); ilGenerator.Emit(OperationCode.Brfalse, nullCaseLabel); ilGenerator.Emit(OperationCode.Ldloc, duplicatearray); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); ilGenerator.Emit(OperationCode.Brfalse, nullCaseLabel); ilGenerator.Emit(OperationCode.Ldloc, duplicatearray); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Ldelema, arrayType.ElementType); ilGenerator.Emit(OperationCode.Stloc, pinnedLocal); ilGenerator.MarkLabel(nullCaseLabel); ilGenerator.Emit(OperationCode.Ldloc, pinnedLocal); ilGenerator.Emit(OperationCode.Conv_I); }
// this function generates code that sets the random state public List<IOperation> generateCodeSetRandomState(LocalDefinition intStateLocal) { List<IOperation> operations = new List<IOperation>(); operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, this.tempRandomLocal)); operations.Add(this.helperClass.createNewOperation(OperationCode.Ldc_I4, this.graph.graphValidPathCount)); operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.helperClass.systemRandomNext)); operations.Add(this.helperClass.createNewOperation(OperationCode.Stloc, intStateLocal)); // if debugging is activated => print used global state if (this.debugging) { operations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, "Current State: ")); operations.Add(this.helperClass.createNewOperation(OperationCode.Ldloca, intStateLocal)); operations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.int32ToString)); operations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, " (possible: 0 - " + (this.graph.graphValidPathCount - 1).ToString() + ")")); operations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.stringConcatThree)); operations.Add(this.helperClass.createNewOperation(OperationCode.Call, this.helperClass.systemConsoleWriteLine)); } return operations; }
ILocalDefinition addDeadLocal(string targetType) { LocalDefinition result = new LocalDefinition(); result.IsReference = result.IsPinned = result.IsModified = false; result.MethodDefinition = methodCfg.method; // Switch for local type (TODO: Support more). // Maybe create multiple variables of the same type to add diffusion (but add upper bound). INamespaceTypeReference type = null; switch (targetType) { case "System.Int32": type = host.PlatformType.SystemInt32; break; case "System.String": type = host.PlatformType.SystemString; break; case "System.Boolean": type = host.PlatformType.SystemBoolean; break; default: throw new ArgumentException("Cannot add dead local of unsupported type."); } // Add the new local variable to our method. result.Type = type; manipulator.addLocalVariable(result); // Initialize dead local variable in the method's first basic block according to its type. // TODO: This might be used to easily detect dead locals. Improve on this. var loadSequence = loadBogusParameter(type); loadSequence.Add(createNewOperation(OperationCode.Stloc, result)); methodCfg.startBasicBlock.operations.InsertRange(0, loadSequence); return(result); }
/// <summary> /// Returns a <see cref="LocalDefinition"/> previously obtained from <see cref="GetTemporaryLocal"/> to the /// pool of locals available for reuse. /// </summary> /// <param name="definition">The <see cref="LocalDefinition"/> to return to the pool.</param> public void ReturnTemporaryLocal(LocalDefinition /*!*/ definition) { _il.LocalSlotManager.FreeSlot(definition); }
private ILocalDefinition ExtractExceptionContainer(DecompiledBlock nestedBlock, ITypeReference exceptionType) { Contract.Requires(nestedBlock != null); Contract.Requires(exceptionType != null); Contract.Ensures(Contract.Result<ILocalDefinition>() != null); Contract.Assume(nestedBlock.Statements.Count > 0); int i = 0; while (nestedBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < nestedBlock.Statements.Count); }; var firstStatement = nestedBlock.Statements[i++]; var firstBlock = firstStatement as DecompiledBlock; while (firstBlock != null) { Contract.Assume(firstBlock.Statements.Count > 0); i = 0; while (firstBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < firstBlock.Statements.Count); }; firstStatement = firstBlock.Statements[i++]; nestedBlock = firstBlock; firstBlock = firstStatement as DecompiledBlock; } //Ignoring any local declarations inserted for lexical scopes, any decompiled block that does not start with a nested block, starts with a label. Contract.Assume(firstStatement is LabeledStatement); if (nestedBlock.Statements.Count > i) { var exprStatement = nestedBlock.Statements[i] as ExpressionStatement; if (exprStatement != null) { nestedBlock.Statements.RemoveRange(i-1, 2); if (exprStatement.Expression is PopValue) return Dummy.LocalVariable; var assignment = exprStatement.Expression as Assignment; if (assignment != null && assignment.Source is PopValue) { var local = assignment.Target.Definition as ILocalDefinition; if (local != null) return local; //if not, this is not a recognized code pattern. } } // can't find the local, so just introduce one and leave its value on the stack var ld = new LocalDefinition() { Type = exceptionType, }; var pushStatement = new PushStatement() { ValueToPush = new BoundExpression() { Definition = ld, Type = exceptionType, }, }; nestedBlock.Statements.Insert(0, pushStatement); return ld; } else { //Valid IL should always have at least one instruction to consume the exception value as well as a branch out of the handler block. Contract.Assume(false); return Dummy.LocalVariable; } }
ILocalDefinition addDeadLocal(string targetType) { LocalDefinition result = new LocalDefinition(); result.IsReference = result.IsPinned = result.IsModified = false; result.MethodDefinition = methodCfg.method; // Switch for local type (TODO: Support more). // Maybe create multiple variables of the same type to add diffusion (but add upper bound). INamespaceTypeReference type = null; switch(targetType) { case "System.Int32": type = host.PlatformType.SystemInt32; break; case "System.String": type = host.PlatformType.SystemString; break; case "System.Boolean": type = host.PlatformType.SystemBoolean; break; default: throw new ArgumentException("Cannot add dead local of unsupported type."); } // Add the new local variable to our method. result.Type = type; manipulator.addLocalVariable(result); // Initialize dead local variable in the method's first basic block according to its type. // TODO: This might be used to easily detect dead locals. Improve on this. var loadSequence = loadBogusParameter(type); loadSequence.Add(createNewOperation(OperationCode.Stloc, result)); methodCfg.startBasicBlock.operations.InsertRange(0, loadSequence); return result; }
public override ILocalDefinition Rewrite(ILocalDefinition localDefinition) { if (localDefinition.MethodDefinition/*.InternedKey*/ == this.sourceMethod/*.InternedKey*/) { ILocalDefinition alreadyReparentedLocal; if (!this.newLocals.TryGetValue(localDefinition, out alreadyReparentedLocal)) { var ld = new LocalDefinition() { MethodDefinition = this.targetMethod, Name = localDefinition.Name, Type = localDefinition.Type, }; this.newLocals.Add(localDefinition, ld); alreadyReparentedLocal = ld; } return alreadyReparentedLocal; } return localDefinition; }
/// <summary> /// Rewrites the children of the specified local definition. /// </summary> /// <param name="localDefinition"></param> public override void RewriteChildren(LocalDefinition localDefinition) { if (localDefinition.MethodDefinition.InternedKey == this.targetMethod.InternedKey) localDefinition.MethodDefinition = this.sourceMethod; base.RewriteChildren(localDefinition); }
protected override void EmitOperation(IOperation operation) { if (operation.Offset <= this.lastOffset) { if (this.parent.IsCallToContractMethod(operation)) { EmitContractCall(operation); } else { base.EmitOperation(operation); } if (!this.moveNextMethod && operation.Offset == this.lastOffset) { #region All done: add return statement if (this.parent.currentMethod.Type.TypeCode != PrimitiveTypeCode.Void) { var ld = new LocalDefinition() { Type = this.parent.currentMethod.Type, }; base.EmitOperation(new Operation() { OperationCode = OperationCode.Ldloc, Value = ld, }); base.TrackLocal(ld); } base.EmitOperation(new Operation() { OperationCode = OperationCode.Ret, }); #endregion All done: add return statement } } }
public override IStatement Rewrite(IForEachStatement forEachStatement) { ILocalDefinition foreachLocal; var key = forEachStatement.Collection.Type.InternedKey; ITypeReference enumeratorType; IMethodReference getEnumerator; IMethodReference getCurrent; var gtir = forEachStatement.Collection.Type as IGenericTypeInstanceReference; if (gtir != null) { var typeArguments = gtir.GenericArguments; ITypeReference genericEnumeratorType = new Immutable.GenericTypeInstanceReference(this.host.PlatformType.SystemCollectionsGenericIEnumerator, typeArguments, this.host.InternFactory); ITypeReference genericEnumerableType = new Immutable.GenericTypeInstanceReference(this.host.PlatformType.SystemCollectionsGenericIEnumerable, typeArguments, this.host.InternFactory); enumeratorType = genericEnumeratorType; getEnumerator = new SpecializedMethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = genericEnumerableType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List <IParameterTypeInformation>(), Type = genericEnumeratorType, UnspecializedVersion = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = this.host.PlatformType.SystemCollectionsGenericIEnumerable, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List <IParameterTypeInformation>(), Type = this.host.PlatformType.SystemCollectionsGenericIEnumerator, }, }; var getEnumerator2 = (IMethodReference) IteratorHelper.First(genericEnumerableType.ResolvedType.GetMembersNamed(this.host.NameTable.GetNameFor("GetEnumerator"), false)); getEnumerator = getEnumerator2; getCurrent = (IMethodReference)IteratorHelper.First(genericEnumeratorType.ResolvedType.GetMembersNamed(this.host.NameTable.GetNameFor("get_Current"), false)); } else { enumeratorType = this.host.PlatformType.SystemCollectionsIEnumerator; getEnumerator = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = enumeratorType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List <IParameterTypeInformation>(), Type = this.host.PlatformType.SystemCollectionsIEnumerable, }; getCurrent = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = enumeratorType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("get_Current"), Parameters = new List <IParameterTypeInformation>(), Type = this.host.PlatformType.SystemObject, }; } var initializer = new MethodCall() { Arguments = new List <IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = getEnumerator, ThisArgument = forEachStatement.Collection, Type = enumeratorType, }; IStatement initialization; if (!this.foreachLocals.TryGetValue(key, out foreachLocal)) { foreachLocal = new LocalDefinition() { Type = enumeratorType, Name = this.host.NameTable.GetNameFor("CS$5$" + this.foreachLocals.Count) }; this.foreachLocals.Add(key, foreachLocal); initialization = new LocalDeclarationStatement() { InitialValue = initializer, LocalVariable = foreachLocal, }; } else { initialization = new ExpressionStatement() { Expression = new Assignment() { Source = initializer, Target = new TargetExpression() { Definition = foreachLocal, Instance = null, Type = foreachLocal.Type, }, Type = foreachLocal.Type, }, }; } var newStmts = new List <IStatement>(); newStmts.Add(new ExpressionStatement() { Expression = new Assignment() { Source = new MethodCall() { Arguments = new List <IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = getCurrent, ThisArgument = new BoundExpression() { Definition = foreachLocal, Instance = null, }, Type = forEachStatement.Variable.Type, }, Target = new TargetExpression() { Definition = forEachStatement.Variable, Instance = null, }, Type = forEachStatement.Variable.Type, }, }); newStmts.Add(forEachStatement.Body); var newBody = new BlockStatement() { Statements = newStmts, }; var result = new BlockStatement() { Statements = new List <IStatement>() { initialization, new TryCatchFinallyStatement() { TryBody = new BlockStatement() { Statements = new List <IStatement>() { new WhileDoStatement() { Body = newBody, Condition = new MethodCall() { Arguments = new List <IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = moveNext, ThisArgument = new BoundExpression() { Definition = foreachLocal, Instance = null, }, Type = this.host.PlatformType.SystemBoolean, }, }, }, }, FinallyBody = new BlockStatement() { Statements = new List <IStatement>() { new ConditionalStatement() { Condition = new Equality() { LeftOperand = new BoundExpression() { Definition = foreachLocal, Instance = null, Type = foreachLocal.Type, }, RightOperand = new CompileTimeConstant() { Type = foreachLocal.Type, Value = null, }, Type = this.host.PlatformType.SystemBoolean, }, FalseBranch = new EmptyStatement(), TrueBranch = new ExpressionStatement() { Expression = new MethodCall() { Arguments = new List <IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = this.disposeMethod, ThisArgument = new BoundExpression() { Definition = foreachLocal, Instance = null, }, Type = this.host.PlatformType.SystemVoid, }, }, }, }, }, }, }, }; return(result); }
private void addOpaquePredicatesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Opaque Predicates): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // process all entry branches of the current basic block List<IBranchTarget> copiedBranchList = new List<IBranchTarget>(currentBasicBlock.entryBranches); foreach (IBranchTarget entryBranch in copiedBranchList) { // get the metadata for the source basic block of the entry branch BasicBlock sourceBasicBlock = entryBranch.sourceBasicBlock; IGraphTransformerMetadata sourceMetadata = null; for (int i = 0; i < sourceBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((sourceBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } sourceMetadata = (sourceBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata); break; } if (sourceMetadata == null) { throw new ArgumentException("Not able to find metadata for source basic block of the entry branch."); } // only process entry branches with only one link to the obfuscation graph if (sourceMetadata.correspondingGraphNodes.Count() != 1) { continue; } // check if the source basic block is a basic block that moves the pointer to the obfuscation graph // => use the link from the current basic block to the obfuscation graph BasicBlockGraphNodeLink link = null; if ((sourceMetadata as GraphTransformerNextNodeBasicBlock) != null) { // get the metadata for the current basic block (because the source basic block has moved the pointer to the obfuscation graph) IGraphTransformerMetadata currentMetadata = null; for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) { // get graph transformer metadata for basic blocks if ((currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) { continue; } currentMetadata = (currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata); break; } if (currentMetadata == null) { throw new ArgumentException("Not able to find metadata for source basic block of the entry branch."); } // when current basic block also moves the pointer to the obfuscation graph => skip opaque predicate insertion it (for the moment) // (problem with obfuscation graph nodes that do not reside on the vpath because of pointer correction code) if ((currentMetadata as GraphTransformerNextNodeBasicBlock) != null) { continue; } // get the link to the correct obfuscation graph node for the valid path that goes through the source basic block BasicBlockGraphNodeLink sourceLink = sourceMetadata.correspondingGraphNodes.ElementAt(0); foreach (BasicBlockGraphNodeLink tempLink in currentMetadata.correspondingGraphNodes) { if (tempLink.validPathId == sourceLink.validPathId) { link = tempLink; } } if (link == null) { throw new ArgumentException("Not able to find link from current basic block to the obfuscation graph."); } } // => just use the link from the source basic block to the obfuscation graph else { link = sourceMetadata.correspondingGraphNodes.ElementAt(0); } // decide randomly to add an opaque predicate switch (this.prng.Next(this.insertOpaquePredicateWeight)) { case 0: case 1: case 2: case 3: case 4: case 5: { // choose randomly which opaque predicate should be added int opaquePredicate = this.prng.Next(2); this.injectOpaquePredicateCode(cfgManipulator, methodCfg, currentBasicBlock, entryBranch, link, opaquePredicate, currentNodeLocal); break; } default: { break; } } } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Opaque Predicates): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
protected override void RewriteStoreField(IOperation op) { var fieldReference = op.Value as IFieldReference; Contract.Assert(fieldReference != null); if (fieldReference.ContainingType.IsEnum == false) { var storeFieldCounter = new FieldReference() { Name = base.host.NameTable.GetNameFor(MemberHelper.GetMemberSignature(fieldReference, NameFormattingOptions.None) + "$$storeCount"), Type = base.host.PlatformType.SystemInt64, InternFactory = base.host.InternFactory, ContainingType = fieldReference.ContainingType, IsStatic = false }; // save the variable that is on the top of stack var name = "XXX_" + fieldReference.Name.ToString(); var def = new LocalDefinition { Name = base.host.NameTable.GetNameFor(name), Type = fieldReference.Type }; if (base.methodBody.LocalVariables == null) base.methodBody.LocalVariables = new List<ILocalDefinition>(1); base.methodBody.LocalVariables.Add(def); // store top-of-stack into a local. This is the value the stfld uses generator.Emit(OperationCode.Stloc, def); base.generator.Emit(OperationCode.Dup); // load "this" onto stack base.generator.Emit(OperationCode.Dup); // load "this" onto stack base.generator.Emit(OperationCode.Ldfld, storeFieldCounter); // load field$$storeCount onto stack base.generator.Emit(OperationCode.Ldc_I4_1); // load 1 onto stack base.generator.Emit(OperationCode.Conv_I8); // convert to int64 base.generator.Emit(OperationCode.Add); // add field$storeCount + 1 base.generator.Emit(OperationCode.Stfld, storeFieldCounter); // store result of add to field$$storeCount // restore the var we saved from the local generator.Emit(OperationCode.Ldloc, def); } // now do the original stfld base.RewriteStoreField(op); }
private ILocalDefinition ExtractExceptionContainer(DecompiledBlock nestedBlock, ITypeReference exceptionType) { Contract.Requires(nestedBlock != null); Contract.Requires(exceptionType != null); Contract.Ensures(Contract.Result <ILocalDefinition>() != null); Contract.Assume(nestedBlock.Statements.Count > 0); int i = 0; while (nestedBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < nestedBlock.Statements.Count); } ; var firstStatement = nestedBlock.Statements[i++]; var firstBlock = firstStatement as DecompiledBlock; while (firstBlock != null) { Contract.Assume(firstBlock.Statements.Count > 0); i = 0; while (firstBlock.Statements[i] is LocalDeclarationStatement) { i++; Contract.Assume(i < firstBlock.Statements.Count); } ; firstStatement = firstBlock.Statements[i++]; nestedBlock = firstBlock; firstBlock = firstStatement as DecompiledBlock; } //Ignoring any local declarations inserted for lexical scopes, any decompiled block that does not start with a nested block, starts with a label. Contract.Assume(firstStatement is LabeledStatement); if (nestedBlock.Statements.Count > i) { var exprStatement = nestedBlock.Statements[i] as ExpressionStatement; if (exprStatement != null) { nestedBlock.Statements.RemoveRange(i - 1, 2); if (exprStatement.Expression is PopValue) { return(Dummy.LocalVariable); } var assignment = exprStatement.Expression as Assignment; if (assignment != null && assignment.Source is PopValue) { var local = assignment.Target.Definition as ILocalDefinition; if (local != null) { return(local); //if not, this is not a recognized code pattern. } } } // can't find the local, so just introduce one and leave its value on the stack var ld = new LocalDefinition() { Type = exceptionType, }; var pushStatement = new PushStatement() { ValueToPush = new BoundExpression() { Definition = ld, Type = exceptionType, }, }; nestedBlock.Statements.Insert(0, pushStatement); return(ld); } else { //Valid IL should always have at least one instruction to consume the exception value as well as a branch out of the handler block. Contract.Assume(false); return(Dummy.LocalVariable); } }
/// <summary> /// The source expression "new C(){ f1 = e1, f2 = e2, ... }" (where the f's can be fields /// or properties) turns into "cgl = new C(); cgl.f1 = e1; cg1.f2 = e2; ...". /// ("cgl" means "compiler-generated local".) /// Turn it into a block expression whose Statements are the statements above (but where /// the first one becomes a local declaration statement), and with an Expression that is /// just the local, cgl', where cgl' is a freshly created local. /// </summary> private bool ReplaceCompilerGeneratedLocalUsedForInitializersPattern(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count - 1; i++) { var expressionStatement = statements[i] as ExpressionStatement; if (expressionStatement == null) continue; var assignment = expressionStatement.Expression as Assignment; if (assignment == null) continue; var local = assignment.Target.Definition as ILocalDefinition; if (local == null || local is CapturedLocalDefinition) continue; if (this.numberOfAssignmentsToLocal[local] != 1) continue; if (this.sourceLocationProvider != null) { bool isCompilerGenerated; var sourceName = this.sourceLocationProvider.GetSourceNameFor(local, out isCompilerGenerated); if (!isCompilerGenerated) continue; } var createObject = assignment.Source as ICreateObjectInstance; if (createObject == null) continue; if (!this.singleUseExpressionChecker.ExpressionCanBeMovedAndDoesNotReference(assignment.Source, local)) continue; var j = 1; while (i + j < statements.Count - 1 && IsAssignmentToFieldOrProperty(local, statements[i + j])) j++; if (j == 1) continue; if (this.numberOfReferencesToLocal[local] != (uint)j) continue; Contract.Assume(i + j < statements.Count); //i < statements.Count-1 and (j == 1 or the loop above established i+j < statements.Count-1) Contract.Assume(statements[i + j] != null); if (LocalFinder.LocalOccursIn(statements[i+j], local) && this.singleAssignmentReferenceFinder.LocalCanBeReplacedIn(statements[i + j], local)) { var newLocal = new LocalDefinition() { Name = this.host.NameTable.GetNameFor(local.Name.Value + "_prime"), MethodDefinition = local.MethodDefinition, Type = local.Type, }; var lds = new LocalDeclarationStatement() { InitialValue = assignment.Source, LocalVariable = newLocal, }; var stmts = new List<IStatement>(j) { lds, }; var boundExpression = new BoundExpression() { Definition = newLocal, Instance = null, Type = newLocal.Type, }; foreach (var s in statements.GetRange(i + 1, j - 1)) { Contract.Assume(s != null); this.singleAssignmentLocalReplacer.Replace(boundExpression, local, s); stmts.Add(s); } var blockExpression = new BlockExpression() { BlockStatement = new BlockStatement() { Statements = stmts, }, Expression = new BoundExpression() { Definition = newLocal, Instance = null, Type = newLocal.Type, }, Type = newLocal.Type, }; if (this.singleAssignmentLocalReplacer.Replace(blockExpression, local, statements[i + j])) { this.numberOfAssignmentsToLocal[newLocal] = 1; this.numberOfReferencesToLocal[newLocal] = (uint)j; this.numberOfAssignmentsToLocal[local]--; this.numberOfReferencesToLocal[local] = 0; statements.RemoveRange(i, j); replacedPattern = true; } else Contract.Assume(false); // replacement should succeed since the combination of LocalOccursIn and LocalCanBeReplacedIn returned true } } return replacedPattern; }
public override ILocalDefinition Rewrite(ILocalDefinition localDefinition) { if (localDefinition.MethodDefinition != this.moveNext) // might happen to visit an already replaced local return localDefinition; ILocalDefinition loc; if (!this.localTable.TryGetValue(localDefinition, out loc)) { loc = new LocalDefinition() { MethodDefinition = this.iterator, Name = localDefinition.Name, Type = localDefinition.Type, }; this.localTable.Add(localDefinition, loc); } return loc; }
private void FindCapturedLocals(List<IStatement> statements) { ILocalDefinition/*?*/ locDef = null; IFieldReference/*?*/ fieldRef = null; INestedTypeReference/*?*/ closureType = null; int i = 0; while (i < statements.Count && closureType == null) { var statement = statements[i++]; var locDecl = statement as LocalDeclarationStatement; if (locDecl == null) { var exprStatement = statement as ExpressionStatement; if (exprStatement == null) continue; var assignment = exprStatement.Expression as Assignment; if (assignment == null) continue; if (!(assignment.Source is ICreateObjectInstance)) continue; locDef = assignment.Target.Definition as ILocalDefinition; if (locDef != null) closureType = UnspecializedMethods.AsUnspecializedNestedTypeReference(locDef.Type); else { fieldRef = assignment.Target.Definition as IFieldReference; if (fieldRef == null || !(assignment.Target.Instance is IThisReference)) continue; closureType = UnspecializedMethods.AsUnspecializedNestedTypeReference(fieldRef.Type); } } else { if (!(locDecl.InitialValue is ICreateObjectInstance)) continue; locDef = locDecl.LocalVariable; closureType = UnspecializedMethods.AsUnspecializedNestedTypeReference(locDef.Type); } } if (closureType == null) return; //REVIEW: need to avoid resolving types that are not defined in the module we are analyzing. ITypeReference t1 = UnspecializedMethods.AsUnspecializedTypeReference(closureType.ContainingType.ResolvedType); ITypeReference t2 = UnspecializedMethods.AsUnspecializedTypeReference(this.remover.containingType); if (!TypeHelper.TypesAreEquivalent(t1, t2)) { var nt2 = t2 as INestedTypeReference; if (nt2 == null || !TypeHelper.TypesAreEquivalent(t1, nt2.ContainingType)) return; } var resolvedClosureType = closureType.ResolvedType; if (!UnspecializedMethods.IsCompilerGenerated(resolvedClosureType)) return; //Check if this is an iterator creating its state class, rather than just a method creating a closure class foreach (var iface in resolvedClosureType.Interfaces) { if (TypeHelper.TypesAreEquivalent(iface, resolvedClosureType.PlatformType.SystemCollectionsIEnumerator)) return; } if (this.remover.sourceMethodBody.privateHelperTypesToRemove == null) this.remover.sourceMethodBody.privateHelperTypesToRemove = new List<ITypeDefinition>(); this.remover.sourceMethodBody.privateHelperTypesToRemove.Add(resolvedClosureType); if (locDef != null) this.remover.currentClosureLocals.Add(locDef, true); else { if (this.remover.sourceMethodBody.privateHelperFieldsToRemove == null) this.remover.sourceMethodBody.privateHelperFieldsToRemove = new Dictionary<IFieldDefinition, IFieldDefinition>(); var field = UnspecializedMethods.UnspecializedFieldDefinition(fieldRef.ResolvedField); this.remover.sourceMethodBody.privateHelperFieldsToRemove.Add(field, field); } if (resolvedClosureType.IsGeneric && this.remover.sourceMethodBody.MethodDefinition.IsGeneric) this.remover.genericParameterMapper = new GenericMethodParameterMapper(this.remover.host, this.remover.sourceMethodBody.MethodDefinition, resolvedClosureType); statements.RemoveAt(i - 1); // Walk the rest of the statements in the block (but *without* recursively // descending into them) looking for assignments that save local state into // fields in the closure. Such assignments do not belong in the method body. // // They were introduced by the compiler because the closure reads their value. // That is, such assignments are of the form: // closureLocal.f := e // where "e" is either "this", a local, a parameter, (corner case) a value not held in a local of the original program, // or another closureLocal (because sometimes the compiler generates code so // that one closure class has access to another one). // When the RHS expression is a local/parameter, then rely on a naming // convention that the field f has the same name as the local/parameter. // If it does not follow the naming convention, then the statement corresponds to // a real statement that was in the original method body. // // For each such assignment statement, delete it from the list of statements and // add "e" to the remover's table as the expression to replace all occurrences of // "closureLocal.f" throughout the method body. // // [Note on corner case: this seems to arise when a value occurs in an anonymous delegate that // isn't used outside of the anonymous delegate. // For instance: { ... var x = new Object(); M((args for lambda) => ... body of lambda contains a reference to x ...) ... } // where there are no occurrences of x in the rest of the method body. The compiler plays it safe and still treats x as a // captured local.] // for (int j = i - 1; j < statements.Count; j++) { if (statements[j] is IEmptyStatement) continue; IExpressionStatement/*?*/ es = statements[j] as IExpressionStatement; if (es == null) continue; IAssignment/*?*/ assignment = es.Expression as IAssignment; if (assignment == null) continue; IFieldReference/*?*/ closureField = assignment.Target.Definition as IFieldReference; if (closureField == null) { // check to see if it is of the form "loc := closureLocal". // I.e., a local has been introduced that is an alias for a local containing a closure instance. var targetLoc = this.TargetExpressionAsLocal(assignment.Target); var sourceLoc = this.ExpressionAsLocal(assignment.Source); if (targetLoc != null && sourceLoc != null && this.remover.currentClosureLocals.ContainsKey(sourceLoc)) { this.remover.currentClosureLocals.Add(targetLoc, true); statements.RemoveAt(j--); } continue; } var unspecializedClosureField = UnspecializedMethods.UnspecializedFieldReference(closureField); var closureFieldContainingType = UnspecializedMethods.AsUnspecializedNestedTypeReference(closureField.ContainingType); if (closureFieldContainingType == null) continue; if (!TypeHelper.TypesAreEquivalent(closureFieldContainingType, closureType)) continue; if (this.remover.capturedBinding.ContainsKey(unspecializedClosureField.InternedKey)) continue; var thisReference = assignment.Source as IThisReference; if (thisReference == null) { var/*?*/ binding = assignment.Source as IBoundExpression; //if (binding == null) { // //The closure is capturing a local that is defined in the block being closed over. Need to introduce the local. // var newLocal = new LocalDefinition() { // Name = closureField.Name, // Type = closureField.Type, // }; // var newLocalDecl = new LocalDeclarationStatement() { LocalVariable = newLocal, InitialValue = assignment.Source }; // statements[j] = newLocalDecl; // if (this.remover.sourceMethodBody.privateHelperFieldsToRemove == null) // this.remover.sourceMethodBody.privateHelperFieldsToRemove = new Dictionary<IFieldDefinition, IFieldDefinition>(); // this.remover.sourceMethodBody.privateHelperFieldsToRemove[unspecializedClosureField.ResolvedField] = unspecializedClosureField.ResolvedField; // this.remover.capturedBinding.Add(unspecializedClosureField.InternedKey, new BoundExpression() { Definition = newLocal, Type = newLocal.Type }); // continue; //} if (binding != null && (binding.Definition is IParameterDefinition || binding.Definition is ILocalDefinition)) { var p = binding.Definition as IParameterDefinition; if (p != null) { if (closureField.Name != p.Name) { continue; } else { this.remover.capturedBinding[unspecializedClosureField.InternedKey] = binding; } } else { // must be a local var l = binding.Definition as ILocalDefinition; if (closureField.Name != l.Name) { // Check to see if it is closureLocal.f := other_closure_local // If so, delete it. var sourceLoc = ExpressionAsLocal(assignment.Source); if (sourceLoc != null && (this.remover.currentClosureLocals.ContainsKey(sourceLoc) || this.exceptionContainer == sourceLoc)) { statements.RemoveAt(j--); if (this.exceptionContainer == sourceLoc) this.remover.capturedBinding[unspecializedClosureField.InternedKey] = binding; } continue; } else { this.remover.capturedBinding[unspecializedClosureField.InternedKey] = binding; } } } else if (binding != null && fieldRef != null) { //In this case the closure is inside an iterator and its closure fields get their values from iterator state class fields or expressions. //In the former case, arrange for all references to the closure field to become references to the corresponding iterator state field. //In the latter case, the loop below will introduce a local to hold the value of the expression and arrange for references to the closure //field to become a reference to the local. IFieldReference iteratorField = binding.Definition as IFieldReference; if (iteratorField != null && binding.Instance is IThisReference) { this.remover.capturedBinding[unspecializedClosureField.InternedKey] = binding; } else continue; } else if (binding != null) { //In this case the closure is inside another closure and the closure fields get their values from the fields of the outer closure. IFieldReference outerClosureField = binding.Definition as IFieldReference; if (outerClosureField != null && binding.Instance is IThisReference) { this.remover.capturedBinding[unspecializedClosureField.InternedKey] = binding; } else continue; } else { // Corner case: see note above LocalDefinition localDefinition = new LocalDefinition() { Name = closureField.ResolvedField.Name, Type = this.remover.genericParameterMapper == null ? closureField.Type : this.remover.genericParameterMapper.Visit(closureField.Type), }; LocalDeclarationStatement localDeclStatement = new LocalDeclarationStatement() { LocalVariable = localDefinition, InitialValue = assignment.Source, }; statements.Insert(j, localDeclStatement); j++; this.remover.capturedBinding[unspecializedClosureField.InternedKey] = new BoundExpression() { Definition = localDefinition }; if (this.remover.sourceMethodBody.privateHelperFieldsToRemove == null) this.remover.sourceMethodBody.privateHelperFieldsToRemove = new Dictionary<IFieldDefinition, IFieldDefinition>(); this.remover.sourceMethodBody.privateHelperFieldsToRemove[closureField.ResolvedField] = closureField.ResolvedField; } } else { this.remover.capturedBinding[unspecializedClosureField.InternedKey] = new BoundExpression() { Instance = thisReference }; } statements.RemoveAt(j--); } foreach (var field in closureType.ResolvedType.Fields) { if (this.remover.capturedBinding.ContainsKey(field.InternedKey)) continue; var newLocal = new LocalDefinition() { Name = field.Name, Type = this.remover.genericParameterMapper == null ? field.Type : this.remover.genericParameterMapper.Visit(field.Type), }; var newLocalDecl = new LocalDeclarationStatement() { LocalVariable = newLocal }; statements.Insert(i - 1, newLocalDecl); if (this.remover.sourceMethodBody.privateHelperFieldsToRemove == null) this.remover.sourceMethodBody.privateHelperFieldsToRemove = new Dictionary<IFieldDefinition, IFieldDefinition>(); this.remover.sourceMethodBody.privateHelperFieldsToRemove[field] = field; this.remover.capturedBinding.Add(field.InternedKey, new BoundExpression() { Definition = newLocal, Type = newLocal.Type }); } }
private ILocalDefinition PossiblyReplaceLocal(ILocalDefinition localDefinition) { ILocalDefinition localToUse; if (!this.tableForLocalDefinition.TryGetValue(localDefinition, out localToUse)) { localToUse = new LocalDefinition() { MethodDefinition = localDefinition.MethodDefinition, Name = this.host.NameTable.GetNameFor("loc" + counter), Type = localDefinition.Type, }; this.counter++; this.tableForLocalDefinition.Add(localDefinition, localToUse); this.tableForLocalDefinition.Add(localToUse, localToUse); // in case it gets encountered again this.localDeclarations.Add( new LocalDeclarationStatement() { InitialValue = null, LocalVariable = localToUse, }); } return localToUse ?? localDefinition; }
private ILocalDefinition GetOrCreateLocal(int depth, ITypeReference type) { Contract.Requires(0 <= depth); Contract.Requires(type != null); ILocalDefinition local; var key = KeyForLocal(depth, type); if (this.createdLocals.TryGetValue(key, out local)) return local; local = new LocalDefinition() { Name = this.host.NameTable.GetNameFor(NameForLocal(depth, type)), MethodDefinition = this.methodDefinition, Type = type, }; this.createdLocals.Add(key, local); return local; }
public override IExpression VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) { var e = this.Visit(node.Operand); switch (node.OperatorToken.Kind) { case SyntaxKind.MinusMinusToken: case SyntaxKind.PlusPlusToken: var stmts = new List <IStatement>(); var temp = new LocalDefinition() { MethodDefinition = this.method, Name = this.host.NameTable.GetNameFor("__temp" + LocalNumber()), Type = e.Type, }; stmts.Add( new LocalDeclarationStatement() { InitialValue = e, LocalVariable = temp, }); BinaryOperation bo; if (node.OperatorToken.Kind == SyntaxKind.MinusMinusToken) { bo = new Subtraction(); } else { bo = new Addition(); } object one = GetConstantOneOfMatchingTypeForIncrementDecrement(e.Type.ResolvedType); // REVIEW: Do we really need to resolve? bo.LeftOperand = e; bo.RightOperand = new CompileTimeConstant() { Type = e.Type, Value = one, }; bo.Type = e.Type; var assign = new Assignment() { Source = bo, Target = Helper.MakeTargetExpression(e), Type = e.Type, }; stmts.Add( new ExpressionStatement() { Expression = assign, }); var blockExpression = new BlockExpression() { BlockStatement = new BlockStatement() { Statements = stmts, }, Expression = new BoundExpression() { Definition = temp, Instance = null, Type = temp.Type }, Type = e.Type, }; return(blockExpression); default: throw new InvalidDataException("VisitPostfixUnaryExpression: unknown operator token '" + node.OperatorToken.ValueText); } }
public IEnumerable <IPrimarySourceLocation> GetPrimarySourceLocationsForDefinitionOf(ILocalDefinition localDefinition) { LocalDefinition locDef = localDefinition as LocalDefinition; return(Enumerable <IPrimarySourceLocation> .Empty); }
/// <summary> /// When given a method definition and a block of statements that represents the Block property of the body of the method /// this method returns a semantically equivalent SourceMethod with a body that no longer has any anonymous delegate expressions. /// The given block of statements is mutated in place. /// Any types that get defined in order to implement the body semantics are returned (null if no such types are defined). /// </summary> /// <param name="method">The method containing the block that is to be rewritten.</param> /// <param name="body">The block to be rewritten. /// The entire tree rooted at the block must be mutable and the nodes must not be shared with anything else.</param> public ICollection<ITypeDefinition>/*?*/ RemoveAnonymousDelegates(IMethodDefinition method, BlockStatement body) { this.method = method; var finder = new CapturedParameterAndLocalFinder(); finder.TraverseChildren(body); this.fieldReferencesForUseInsideAnonymousMethods = finder.captures; this.anonymousDelegatesThatCaptureLocalsOrParameters = finder.anonymousDelegatesThatCaptureLocalsOrParameters; this.anonymousDelegatesThatCaptureThis = finder.anonymousDelegatesThatCaptureThis; finder = null; var blockFinder = new ScopesWithCapturedLocalsFinder(this.fieldReferencesForUseInsideAnonymousMethods); blockFinder.TraverseChildren(body); this.scopesWithCapturedLocals = blockFinder.scopesWithCapturedLocals; blockFinder = null; this.fieldReferencesForUseInsideThisMethod = new Dictionary<object, IFieldReference>(this.fieldReferencesForUseInsideAnonymousMethods); this.GenerateTopLevelClosure(); if (this.currentClosureClass != null) { //declare a local to keep the parameter closure class var closureLocal = new LocalDefinition() { Type = this.currentClosureInstance, Name = this.host.NameTable.GetNameFor("CS$<>8__locals"+this.closureClasses.Count) }; this.currentClosureLocal = closureLocal; this.currentClosureObject = new BoundExpression() { Definition = closureLocal, Type = closureLocal.Type }; this.closureLocalInstances = new List<IExpression>(); this.closureLocalInstances.Add(this.currentClosureObject); this.scopesWithCapturedLocals.Remove(body); //otherwise it will introduce its own closure class if any of its locals were captured. this.RewriteChildren(body); //do this after rewriting so that parameter references are not rewritten into closure field references. this.InsertStatementsToAllocateAndInitializeTopLevelClosure(body); } else { this.RewriteChildren(body); } return this.closureClasses == null ? null : this.closureClasses.AsReadOnly(); }
/// <summary /> public override IStatement Rewrite(IForEachStatement forEachStatement) { ILocalDefinition foreachLocal; var key = forEachStatement.Collection.Type.InternedKey; ITypeReference enumeratorType; IMethodReference getEnumerator; IMethodReference getCurrent; var gtir = forEachStatement.Collection.Type as IGenericTypeInstanceReference; if (gtir != null) { var typeArguments = gtir.GenericArguments; ITypeReference genericEnumeratorType = new Immutable.GenericTypeInstanceReference(this.host.PlatformType.SystemCollectionsGenericIEnumerator, typeArguments, this.host.InternFactory); ITypeReference genericEnumerableType = new Immutable.GenericTypeInstanceReference(this.host.PlatformType.SystemCollectionsGenericIEnumerable, typeArguments, this.host.InternFactory); enumeratorType = genericEnumeratorType; getEnumerator = new SpecializedMethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = genericEnumerableType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List<IParameterTypeInformation>(), Type = genericEnumeratorType, UnspecializedVersion = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = this.host.PlatformType.SystemCollectionsGenericIEnumerable, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List<IParameterTypeInformation>(), Type = this.host.PlatformType.SystemCollectionsGenericIEnumerator, }, }; var getEnumerator2 = (IMethodReference) IteratorHelper.First(genericEnumerableType.ResolvedType.GetMembersNamed(this.host.NameTable.GetNameFor("GetEnumerator"), false)); getEnumerator = getEnumerator2; getCurrent = (IMethodReference) IteratorHelper.First(genericEnumeratorType.ResolvedType.GetMembersNamed(this.host.NameTable.GetNameFor("get_Current"), false)); } else { enumeratorType = this.host.PlatformType.SystemCollectionsIEnumerator; getEnumerator = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = enumeratorType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("GetEnumerator"), Parameters = new List<IParameterTypeInformation>(), Type = this.host.PlatformType.SystemCollectionsIEnumerable, }; getCurrent = new MethodReference() { CallingConvention = CallingConvention.HasThis, ContainingType = enumeratorType, InternFactory = this.host.InternFactory, Name = this.host.NameTable.GetNameFor("get_Current"), Parameters = new List<IParameterTypeInformation>(), Type = this.host.PlatformType.SystemObject, }; } var initializer = new MethodCall() { Arguments = new List<IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = getEnumerator, ThisArgument = forEachStatement.Collection, Type = enumeratorType, }; IStatement initialization; if (!this.foreachLocals.TryGetValue(key, out foreachLocal)) { foreachLocal = new LocalDefinition() { Type = enumeratorType, Name = this.host.NameTable.GetNameFor("CS$5$" + this.foreachLocals.Count) }; this.foreachLocals.Add(key, foreachLocal); initialization = new LocalDeclarationStatement() { InitialValue = initializer, LocalVariable = foreachLocal, }; } else { initialization = new ExpressionStatement() { Expression = new Assignment() { Source = initializer, Target = new TargetExpression() { Definition = foreachLocal, Instance = null, Type = foreachLocal.Type, }, Type = foreachLocal.Type, }, }; } var newStmts = new List<IStatement>(); newStmts.Add(new ExpressionStatement(){ Expression = new Assignment(){ Source = new MethodCall(){ Arguments = new List<IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = getCurrent, ThisArgument = new BoundExpression(){ Definition = foreachLocal, Instance = null, }, Type = forEachStatement.Variable.Type, }, Target = new TargetExpression(){ Definition = forEachStatement.Variable, Instance = null, }, Type = forEachStatement.Variable.Type, }, }); newStmts.Add(forEachStatement.Body); var newBody = new BlockStatement(){ Statements = newStmts,}; var result = new BlockStatement() { Statements = new List<IStatement>(){ initialization, new TryCatchFinallyStatement(){ TryBody = new BlockStatement() { Statements = new List<IStatement>(){ new WhileDoStatement(){ Body = newBody, Condition = new MethodCall(){ Arguments = new List<IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = moveNext, ThisArgument = new BoundExpression(){ Definition = foreachLocal, Instance = null, }, Type = this.host.PlatformType.SystemBoolean, }, }, }, }, FinallyBody = new BlockStatement() { Statements = new List<IStatement>(){ new ConditionalStatement(){ Condition = new Equality(){ LeftOperand = new BoundExpression(){ Definition = foreachLocal, Instance = null, Type = foreachLocal.Type, }, RightOperand = new CompileTimeConstant(){ Type = foreachLocal.Type, Value = null, }, Type = this.host.PlatformType.SystemBoolean, }, FalseBranch = new EmptyStatement(), TrueBranch = new ExpressionStatement(){ Expression = new MethodCall(){ Arguments = new List<IExpression>(), IsStaticCall = false, IsVirtualCall = true, MethodToCall = this.disposeMethod, ThisArgument = new BoundExpression(){ Definition = foreachLocal, Instance = null, }, Type = this.host.PlatformType.SystemVoid, }, }, }, }, }, }, }, }; return result; }
/// <summary> /// Rewrites the given assignment expression. /// </summary> public override IExpression Rewrite(IAssignment assignment) { var targetInstance = assignment.Target.Instance; var result = base.Rewrite(assignment); if (targetInstance == null && assignment.Target.Instance != null) { //The target now pushes something onto the stack that was not there before the rewrite. //It the right hand side uses the stack, then it will not see the stack it expected. //If so, we need to evaluate the right handside and squirrel it away in a temp before executing //the actual assignment. var popFinder = new PopFinder(); popFinder.Traverse(assignment.Source); if (popFinder.foundAPop) { var temp = new LocalDefinition() { Name = this.host.NameTable.GetNameFor("PopTemp"+this.popTempCounter++), Type = assignment.Source.Type }; var localDeclarationStatement = new LocalDeclarationStatement() { LocalVariable = temp, InitialValue = assignment.Source }; var blockStatement = new BlockStatement(); blockStatement.Statements.Add(localDeclarationStatement); Contract.Assume(assignment is Assignment); ((Assignment)assignment).Source = new BoundExpression() { Definition = temp, Type = temp.Type }; return new BlockExpression() { BlockStatement = blockStatement, Expression = assignment, Type = assignment.Type }; } } return result; }
internal override void Generate(CodeGenerator cg) { Debug.Assert(this.Enumeree != null); // get the enumerator, // bind actual MoveNext() and CurrentValue and CurrentKey // Template: using( // a) enumerator = enumeree.GetEnumerator() // b) enumerator = Operators.GetEnumerator(enumeree) // ) ... cg.EmitSequencePoint(this.Enumeree.PhpSyntax); var enumereeType = cg.Emit(this.Enumeree); Debug.Assert(enumereeType.SpecialType != SpecialType.System_Void); var getEnumeratorMethod = enumereeType.LookupMember <MethodSymbol>(WellKnownMemberNames.GetEnumeratorMethodName); TypeSymbol enumeratorType; if (enumereeType.IsEqualToOrDerivedFrom(cg.CoreTypes.PhpArray)) { cg.Builder.EmitBoolConstant(_aliasedValues); // PhpArray.GetForeachtEnumerator(bool) enumeratorType = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.GetForeachEnumerator_Boolean); } // TODO: IPhpEnumerable // TODO: Iterator else if (getEnumeratorMethod != null && getEnumeratorMethod.ParameterCount == 0 && enumereeType.IsReferenceType) { // enumeree.GetEnumerator() enumeratorType = cg.EmitCall(getEnumeratorMethod.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, getEnumeratorMethod); } else { cg.EmitConvertToPhpValue(enumereeType, 0); cg.Builder.EmitBoolConstant(_aliasedValues); cg.EmitCallerRuntimeTypeHandle(); // Operators.GetForeachEnumerator(PhpValue, bool, RuntimeTypeHandle) enumeratorType = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.GetForeachEnumerator_PhpValue_Bool_RuntimeTypeHandle); } // _current = enumeratorType.LookupMember <PropertySymbol>(WellKnownMemberNames.CurrentPropertyName); // TODO: Err if no Current _currentValue = enumeratorType.LookupMember <PropertySymbol>(_aliasedValues ? "CurrentValueAliased" : "CurrentValue"); _currentKey = enumeratorType.LookupMember <PropertySymbol>("CurrentKey"); _disposeMethod = enumeratorType.LookupMember <MethodSymbol>("Dispose", m => m.ParameterCount == 0 && !m.IsStatic); // _enumeratorLoc = cg.GetTemporaryLocal(enumeratorType); cg.Builder.EmitLocalStore(_enumeratorLoc); // bind methods _moveNextMethod = enumeratorType.LookupMember <MethodSymbol>(WellKnownMemberNames.MoveNextMethodName); // TODO: Err if there is no MoveNext() Debug.Assert(_moveNextMethod.ReturnType.SpecialType == SpecialType.System_Boolean); Debug.Assert(_moveNextMethod.IsStatic == false); if (_disposeMethod != null) { /* Template: try { body } finally { enumerator.Dispose } */ // try { cg.Builder.AssertStackEmpty(); cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); cg.Builder.OpenLocalScope(ScopeType.Try); // EmitBody(cg); // } cg.Builder.CloseLocalScope(); // /Try // finally { cg.Builder.OpenLocalScope(ScopeType.Finally); // enumerator.Dispose() & cleanup EmitDisposeAndClean(cg); // } cg.Builder.CloseLocalScope(); // /Finally cg.Builder.CloseLocalScope(); // /TryCatchFinally } else { EmitBody(cg); EmitDisposeAndClean(cg); } }
public TemporaryLocalDefinition(CodeGenerator cg, LocalDefinition loc) { _cg = cg; _loc = loc; _type = (TypeSymbol)loc.Type; }
//not defined in CLR v2. /// <summary> /// Saves the current closure fields. Allocates a new closure and updates the fields. Then calls the given delegate and /// restores the earlier state. /// </summary> private void AllocateClosureFor(object scope, List<IStatement> statements, Action rewriteScope) { Contract.Assume(!this.isInsideAnonymousMethod); var savedCurrentClosure = this.currentClosureClass; var savedCurrentClosureSelfInstance = this.currentClosureSelfInstance; var savedCurrentClosureInstance = this.currentClosureInstance; var savedCurrentClosureObject = this.currentClosureObject; var savedCurrentClosureLocal = this.currentClosureLocal; this.CreateClosureClass(); IFieldReference outerClosure = null; if (savedCurrentClosureLocal != null) { this.CreateClosureField(this.currentClosureSelfInstance, savedCurrentClosureSelfInstance, savedCurrentClosureInstance, savedCurrentClosureLocal.Name.Value); outerClosure = this.fieldReferencesForUseInsideThisMethod[this.currentClosureSelfInstance]; } var closureLocal = new LocalDefinition() { Type = this.currentClosureInstance, Name = this.host.NameTable.GetNameFor("CS$<>__locals"+this.closureClasses.Count) }; this.currentClosureObject = new BoundExpression() { Definition = closureLocal, Type = this.currentClosureInstance }; this.currentClosureLocal = closureLocal; if (this.closureLocalInstances == null) this.closureLocalInstances = new List<IExpression>(); this.closureLocalInstances.Add(this.currentClosureObject); rewriteScope(); statements.Insert(0, new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Definition = closureLocal, Type = closureLocal.Type }, Source = new CreateObjectInstance() { MethodToCall = this.GetReferenceToDefaultConstructor(this.currentClosureInstance), Type = currentClosureSelfInstance, } } }); if (outerClosure != null) { statements.Insert(1, new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Instance = new BoundExpression() { Definition = closureLocal }, Definition = outerClosure }, Source = new BoundExpression() { Definition = savedCurrentClosureLocal } } }); } this.currentClosureClass = savedCurrentClosure; this.currentClosureSelfInstance = savedCurrentClosureSelfInstance; this.currentClosureInstance = savedCurrentClosureInstance; this.currentClosureObject = savedCurrentClosureObject; this.currentClosureLocal = savedCurrentClosureLocal; }
private ILocalDefinition GetLocalWithSourceName(ILocalDefinition localDef) { if (this.sourceLocationProvider == null) return localDef; var mutableLocal = this.localMap[localDef]; if (mutableLocal != null) return mutableLocal; mutableLocal = localDef as LocalDefinition; if (mutableLocal == null) { mutableLocal = new LocalDefinition(); mutableLocal.Copy(localDef, this.host.InternFactory); } this.localMap.Add(localDef, mutableLocal); bool isCompilerGenerated; var sourceName = this.sourceLocationProvider.GetSourceNameFor(localDef, out isCompilerGenerated); if (sourceName != localDef.Name.Value) { mutableLocal.Name = this.host.NameTable.GetNameFor(sourceName); } return mutableLocal; }
private static void AddExecCommandSTS(CacheFile cache, SourceFileDefinition mySourceFile) { var gameInstanceNative = cache.GetNative("GameInstance"); var stringNative = cache.GetNative("String"); var inkMenuInstanceSwitchToScenarioClass = cache.GetClass("inkMenuInstance_SwitchToScenario"); /* Add a new definition for a native inkMenuInstance_SwitchToScenario since it doesn't exist * in the cache by default. It is actually defined by the game but none of the existing game * code uses it, so it's missing. */ var inkMenuInstanceSwitchToScenario = new NativeDefinition() { Name = "inkMenuInstance_SwitchToScenario", NativeType = NativeType.Complex, }; cache.Definitions.Add(inkMenuInstanceSwitchToScenario); // Add a new ref native for the previous native. var inkMenuInstanceSwitchToScenarioRef = new NativeDefinition() { Name = "ref:inkMenuInstance_SwitchToScenario", NativeType = NativeType.Handle, BaseType = inkMenuInstanceSwitchToScenario, }; cache.Definitions.Add(inkMenuInstanceSwitchToScenarioRef); // stuff we use in our custom function var stringToNameFunction = cache.GetFunction("StringToName"); var getUISystemFunction = cache.GetFunction("GameInstance", "GetUISystem"); var uiSystemClass = cache.GetClass("UISystem"); var queueEventFunction = uiSystemClass.GetFunction("QueueEvent"); var myFunction = new FunctionDefinition() { Name = "STS", Flags = FunctionFlags.IsStatic | FunctionFlags.IsExec | FunctionFlags.HasParameters | FunctionFlags.HasLocals | FunctionFlags.HasCode, SourceFile = mySourceFile, }; cache.Definitions.Add(myFunction); var myParameter0 = new ParameterDefinition() { Name = "gameInstance", Parent = myFunction, Type = gameInstanceNative, Flags = ParameterFlags.None, }; cache.Definitions.Add(myParameter0); myFunction.Parameters.Add(myParameter0); var myParameter1 = new ParameterDefinition() { Name = "name", Parent = myFunction, Type = stringNative, Flags = ParameterFlags.None, }; cache.Definitions.Add(myParameter1); myFunction.Parameters.Add(myParameter1); var myLocal0 = new LocalDefinition() { Name = "event", Parent = myFunction, Type = inkMenuInstanceSwitchToScenarioRef, Unknown28 = 0, }; cache.Definitions.Add(myLocal0); myFunction.Locals.Add(myLocal0); var cg = new CodeGenerator(); // event = new inkMenuInstance_SwitchToScenario cg.Emit(Opcode.Assign); { cg.Emit(Opcode.LocalVar, myLocal0); cg.Emit(Opcode.New, inkMenuInstanceSwitchToScenarioClass); } // event.Init(StringToName(name), 0) var afterEventContextLabel = cg.DefineLabel(); cg.Emit(Opcode.Context, afterEventContextLabel); { cg.Emit(Opcode.LocalVar, myLocal0); cg.Emit(Opcode.FinalFunc, afterEventContextLabel, 0, inkMenuInstanceSwitchToScenarioClass.Functions[0]); { // StringToName(name) var afterStringToNameLabel = cg.DefineLabel(); cg.Emit(Opcode.FinalFunc, afterStringToNameLabel, 0, stringToNameFunction); { cg.Emit(Opcode.ParamVar, myParameter1); cg.Emit(Opcode.ParamEnd); } cg.MarkLabel(afterStringToNameLabel); } cg.Emit(Opcode.Nop); cg.Emit(Opcode.ParamEnd); } cg.MarkLabel(afterEventContextLabel); // getUISystem(gameInstance).QueueEvent(event) var afterUISystemContextLabel = cg.DefineLabel(); cg.Emit(Opcode.Context, afterUISystemContextLabel); { var afterGetUISystemLabel = cg.DefineLabel(); cg.Emit(Opcode.FinalFunc, afterGetUISystemLabel, 0, getUISystemFunction); { cg.Emit(Opcode.ParamVar, myParameter0); cg.Emit(Opcode.ParamEnd); } cg.MarkLabel(afterGetUISystemLabel); cg.Emit(Opcode.FinalFunc, afterUISystemContextLabel, 0, queueEventFunction); { cg.Emit(Opcode.LocalVar, myLocal0); cg.Emit(Opcode.ParamEnd); } } cg.MarkLabel(afterUISystemContextLabel); cg.Emit(Opcode.Nop); myFunction.Code.AddRange(cg.GetCode()); }
/// <summary> /// Create the new body of the iterator method. /// </summary> /// <remarks> /// Pseudo code: /// iteratorClosureLocal = new Closure(0); /// iteratorClosureLocal.field = parameter; // for each parameter including this. /// return iteratorClosureLocal; /// </remarks> private BlockStatement CreateNewIteratorMethodBody(IteratorClosureInformation iteratorClosure) { BlockStatement result = new BlockStatement(); // iteratorClosureLocal = new IteratorClosure(0); LocalDefinition localDefinition = new LocalDefinition() { Name = this.host.NameTable.GetNameFor("iteratorClosureLocal"), Type = GetClosureTypeReferenceFromIterator(iteratorClosure), }; CreateObjectInstance createObjectInstance = new CreateObjectInstance() { MethodToCall = GetMethodReference(iteratorClosure, iteratorClosure.Constructor), Type = localDefinition.Type }; // the start state depends on whether the iterator is an IEnumerable or an IEnumerator. For the former, // it must be created in state -2. Then it is the GetEnumerator method that puts it into its // "start" state, i.e., state 0. var startState = this.isEnumerable ? -2 : 0; createObjectInstance.Arguments.Add(new CompileTimeConstant() { Value = startState, Type = this.host.PlatformType.SystemInt32 }); LocalDeclarationStatement localDeclarationStatement = new LocalDeclarationStatement() { InitialValue = createObjectInstance, LocalVariable = localDefinition }; result.Statements.Add(localDeclarationStatement); // Generate assignments to closure instance's fields for each of the parameters captured by the closure. foreach (object capturedLocalOrParameter in FieldForCapturedLocalOrParameter.Keys) { BoundField boundField = FieldForCapturedLocalOrParameter[capturedLocalOrParameter]; Assignment assignment; ITypeReference localOrParameterType = GetLocalOrParameterType(capturedLocalOrParameter); if (capturedLocalOrParameter is ILocalDefinition) continue; if (capturedLocalOrParameter is IThisReference) { var thisR = new ThisReference(); IExpression thisValue = thisR; if (!this.method.ContainingTypeDefinition.IsClass) { thisValue = new AddressDereference() { Address = thisR, Type = this.method.ContainingTypeDefinition.IsGeneric ? (ITypeReference)this.method.ContainingTypeDefinition.InstanceType : (ITypeReference)this.method.ContainingTypeDefinition }; } assignment = new Assignment { Source = thisValue, Type = this.method.ContainingType, Target = new TargetExpression() { Definition = GetFieldReference(iteratorClosure, boundField.Field), Type = this.method.ContainingType, Instance = new BoundExpression() { Type = localDefinition.Type, Instance = null, Definition = localDefinition, IsVolatile = false } }, }; } else { assignment = new Assignment { Source = new BoundExpression() { Definition = capturedLocalOrParameter, Instance = null, IsVolatile = false, Type = localOrParameterType }, Type = localOrParameterType, Target = new TargetExpression() { Definition = GetFieldReference(iteratorClosure, boundField.Field), Type = localOrParameterType, Instance = new BoundExpression() { Type = localDefinition.Type, Instance = null, Definition = localDefinition, IsVolatile = false } }, }; } ExpressionStatement expressionStatement = new ExpressionStatement() { Expression = assignment }; result.Statements.Add(expressionStatement); } // Generate: return iteratorClosureLocal; result.Statements.Add(new ReturnStatement() { Expression = new BoundExpression() { Definition = localDeclarationStatement.LocalVariable, Instance = null, Type = localDeclarationStatement.LocalVariable.Type } }); return result; }
delegate void Action(); //not defined in CLR v2. /// <summary> /// Saves the current closure fields. Allocates a new closure and updates the fields. Then calls the given delegate and /// restores the earlier state. /// </summary> private void AllocateClosureFor(object scope, List<IStatement> statements, Action rewriteScope) { Contract.Assume(!this.isInsideAnonymousMethod); var savedCurrentClosure = this.currentClosureClass; var savedCurrentClosureSelfInstance = this.currentClosureSelfInstance; var savedCurrentClosureInstance = this.currentClosureInstance; var savedCurrentClosureObject = this.currentClosureObject; var savedCurrentClosureLocal = this.currentClosureLocal; this.CreateClosureClass(); IFieldReference outerClosure = null; if (savedCurrentClosureLocal != null) { this.CreateClosureField(this.currentClosureSelfInstance, savedCurrentClosureSelfInstance, savedCurrentClosureInstance, savedCurrentClosureLocal.Name.Value); outerClosure = this.fieldReferencesForUseInsideThisMethod[this.currentClosureSelfInstance]; } var closureLocal = new LocalDefinition() { Type = this.currentClosureInstance, Name = this.host.NameTable.GetNameFor("CS$<>__locals"+this.closureClasses.Count) }; this.currentClosureObject = new BoundExpression() { Definition = closureLocal, Type = this.currentClosureInstance }; this.currentClosureLocal = closureLocal; if (this.closureLocalInstances == null) this.closureLocalInstances = new List<IExpression>(); this.closureLocalInstances.Add(this.currentClosureObject); rewriteScope(); Statement createClosure = new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Definition = closureLocal, Type = closureLocal.Type }, Source = new CreateObjectInstance() { MethodToCall = this.GetReferenceToDefaultConstructor(this.currentClosureInstance), Type = currentClosureSelfInstance, } } }; ILabeledStatement labeledStatement = null; for (int i = 0, n = statements.Count; i < n; i++) { labeledStatement = statements[i] as ILabeledStatement; if (labeledStatement != null) { createClosure = new LabeledStatement() { Label = labeledStatement.Label, Statement = createClosure }; createClosure.Locations.AddRange(labeledStatement.Locations); statements[i] = labeledStatement.Statement; break; } else if (statements[i] is IEmptyStatement) { continue; } else { var declSt = statements[i] as ILocalDeclarationStatement; if (declSt != null && declSt.InitialValue == null) continue; break; } } statements.Insert(0, createClosure); if (outerClosure != null) { statements.Insert(1, new ExpressionStatement() { Expression = new Assignment() { Target = new TargetExpression() { Instance = new BoundExpression() { Definition = closureLocal, Type = closureLocal.Type }, Definition = outerClosure, Type = closureLocal.Type }, Source = new BoundExpression() { Definition = savedCurrentClosureLocal, Type = savedCurrentClosureLocal.Type }, Type = closureLocal.Type, } }); } this.currentClosureClass = savedCurrentClosure; this.currentClosureSelfInstance = savedCurrentClosureSelfInstance; this.currentClosureInstance = savedCurrentClosureInstance; this.currentClosureObject = savedCurrentClosureObject; this.currentClosureLocal = savedCurrentClosureLocal; }
/// <summary> /// Create a mutable copy of a local definition. /// </summary> /// <param name="localDefinition"></param> /// <returns></returns> protected virtual LocalDefinition GetMutableCopy(ILocalDefinition localDefinition) { object cachedValue; if (this.cache.TryGetValue(localDefinition, out cachedValue)) { return (LocalDefinition)cachedValue; } var result = new LocalDefinition(); result.Copy(localDefinition, this.host.InternFactory); this.cache.Add(localDefinition, result); this.cache.Add(result, result); return result; }
// this function creates all methods that are needed for the generated graph public void createGraphMethods() { this.logger.writeLine("Adding graph methods to \"" + this.targetClass.ToString() + "\""); // check if the graph is already initialized (needed to create the methods) if (this.graph == null) { throw new ArgumentException("Graph is not initialized."); } // if debugging is activated // => add field for the basic block trace file if (this.debugging || this.trace) { this.logger.writeLine("Debugging activated: Adding field for a basic block tracer file"); // add trace writer field this.debuggingTraceWriter = new FieldDefinition(); this.debuggingTraceWriter.IsCompileTimeConstant = false; this.debuggingTraceWriter.IsNotSerialized = false; this.debuggingTraceWriter.IsReadOnly = false; this.debuggingTraceWriter.IsRuntimeSpecial = false; this.debuggingTraceWriter.IsSpecialName = false; this.debuggingTraceWriter.Type = this.helperClass.systemIOStreamWriter; this.debuggingTraceWriter.IsStatic = false; this.debuggingTraceWriter.Name = host.NameTable.GetNameFor("DEBUG_traceWriter"); this.debuggingTraceWriter.Visibility = TypeMemberVisibility.Public; this.debuggingTraceWriter.InternFactory = host.InternFactory; this.debuggingTraceWriter.ContainingTypeDefinition = this.targetClass; this.targetClass.Fields.Add(this.debuggingTraceWriter); } // create a method that can be called to generate the graph this.buildGraphMethod = this.helperClass.createNewMethod("buildGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO RENAME ILGenerator ilGenerator = new ILGenerator(host, this.buildGraphMethod); // check if graph was already build // => if it was jump to exit ILGeneratorLabel buildGraphExitLabel = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brfalse, buildGraphExitLabel); // set initial node (root of the tree) ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); // needed as argument for the constructor ilGenerator.Emit(OperationCode.Newobj, this.graph.startingNode.constructorToUse); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); // build rest of graph in a "pseudo recursive" manner MethodDefinition newMethodToCall = this.addNodeRecursively(this.graph.startingNode, 1, "addNode_0"); // TODO: method name ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Callvirt, newMethodToCall); // exit ilGenerator.MarkLabel(buildGraphExitLabel); ilGenerator.Emit(OperationCode.Ret); // create body IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.buildGraphMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); this.buildGraphMethod.Body = body; // create exchangeNodes method List<IParameterDefinition> parameters = new List<IParameterDefinition>(); // node type parameter ParameterDefinition parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); // int array parameter for path to node one VectorTypeReference intArrayType = new VectorTypeReference(); intArrayType.ElementType = this.host.PlatformType.SystemInt32; intArrayType.Rank = 1; intArrayType.IsFrozen = true; intArrayType.IsValueType = false; intArrayType.InternFactory = host.InternFactory; parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = intArrayType; parameters.Add(parameter); // int array parameter for path to node two parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = intArrayType; parameters.Add(parameter); this.exchangeNodesMethod = this.helperClass.createNewMethod("exchangeNodes", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO RENAME ilGenerator = new ILGenerator(host, this.exchangeNodesMethod); List<ILocalDefinition> localVariables = new List<ILocalDefinition>(); // create local integer variable needed for the loops LocalDefinition loopIntLocal = new LocalDefinition(); loopIntLocal.IsReference = false; loopIntLocal.IsPinned = false; loopIntLocal.IsModified = false; loopIntLocal.Type = this.host.PlatformType.SystemInt32; loopIntLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(loopIntLocal); // create local iNode variable needed for nodeOne LocalDefinition nodeOneLocal = new LocalDefinition(); nodeOneLocal.IsReference = false; nodeOneLocal.IsPinned = false; nodeOneLocal.IsModified = false; nodeOneLocal.Type = this.nodeInterface; nodeOneLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(nodeOneLocal); // create local iNode variable needed for prevNodeOne LocalDefinition prevNodeOneLocal = new LocalDefinition(); prevNodeOneLocal.IsReference = false; prevNodeOneLocal.IsPinned = false; prevNodeOneLocal.IsModified = false; prevNodeOneLocal.Type = this.nodeInterface; prevNodeOneLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeOneLocal); // create local integer variable needed for prevNodeOneIdx LocalDefinition prevNodeOneIdxLocal = new LocalDefinition(); prevNodeOneIdxLocal.IsReference = false; prevNodeOneIdxLocal.IsPinned = false; prevNodeOneIdxLocal.IsModified = false; prevNodeOneIdxLocal.Type = this.host.PlatformType.SystemInt32; prevNodeOneIdxLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeOneIdxLocal); // create local iNode variable needed for nodeTwo LocalDefinition nodeTwoLocal = new LocalDefinition(); nodeTwoLocal.IsReference = false; nodeTwoLocal.IsPinned = false; nodeTwoLocal.IsModified = false; nodeTwoLocal.Type = this.nodeInterface; nodeTwoLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(nodeTwoLocal); // create local iNode variable needed for prevNodeOne LocalDefinition prevNodeTwoLocal = new LocalDefinition(); prevNodeTwoLocal.IsReference = false; prevNodeTwoLocal.IsPinned = false; prevNodeTwoLocal.IsModified = false; prevNodeTwoLocal.Type = this.nodeInterface; prevNodeTwoLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeTwoLocal); // create local integer variable needed for prevNodeOneIdx LocalDefinition prevNodeTwoIdxLocal = new LocalDefinition(); prevNodeTwoIdxLocal.IsReference = false; prevNodeTwoIdxLocal.IsPinned = false; prevNodeTwoIdxLocal.IsModified = false; prevNodeTwoIdxLocal.Type = this.host.PlatformType.SystemInt32; prevNodeTwoIdxLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(prevNodeTwoIdxLocal); // create local iNode variable needed for temp LocalDefinition tempNodeLocal = new LocalDefinition(); tempNodeLocal.IsReference = false; tempNodeLocal.IsPinned = false; tempNodeLocal.IsModified = false; tempNodeLocal.Type = this.nodeInterface; tempNodeLocal.MethodDefinition = this.exchangeNodesMethod; localVariables.Add(tempNodeLocal); // initialize local variables /* iNode nodeOne = givenStartingNode; iNode prevNodeOne = null; int prevNodeOneIdx = 0; */ ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); ILGeneratorLabel loopConditionAndIncBranch = new ILGeneratorLabel(); ILGeneratorLabel loopConditionBranch = new ILGeneratorLabel(); ILGeneratorLabel loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop /* if (nodeOne.getNode(pathToNodeOne[i]) != null) { */ ilGenerator.MarkLabel(loopStartBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // get the node of the graph that should be exchanged (nodeOne) /* prevNodeOne = nodeOne; prevNodeOneIdx = pathToNodeOne[i]; nodeOne = nodeOne.getNode(pathToNodeOne[i]); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Stloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, nodeOneLocal); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < pathToNodeOne.Length; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // initialize local variables /* iNode nodeTwo = givenStartingNode; iNode prevNodeTwo = null; int prevNodeTwoIdx = 0; */ ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); loopConditionAndIncBranch = new ILGeneratorLabel(); loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop /* if (nodeTwo.getNode(pathToNodeTwo[i]) != null) { */ ilGenerator.MarkLabel(loopStartBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // get the node of the graph that should be exchanged (nodeTwo) /* prevNodeTwo = nodeTwo; prevNodeTwoIdx = pathToNodeTwo[i]; nodeTwo = nodeTwo.getNode(pathToNodeTwo[i]); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldelem_I4); ilGenerator.Emit(OperationCode.Stloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, nodeTwoLocal); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < pathToNodeTwo.Length; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldlen); ilGenerator.Emit(OperationCode.Conv_I4); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // initialize loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); loopConditionAndIncBranch = new ILGeneratorLabel(); loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of the code in the loop ilGenerator.MarkLabel(loopStartBranch); /* if (nodeOne.getNode(i) == nodeTwo) { */ ILGeneratorLabel conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brfalse, conditionBranch); /* nodeOne.setNode(nodeTwo.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeTwo.setNode(nodeOne, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch); /* else if (nodeTwo.getNode(i) == nodeOne) { */ ilGenerator.MarkLabel(conditionBranch); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ceq); conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brfalse, conditionBranch); /* nodeTwo.setNode(nodeOne.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeOne.setNode(nodeTwo, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, loopConditionAndIncBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* temp = nodeOne.getNode(i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Stloc, tempNodeLocal); /* nodeOne.setNode(nodeTwo.getNode(i), i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); /* nodeTwo.setNode(temp, i); */ ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, tempNodeLocal); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); // increment counter of loop ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, loopIntLocal); // loop condition /* for (int i = 0; i < GRAPH_DIMENSION; i++) { */ ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, loopIntLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); /* if (prevNodeOne != null) { */ conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, conditionBranch); /* if (prevNodeOne != nodeTwo) { */ ILGeneratorLabel exitConditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch); /* prevNodeOne.setNode(nodeTwo, prevNodeOneIdx); */ ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeOneIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, exitConditionBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* this.graphStartNode = nodeTwo; */ ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldloc, nodeTwoLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); ilGenerator.MarkLabel(exitConditionBranch); /* if (prevNodeTwo != null) { */ conditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldnull); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, conditionBranch); /* if (prevNodeTwo != nodeOne) { */ exitConditionBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ceq); ilGenerator.Emit(OperationCode.Brtrue, exitConditionBranch); /* prevNodeTwo.setNode(nodeOne, prevNodeTwoIdx); */ ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Ldloc, prevNodeTwoIdxLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesSet); ilGenerator.Emit(OperationCode.Br, exitConditionBranch); /* else { */ ilGenerator.MarkLabel(conditionBranch); /* this.graphStartNode = nodeOne; */ ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldloc, nodeOneLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerSet); ilGenerator.MarkLabel(exitConditionBranch); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.exchangeNodesMethod, localVariables, Enumerable<ITypeDefinition>.Empty); this.exchangeNodesMethod.Body = body; // check if debugging is activated // => add function to dump graph as .dot file if (this.debugging) { this.logger.writeLine("Debugging activated: Adding code to dump graph as .dot file"); // create dumpGraph method parameters = new List<IParameterDefinition>(); // string parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemString; parameter.Index = 0; parameters.Add(parameter); // node type parameter (current pointer of debug method) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 1; parameters.Add(parameter); // node type parameter (current pointer of caller) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 2; parameters.Add(parameter); this.debuggingDumpGraphMethod = this.helperClass.createNewMethod("DEBUG_dumpGraph", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // create dumpGraphRec method parameters = new List<IParameterDefinition>(); // stream writer parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.helperClass.systemIOStreamWriter; parameter.Index = 0; parameters.Add(parameter); // string parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemString; parameter.Index = 1; parameters.Add(parameter); // node type parameter (current pointer of debug method) parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameter.Index = 2; parameters.Add(parameter); // node type parameter (current pointer of caller) ParameterDefinition currentNodeCallerParameter = new ParameterDefinition(); currentNodeCallerParameter.IsIn = false; currentNodeCallerParameter.IsOptional = false; currentNodeCallerParameter.IsOut = false; currentNodeCallerParameter.Type = this.nodeInterface; currentNodeCallerParameter.Index = 3; parameters.Add(currentNodeCallerParameter); MethodDefinition dumpGraphRecMethod = this.helperClass.createNewMethod("DEBUG_dumpGraphRec", this.targetClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); currentNodeCallerParameter.ContainingSignature = dumpGraphRecMethod; // is needed when parameter is accessed via Ldarg // create body for dumpGraph method ilGenerator = new ILGenerator(host, this.debuggingDumpGraphMethod); localVariables = new List<ILocalDefinition>(); // create local string variable needed for debugging code LocalDefinition nodeNameLocal = new LocalDefinition(); nodeNameLocal.IsReference = false; nodeNameLocal.IsPinned = false; nodeNameLocal.IsModified = false; nodeNameLocal.Type = this.host.PlatformType.SystemString; nodeNameLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(nodeNameLocal); // create local stream writer variable needed for debugging code LocalDefinition streamWriterLocal = new LocalDefinition(); streamWriterLocal.IsReference = false; streamWriterLocal.IsPinned = false; streamWriterLocal.IsModified = false; streamWriterLocal.Type = this.helperClass.systemIOStreamWriter; streamWriterLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(streamWriterLocal); // create local integer variable for the for loop needed for debugging code LocalDefinition forIntegerLocal = new LocalDefinition(); forIntegerLocal.IsReference = false; forIntegerLocal.IsPinned = false; forIntegerLocal.IsModified = false; forIntegerLocal.Type = this.host.PlatformType.SystemInt32; forIntegerLocal.MethodDefinition = this.debuggingDumpGraphMethod; localVariables.Add(forIntegerLocal); // generate dump file location string ilGenerator.Emit(OperationCode.Ldstr, this.debuggingDumpLocation + this.debuggingDumpFilePrefix); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, ".dot"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // initialize io stream writer ilGenerator.Emit(OperationCode.Newobj, this.helperClass.streamWriterCtor); ilGenerator.Emit(OperationCode.Stloc, streamWriterLocal); // initialize .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "digraph G {"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // check if the node to dump is the same as the current node of the class // if it is => color the current dumped node ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ceq); ILGeneratorLabel currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch); // case: current dumped node is not the current node of the class // create name for the nodes ilGenerator.Emit(OperationCode.Ldstr, "node_0"); ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // jump to the end of this case ILGeneratorLabel currentNodeDumpedBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch); // case: current dumped node is the current node of the class ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch); // create name for the nodes ilGenerator.Emit(OperationCode.Ldstr, "node_0"); ilGenerator.Emit(OperationCode.Stloc, nodeNameLocal); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // end of the case ilGenerator.MarkLabel(currentNodeDumpedBranch); // write start of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node name to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "Node: "); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, "|"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node id to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "Id: "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write end of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "}\"]"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // initialize counter of for loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // jump to loop condition loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of loop ilGenerator.MarkLabel(loopStartBranch); // check if childNodes[i] == startNode ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ceq); loopConditionAndIncBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // write connection of current node to next node to .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); // generate first part of the string ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, " -> "); ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // generate second part of string and concat to first part ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // write to .dot file ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) ) ilGenerator.Emit(OperationCode.Ldarg_0); // push stream writer parameter ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); // push string parameter ilGenerator.Emit(OperationCode.Ldloc, nodeNameLocal); ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // push node parameter (current pointer of debug method) ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); // push node parameter (current pointer of the caller) ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod); // increment loop counter ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // loop condition ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); // end .dot file ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Ldstr, "}"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // close io stream writer ilGenerator.Emit(OperationCode.Ldloc, streamWriterLocal); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterClose); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, this.debuggingDumpGraphMethod, localVariables, Enumerable<ITypeDefinition>.Empty); this.debuggingDumpGraphMethod.Body = body; // create body for dumpGraphRec method localVariables = new List<ILocalDefinition>(); ilGenerator = new ILGenerator(host, dumpGraphRecMethod); // create local integer variable for the for loop needed for debugging code forIntegerLocal = new LocalDefinition(); forIntegerLocal.IsReference = false; forIntegerLocal.IsPinned = false; forIntegerLocal.IsModified = false; forIntegerLocal.Type = this.host.PlatformType.SystemInt32; forIntegerLocal.MethodDefinition = dumpGraphRecMethod; localVariables.Add(forIntegerLocal); // check if the node to dump is the same as the current node of the class // if it is => color the current dumped node ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ceq); currentNodeEqualDumpedNodeBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, currentNodeEqualDumpedNodeBranch); // case: current dumped node is not the current node of the class // write current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // jump to the end of this case currentNodeDumpedBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, currentNodeDumpedBranch); // case: current dumped node is the current node of the class ilGenerator.MarkLabel(currentNodeEqualDumpedNodeBranch); // write current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [shape=record, color=blue]"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // end of the case ilGenerator.MarkLabel(currentNodeDumpedBranch); // write start of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " [label=\"{"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node name to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "Node: "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, "|"); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write current node id to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "Id: "); ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Callvirt, this.debuggingInterfaceIdGet); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatTwo); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWrite); // write end of label of the current node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldstr, "}\"]"); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // initialize counter of for loop ilGenerator.Emit(OperationCode.Ldc_I4_0); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // jump to loop condition loopConditionBranch = new ILGeneratorLabel(); loopStartBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Br, loopConditionBranch); // start of loop ilGenerator.MarkLabel(loopStartBranch); // check if childNodes[i] == startNode ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceStartPointerGet); ilGenerator.Emit(OperationCode.Ceq); loopConditionAndIncBranch = new ILGeneratorLabel(); ilGenerator.Emit(OperationCode.Brtrue, loopConditionAndIncBranch); // write connection of current node to next node to .dot file ilGenerator.Emit(OperationCode.Ldarg_1); // generate first part of the string ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, " -> "); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // generate second part of string and concat to first part ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // write to .dot file ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.textWriterWriteLine); // call method that dumps graph recursively ( this.dumpGraphRec(streamWriter, String name, nextNode) ) ilGenerator.Emit(OperationCode.Ldarg_0); // push stream writer parameter ilGenerator.Emit(OperationCode.Ldarg_1); // push string parameter ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldstr, "_"); ilGenerator.Emit(OperationCode.Ldloca, forIntegerLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Call, this.helperClass.stringConcatThree); // push node parameter (current pointer of debug method) ilGenerator.Emit(OperationCode.Ldarg_3); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Callvirt, this.interfaceChildNodesGet); // push node parameter (current pointer of the caller) ilGenerator.Emit(OperationCode.Ldarg, currentNodeCallerParameter); ilGenerator.Emit(OperationCode.Callvirt, dumpGraphRecMethod); // increment loop counter ilGenerator.MarkLabel(loopConditionAndIncBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4_1); ilGenerator.Emit(OperationCode.Add); ilGenerator.Emit(OperationCode.Stloc, forIntegerLocal); // loop condition ilGenerator.MarkLabel(loopConditionBranch); ilGenerator.Emit(OperationCode.Ldloc, forIntegerLocal); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Clt); ilGenerator.Emit(OperationCode.Brtrue, loopStartBranch); ilGenerator.Emit(OperationCode.Ret); // create body body = new ILGeneratorMethodBody(ilGenerator, true, 8, dumpGraphRecMethod, localVariables, Enumerable<ITypeDefinition>.Empty); dumpGraphRecMethod.Body = body; } // inject code to build the graph to all constructors (except the artificial added ctor for a graph node) foreach (MethodDefinition ctorMethod in this.targetClass.Methods) { // only process constructors if (!ctorMethod.IsConstructor) { continue; } // skip the artificial added ctor with the node interface as parameter bool skip = false; if (ctorMethod.Parameters != null) { foreach (IParameterDefinition ctorParameter in ctorMethod.Parameters) { if (ctorParameter.Type == this.nodeInterface) { skip = true; break; } } } if (skip) { continue; } this.logger.writeLine("Injecting code to build graph to \"" + this.logger.makeFuncSigString(ctorMethod) + "\""); MethodCfg ctorMethodCfg = this.cfgBuilder.buildCfgForMethod(ctorMethod); // create new basic block that builds the graph // (will be the new starting basic block of the method) BasicBlock startBasicBlock = new BasicBlock(); startBasicBlock.startIdx = 0; startBasicBlock.endIdx = 0; startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.buildGraphMethod)); if (this.debugging) { // dump generated graph startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(ctorMethodCfg.method))); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet)); startBasicBlock.operations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod)); } // create exit branch for the new start basic block NoBranchTarget startExitBranch = new NoBranchTarget(); startExitBranch.sourceBasicBlock = startBasicBlock; startBasicBlock.exitBranch = startExitBranch; // set the original start basic block as the target of the exit branch startExitBranch.takenTarget = ctorMethodCfg.startBasicBlock; ctorMethodCfg.startBasicBlock.entryBranches.Add(startExitBranch); // set new start basic block as start basic block of the method cfg ctorMethodCfg.startBasicBlock = startBasicBlock; ctorMethodCfg.basicBlocks.Add(startBasicBlock); this.cfgBuilder.createMethodFromCfg(ctorMethodCfg); } }
/// <summary> /// Deep copy a local definition. /// </summary> /// <param name="localDefinition"></param> /// <returns></returns> protected override LocalDefinition DeepCopy(LocalDefinition localDefinition) { localDefinition.Type = this.Substitute(localDefinition.Type); localDefinition.CustomModifiers = this.DeepCopy(localDefinition.CustomModifiers); return localDefinition; }
private void removeReplaceUnconditionalBranchesIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) { // create a list of basic blocks that still have to be processed by the algorithm List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks); System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count()); while (true) { List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess); foreach (BasicBlock currentBasicBlock in copiedList) { // check if basic block has entry branches that can be optimized bool hasUnconditionalBranchTarget = false; bool hasNoBranchTarget = false; foreach (IBranchTarget entryBranch in currentBasicBlock.entryBranches) { if ((entryBranch as NoBranchTarget) != null) { hasNoBranchTarget = true; continue; } else if ((entryBranch as UnconditionalBranchTarget) != null) { hasUnconditionalBranchTarget = true; continue; } } // skip if basic block already has no branch target if (hasNoBranchTarget) { // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); continue; } // skip if basic block does not have an unconditional branch target if (!hasUnconditionalBranchTarget) { // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); continue; } // replace one unconditional branch by a no branch List<IBranchTarget> copiedBranchList = new List<IBranchTarget>(currentBasicBlock.entryBranches); foreach (IBranchTarget entryBranch in copiedBranchList) { if ((entryBranch as UnconditionalBranchTarget) != null) { BasicBlock sourceBasicBlock = entryBranch.sourceBasicBlock; // create replacement branch NoBranchTarget replacementBranch = new NoBranchTarget(); replacementBranch.sourceBasicBlock = sourceBasicBlock; replacementBranch.takenTarget = currentBasicBlock; // replace old branch with new one sourceBasicBlock.exitBranch = replacementBranch; currentBasicBlock.entryBranches.Remove(entryBranch); currentBasicBlock.entryBranches.Add(replacementBranch); // replace unconditional branch instruction with nop IOperation lastOperation = sourceBasicBlock.operations.ElementAt(sourceBasicBlock.operations.Count() - 1); if (!CfgBuilder.isUnconditionalBranchOperation(lastOperation)) { throw new ArgumentException("Last instruction of basic block have to be an unconditional branch."); } IOperation replacementOperation = this.helperClass.createNewOperation(OperationCode.Nop); sourceBasicBlock.operations[sourceBasicBlock.operations.Count() - 1] = replacementOperation; break; } } // remove currently processed basic block from the list of basic blocks to process basicBlocksToProcess.Remove(currentBasicBlock); } System.Console.WriteLine("Basic Blocks to process (Replace Unconditional Branches): " + basicBlocksToProcess.Count()); // check if basic blocks exist to process => if not break loop if (basicBlocksToProcess.Count() == 0) { break; } } }
public LocalPlace(LocalDefinition def) { Contract.ThrowIfNull(def); _def = def; }
public override void RewriteChildren(LocalDefinition localDefinition) { //The locals have already been copied. They just have to get fixed up. localDefinition.MethodDefinition = this.method; }
public override IExpression Rewrite(IBoundExpression boundExpression) { if (boundExpression.Instance == null || ExpressionTraverser.IsAtomicInstance(boundExpression.Instance)) return boundExpression; // boundExpression == BE(inst, def), i.e., inst.def // return { loc := e; [assert loc != null;] | BE(BE(null,loc), def) }, i.e., "loc := e; loc.def" // where e is the rewritten inst var e = base.Rewrite(boundExpression.Instance); var loc = new LocalDefinition() { Name = this.host.NameTable.GetNameFor("_loc" + this.sink.LocalCounter.ToString()), Type = e.Type, }; var locDecl = new LocalDeclarationStatement() { InitialValue = e, LocalVariable = loc, }; return new BlockExpression() { BlockStatement = new BlockStatement() { Statements = new List<IStatement> { locDecl }, }, Expression = new BoundExpression() { Definition = boundExpression.Definition, Instance = new BoundExpression() { Definition = loc, Instance = null, Type = loc.Type, }, Type = boundExpression.Type, }, }; }
public override IExpression Rewrite(IArrayIndexer arrayIndexer) { if (ExpressionTraverser.IsAtomicInstance(arrayIndexer.IndexedObject)) return arrayIndexer; // arrayIndexer == AI(inst, [index]), i.e., inst[index0, index1,...] // return { loc := e; [assert loc != null;] | AI(BE(null,loc), [index]) } // where e is the rewritten array instance var e = base.Rewrite(arrayIndexer.IndexedObject); var loc = new LocalDefinition() { Name = this.host.NameTable.GetNameFor("_loc" + this.sink.LocalCounter.ToString()), Type = e.Type }; var locDecl = new LocalDeclarationStatement() { InitialValue = e, LocalVariable = loc, }; return new BlockExpression() { BlockStatement = new BlockStatement() { Statements = new List<IStatement> { locDecl }, }, Expression = new ArrayIndexer() { IndexedObject = new BoundExpression() { Definition = loc, Instance = null, Type = loc.Type, }, Indices = new List<IExpression>(arrayIndexer.Indices), Type = arrayIndexer.Type, }, }; }
public override void RewriteChildren(MethodBody methodBody) { var method = methodBody.MethodDefinition; Contract.Assume(this.copier.OriginalFor.ContainsKey(method)); var o = this.copier.OriginalFor[method]; var originalMethod = (IMethodDefinition)o; var keepEntireBody = this.methodDefsToKeep.Contains(originalMethod.InternedKey); if (!keepEntireBody) { #region Keep only contract portion of the IL (if it has a contract), add return statement at end var ops = new List<IOperation>(); uint contractOffset; if (this.contractOffsets.TryGetValue(originalMethod, out contractOffset)) { if (contractOffset != uint.MaxValue) { // then it has a contract foreach (var op in methodBody.Operations) { if (contractOffset < op.Offset) break; ops.Add(op); } } } LocalDefinition ld = null; if (method.Type.TypeCode != PrimitiveTypeCode.Void) { ld = new LocalDefinition() { MethodDefinition = method, Type = method.Type, }; ops.Add(new Operation() { OperationCode = OperationCode.Ldloc, Value = ld, }); methodBody.LocalsAreZeroed = true; } ops.Add(new Operation() { OperationCode = OperationCode.Ret, }); if (ld != null) { if (methodBody.LocalVariables == null) methodBody.LocalVariables = new List<ILocalDefinition>(); methodBody.LocalVariables.Add(ld); methodBody.MaxStack++; } #endregion methodBody.Operations = ops; methodBody.OperationExceptionInformation = null; } }