Xamarin Public Jenkins (auto-signing) 94b2861243 Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
2016-11-10 13:04:39 +00:00

291 lines
13 KiB
C#

//
// ContractRuntime.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using System.Diagnostics.Contracts;
using Mono.Cecil.Cil;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using System.Runtime.CompilerServices;
namespace Mono.CodeContracts.Rewrite {
class ContractsRuntime {
private const string Namespace = "System.Diagnostics.Contracts";
public ContractsRuntime (ModuleDefinition module, RewriterOptions options)
{
this.module = module;
this.options = options;
}
private ModuleDefinition module;
private RewriterOptions options;
private TypeDefinition typeContractsRuntime = null;
private TypeDefinition typeContractException = null;
private MethodDefinition methodContractExceptionCons = null;
private MethodDefinition methodTriggerFailure = null;
private MethodDefinition methodReportFailure = null;
private MethodDefinition methodRequires = null;
private void EnsureTypeContractRuntime ()
{
if (this.typeContractsRuntime == null) {
// namespace System.Diagnostics.Contracts {
// [CompilerGenerated]
// private static class __ContractsRuntime {
// }
// }
// Create type
TypeReference typeObject = this.module.Import (typeof (object));
TypeDefinition type = new TypeDefinition ("__ContractsRuntime", Namespace,
TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, // | TypeAttributes.BeforeFieldInit,
typeObject);
this.module.Types.Add (type);
// Attach custom attributes
var attrCompilerGeneratedCons = typeof (CompilerGeneratedAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrCompilerGenerated = new CustomAttribute (this.module.Import (attrCompilerGeneratedCons));
type.CustomAttributes.Add (attrCompilerGenerated);
// Store type
this.typeContractsRuntime = type;
}
}
private void EnsureTypeContractException ()
{
if (this.options.ThrowOnFailure && this.typeContractException == null) {
// [CompilerGenerated]
// private class ContractException : Exception {
// internal ContractException(ContractFailureKind kind, string usermsg, string condition, Exception inner)
// : base(failure, inner)
// {
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
// Create type
TypeDefinition type = new TypeDefinition ("ContractException", Namespace,
TypeAttributes.NestedPrivate | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeException);
//this.typeContractsRuntime.NestedTypes.Add (type);
this.module.Types.Add(type);
// Create constructor
MethodDefinition cons = new MethodDefinition (".ctor",
MethodAttributes.Assembly | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeVoid);
cons.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
cons.Parameters.Add (new ParameterDefinition ("failure", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("usermsg", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("condition", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
var il = cons.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_S, cons.Parameters [4]);
MethodReference mExceptionCons = this.module.Import (typeof (Exception).GetConstructor (new [] { typeof (string), typeof (Exception) }));
il.Emit (OpCodes.Call, mExceptionCons);
il.Emit (OpCodes.Ret);
type.Methods.Add (cons);
// Attach custom attributes
var attrCompilerGeneratedCons = typeof (CompilerGeneratedAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrCompilerGenerated = new CustomAttribute (this.module.Import (attrCompilerGeneratedCons));
type.CustomAttributes.Add (attrCompilerGenerated);
// Store constructor and type
this.methodContractExceptionCons = cons;
this.typeContractException = type;
}
}
private void EnsureMethodTriggerFailure ()
{
if (this.methodTriggerFailure == null) {
// if the ThrowOnFailure option is true, then:
// internal static void TriggerFailure(ContractFailureKind kind, string message, string userMessage, string conditionText, Exception inner)
// {
// throw new ContractException(kind, message, userMessage, conditionText, inner);
// }
// if the ThrowOnFailure option is false, then:
// internal static void TriggerFailure(ContractFailureKind kind, string message, string userMessage, string conditionText, Exception inner)
// {
// Debug.Fail(message, userMessage);
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
// Create method
MethodDefinition method = new MethodDefinition ("TriggerFailure",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("userMessage", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
var il = method.Body.GetILProcessor ();
if (this.options.ThrowOnFailure) {
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Ldarg_S, method.Parameters [4]);
il.Emit (OpCodes.Newobj, this.methodContractExceptionCons);
il.Emit (OpCodes.Throw);
} else {
var mDebugFail = typeof (Debug).GetMethod ("Fail", new [] { typeof (string), typeof(string) });
MethodReference methodDebugFail = this.module.Import (mDebugFail);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Call, methodDebugFail);
il.Emit (OpCodes.Ret);
}
this.typeContractsRuntime.Methods.Add (method);
this.methodTriggerFailure = method;
}
}
private void EnsureMethodReportFailure ()
{
if (this.methodReportFailure == null) {
// internal static void ReportFailure(ContractFailureKind kind, string message, string conditionText, Exception inner)
// {
// string s = ContractHelper.RaiseContractFailedEvent(kind, message, conditionText, inner);
// if (s != null) {
// TriggerFailure(kind, s, message, conditionText, inner);
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
var helper = typeof (ContractHelper);
MethodReference mRaiseContractFailedEvent = this.module.Import (helper.GetMethod ("RaiseContractFailedEvent"));
// Create method
MethodDefinition method = new MethodDefinition ("ReportFailure",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
VariableDefinition vMsg = new VariableDefinition (typeString);
method.Body.Variables.Add (vMsg);
method.Body.InitLocals = true;
var il = method.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Call, mRaiseContractFailedEvent);
il.Emit (OpCodes.Stloc_0);
il.Emit (OpCodes.Ldloc_0);
var instRet = il.Create (OpCodes.Ret);
il.Emit (OpCodes.Brfalse_S, instRet);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldloc_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Call, this.methodTriggerFailure);
il.Append (instRet);
this.typeContractsRuntime.Methods.Add (method);
this.methodReportFailure = method;
}
}
private void EnsureGlobal ()
{
this.EnsureTypeContractRuntime ();
this.EnsureTypeContractException ();
this.EnsureMethodTriggerFailure ();
this.EnsureMethodReportFailure ();
}
public MethodDefinition GetRequires ()
{
this.EnsureGlobal ();
if (this.methodRequires == null) {
// [DebuggerNonUserCode]
// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
// internal static void Requires(bool condition, string message, string conditionText)
// {
// if (!condition) {
// ReportFailure(ContractFailureKind.Precondition, message, conditionText, null);
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeBoolean = this.module.Import (typeof (bool));
TypeReference typeString = this.module.Import (typeof (string));
// Create method
MethodDefinition method = new MethodDefinition ("Requires",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("condition", ParameterAttributes.None, typeBoolean));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
var il = method.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
var instRet = il.Create(OpCodes.Ret);
il.Emit (OpCodes.Brtrue_S, instRet);
il.Emit (OpCodes.Ldc_I4_0); // Assumes ContractFailureKind.Precondition == 0
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Call, this.methodReportFailure);
il.Append (instRet);
this.typeContractsRuntime.Methods.Add (method);
// Attach custom attributes
var attrDebugNonUserCodeCons = typeof (DebuggerNonUserCodeAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrDebugNonUserCode = new CustomAttribute (this.module.Import (attrDebugNonUserCodeCons));
method.CustomAttributes.Add (attrDebugNonUserCode);
var attrReliabilityContractCons = typeof (ReliabilityContractAttribute).GetConstructor (new [] { typeof (Consistency), typeof (Cer) });
// Blob for attribute: new ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)
byte [] blob = new byte [] { 1, 0, 3, 0, 0, 0, 1, 0, 0, 0 };
CustomAttribute attrReliabilityContract = new CustomAttribute (this.module.Import (attrReliabilityContractCons), blob);
method.CustomAttributes.Add (attrReliabilityContract);
// Store method
this.methodRequires = method;
}
return this.methodRequires;
}
}
}