public CallCloseOrDisposeAnalysisVisitor(IMetadataHost host, PdbReader pdbReader) { this.host = host; this.pdbReader = pdbReader; this.iDisposable = new NamespaceTypeReference(this.host, this.host.PlatformType.SystemObject.ContainingUnitNamespace, this.host.NameTable.GetNameFor("IDisposable"), 0, false, false, true, PrimitiveTypeCode.Reference); }
/// <summary> /// Generates IL for the specified resource use statement. /// </summary> /// <param name="resourceUseStatement">The resource use statement.</param> public override void TraverseChildren(IResourceUseStatement resourceUseStatement) { this.EmitSequencePoint(resourceUseStatement.Locations); var systemIDisposable = new NamespaceTypeReference(this.host, this.host.PlatformType.SystemObject.ContainingUnitNamespace, this.host.NameTable.GetNameFor("IDisposable"), 0, isEnum: false, isValueType: false, typeCode: PrimitiveTypeCode.NotPrimitive); var dispose = new MethodReference(this.host, systemIDisposable, CallingConvention.Default, this.host.PlatformType.SystemVoid, this.host.NameTable.GetNameFor("Dispose"), 0, Enumerable<IParameterTypeInformation>.Empty); //Get resource into a local ILocalDefinition resourceLocal; var localDeclaration = resourceUseStatement.ResourceAcquisitions as ILocalDeclarationStatement; if (localDeclaration != null) { resourceLocal = localDeclaration.LocalVariable; this.Traverse(localDeclaration.InitialValue); } else { var expressionStatement = (IExpressionStatement)resourceUseStatement.ResourceAcquisitions; this.Traverse(expressionStatement.Expression); resourceLocal = new TemporaryVariable(systemIDisposable, this.method); } this.VisitAssignmentTo(resourceLocal); //try var savedCurrentTryCatch = this.currentTryCatch; this.currentTryCatch = resourceUseStatement; var savedCurrentTryCatchFinallyEnd = this.currentTryCatchFinallyEnd; this.currentTryCatchFinallyEnd = new ILGeneratorLabel(); this.generator.BeginTryBody(); this.Traverse(resourceUseStatement.Body); if (!this.lastStatementWasUnconditionalTransfer) this.generator.Emit(OperationCode.Leave, this.currentTryCatchFinallyEnd); //finally this.generator.BeginFinallyBlock(); var endOfFinally = new ILGeneratorLabel(); if (!resourceLocal.Type.IsValueType) { this.generator.Emit(OperationCode.Ldloc, resourceLocal); this.generator.Emit(OperationCode.Brfalse_S, endOfFinally); } this.generator.Emit(OperationCode.Ldloc, resourceLocal); this.generator.Emit(OperationCode.Callvirt, dispose); this.generator.MarkLabel(endOfFinally); this.generator.Emit(OperationCode.Endfinally); this.generator.EndTryBody(); this.generator.MarkLabel(this.currentTryCatchFinallyEnd); this.currentTryCatchFinallyEnd = savedCurrentTryCatchFinallyEnd; this.currentTryCatch = savedCurrentTryCatch; this.lastStatementWasUnconditionalTransfer = false; }
private void GenerateDownLevelLockStatement(ILockStatement lockStatement) { var systemThreading = new NestedUnitNamespaceReference(this.host.PlatformType.SystemObject.ContainingUnitNamespace, this.host.NameTable.GetNameFor("Threading")); var systemThreadingMonitor = new NamespaceTypeReference(this.host, systemThreading, this.host.NameTable.GetNameFor("Monitor"), 0, isEnum: false, isValueType: false, typeCode: PrimitiveTypeCode.NotPrimitive); var parameters = new IParameterTypeInformation[2]; var monitorEnter = new MethodReference(this.host, systemThreadingMonitor, CallingConvention.Default, this.host.PlatformType.SystemVoid, this.host.NameTable.GetNameFor("Enter"), 0, this.host.PlatformType.SystemObject); var monitorExit = new MethodReference(this.host, systemThreadingMonitor, CallingConvention.Default, this.host.PlatformType.SystemVoid, this.host.NameTable.GetNameFor("Exit"), 0, this.host.PlatformType.SystemObject); this.EmitSequencePoint(lockStatement.Locations); var guardObject = new TemporaryVariable(lockStatement.Guard.Type, this.method); this.Traverse(lockStatement.Guard); this.generator.Emit(OperationCode.Dup); this.StackSize++; this.VisitAssignmentTo(guardObject); this.generator.Emit(OperationCode.Call, monitorEnter); this.StackSize--; //try var savedCurrentTryCatch = this.currentTryCatch; this.currentTryCatch = lockStatement; var savedCurrentTryCatchFinallyEnd = this.currentTryCatchFinallyEnd; this.currentTryCatchFinallyEnd = new ILGeneratorLabel(); this.generator.BeginTryBody(); this.Traverse(lockStatement.Body); if (!this.lastStatementWasUnconditionalTransfer) this.generator.Emit(OperationCode.Leave, this.currentTryCatchFinallyEnd); //finally this.generator.BeginFinallyBlock(); //if (status) this.LoadLocal(guardObject); this.generator.Emit(OperationCode.Call, monitorExit); this.StackSize--; //monitor exit this.generator.Emit(OperationCode.Endfinally); this.generator.EndTryBody(); this.generator.MarkLabel(this.currentTryCatchFinallyEnd); this.currentTryCatchFinallyEnd = savedCurrentTryCatchFinallyEnd; this.currentTryCatch = savedCurrentTryCatch; this.lastStatementWasUnconditionalTransfer = false; }
/// <summary> /// Generates IL for the specified lock statement. /// </summary> /// <param name="lockStatement">The lock statement.</param> public override void TraverseChildren(ILockStatement lockStatement) { if (this.host.SystemCoreAssemblySymbolicIdentity.Version.Major < 4) { this.GenerateDownLevelLockStatement(lockStatement); return; } var systemThreading = new NestedUnitNamespaceReference(this.host.PlatformType.SystemObject.ContainingUnitNamespace, this.host.NameTable.GetNameFor("Threading")); var systemThreadingMonitor = new NamespaceTypeReference(this.host, systemThreading, this.host.NameTable.GetNameFor("Monitor"), 0, isEnum: false, isValueType: false, typeCode: PrimitiveTypeCode.NotPrimitive); var parameters = new IParameterTypeInformation[2]; var monitorEnter = new MethodReference(this.host, systemThreadingMonitor, CallingConvention.Default, this.host.PlatformType.SystemVoid, this.host.NameTable.GetNameFor("Enter"), 0, parameters); parameters[0] = new SimpleParameterTypeInformation(monitorEnter, 0, this.host.PlatformType.SystemObject); parameters[1] = new SimpleParameterTypeInformation(monitorEnter, 1, this.host.PlatformType.SystemBoolean, isByReference: true); var monitorExit = new MethodReference(this.host, systemThreadingMonitor, CallingConvention.Default, this.host.PlatformType.SystemVoid, this.host.NameTable.GetNameFor("Exit"), 0, this.host.PlatformType.SystemObject); this.EmitSequencePoint(lockStatement.Locations); var guardObject = new TemporaryVariable(lockStatement.Guard.Type, this.method); var lockTaken = new TemporaryVariable(this.host.PlatformType.SystemBoolean, this.method); //try var savedCurrentTryCatch = this.currentTryCatch; this.currentTryCatch = lockStatement; var savedCurrentTryCatchFinallyEnd = this.currentTryCatchFinallyEnd; this.currentTryCatchFinallyEnd = new ILGeneratorLabel(); this.generator.BeginTryBody(); this.Traverse(lockStatement.Guard); this.generator.Emit(OperationCode.Dup); this.StackSize++; this.VisitAssignmentTo(guardObject); this.LoadAddressOf(lockTaken, null); this.generator.Emit(OperationCode.Call, monitorEnter); this.StackSize-=2; this.Traverse(lockStatement.Body); if (!this.lastStatementWasUnconditionalTransfer) this.generator.Emit(OperationCode.Leave, this.currentTryCatchFinallyEnd); //finally this.generator.BeginFinallyBlock(); //if (status) var endIf = new ILGeneratorLabel(); this.LoadLocal(lockTaken); this.generator.Emit(OperationCode.Brfalse_S, endIf); this.StackSize--; this.LoadLocal(guardObject); this.generator.Emit(OperationCode.Call, monitorExit); this.StackSize--; this.generator.MarkLabel(endIf); //monitor exit this.generator.Emit(OperationCode.Endfinally); this.generator.EndTryBody(); this.generator.MarkLabel(this.currentTryCatchFinallyEnd); this.currentTryCatchFinallyEnd = savedCurrentTryCatchFinallyEnd; this.currentTryCatch = savedCurrentTryCatch; this.lastStatementWasUnconditionalTransfer = false; }