/// <summary> /// Creates a null-check exception specification. /// </summary> /// <param name="parameterIndex"> /// The index of the instruction parameter that is null checked. /// </param> /// <param name="nullCheckSpec"> /// The exception specification of the exception thrown /// if and when a null check fails. /// </param> public NullCheckExceptionSpecification( int parameterIndex, ExceptionSpecification nullCheckSpec) { this.ParameterIndex = parameterIndex; this.NullCheckSpec = nullCheckSpec; }
/// <summary> /// Creates CIL prototype exception specification rules. /// </summary> /// <param name="corlibTypeResolver"> /// A type resolver for the core library (corlib.dll) that /// defines well-known exception types. /// </param> /// <returns>Prototype exception specification rules.</returns> public static RuleBasedPrototypeExceptionSpecs Create( ReadOnlyTypeResolver corlibTypeResolver) { var result = new RuleBasedPrototypeExceptionSpecs( RuleBasedPrototypeExceptionSpecs.Default); // We know the type of exception thrown by null checks: // it's System.NullReferenceException. var nullRefException = corlibTypeResolver.ResolveTypes( new SimpleName(nameof(NullReferenceException)) .Qualify(nameof(System))) .Single(); // Resolve other well-known exception types. var outOfRangeException = corlibTypeResolver.ResolveTypes( new SimpleName(nameof(IndexOutOfRangeException)) .Qualify(nameof(System))) .Single(); var arrayTypeMismatchException = corlibTypeResolver.ResolveTypes( new SimpleName(nameof(ArrayTypeMismatchException)) .Qualify(nameof(System))) .Single(); // Refine null check exception types. result.Register <GetFieldPointerPrototype>( new NullCheckExceptionSpecification(0, nullRefException)); result.Register <NewDelegatePrototype>( proto => proto.Lookup == MethodLookup.Virtual ? new NullCheckExceptionSpecification(0, nullRefException) : ExceptionSpecification.NoThrow); result.Register <UnboxPrototype>( new NullCheckExceptionSpecification(0, nullRefException)); // Array intrinsics are worth refining, too. result.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetElementPointer), ExceptionSpecification.Union( new NullCheckExceptionSpecification(0, nullRefException), ExceptionSpecification.Exactly(outOfRangeException), ExceptionSpecification.Exactly(arrayTypeMismatchException))); result.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.LoadElement), ExceptionSpecification.Union( new NullCheckExceptionSpecification(0, nullRefException), ExceptionSpecification.Exactly(outOfRangeException))); result.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.StoreElement), ExceptionSpecification.Union( new NullCheckExceptionSpecification(0, nullRefException), ExceptionSpecification.Exactly(outOfRangeException), ExceptionSpecification.Exactly(arrayTypeMismatchException))); result.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetLength), new NullCheckExceptionSpecification(0, nullRefException)); return(result); }
private ExceptionSpecification Reify( ExceptionSpecification prototypeSpec, Instruction instruction, FlowGraph graph) { if (prototypeSpec is ExceptionSpecification.Union) { var unionSpec = (ExceptionSpecification.Union)prototypeSpec; var newOperands = new List <ExceptionSpecification>(); foreach (var operand in unionSpec.Operands) { var newOp = Reify(operand, instruction, graph); if (newOp == ExceptionSpecification.ThrowAny) { return(newOp); } else if (newOp.CanThrowSomething) { newOperands.Add(newOp); } } return(ExceptionSpecification.Union.Create(newOperands.ToArray())); } else if (prototypeSpec is NullCheckExceptionSpecification) { var nullCheck = (NullCheckExceptionSpecification)prototypeSpec; var arg = instruction.Arguments[nullCheck.ParameterIndex]; var nullability = graph.GetAnalysisResult <ValueNullability>(); if (nullability.IsNonNull(arg)) { return(ExceptionSpecification.NoThrow); } else { var innerSpec = Reify(nullCheck.NullCheckSpec, instruction, graph); if (!innerSpec.CanThrowSomething) { return(ExceptionSpecification.NoThrow); } else { return(new NullCheckExceptionSpecification(nullCheck.ParameterIndex, innerSpec)); } } } else { return(prototypeSpec); } }
/// <summary> /// Registers a function that assigns a fixed exception specification /// to a particular type of intrinsic. /// </summary> /// <param name="intrinsicName"> /// The name of the intrinsic to assign the exception /// specifications to. /// </param> /// <param name="exceptionSpec"> /// The exception specification for all intrinsic prototypes with /// name <paramref name="intrinsicName"/>. /// </param> public void Register(string intrinsicName, ExceptionSpecification exceptionSpec) { store.Register(intrinsicName, exceptionSpec); }
/// <summary> /// Maps a particular type of instruction prototype /// to an exception specification. /// </summary> /// <param name="exceptionSpec"> /// The exception specification to register. /// </param> /// <typeparam name="T"> /// The type of instruction prototypes to which /// <paramref name="exceptionSpec"/> is applicable. /// </typeparam> public void Register <T>(ExceptionSpecification exceptionSpec) where T : InstructionPrototype { store.Register <T>(exceptionSpec); }
/// <summary> /// Maps a particular type of instruction prototype /// to an exception specification. /// </summary> /// <param name="exceptionSpec"> /// The exception specification to register. /// </param> /// <typeparam name="T"> /// The type of instruction prototypes to which /// <paramref name="exceptionSpec"/> is applicable. /// </typeparam> public void Register <T>(ExceptionSpecification exceptionSpec) where T : InstructionPrototype { instructionSpecs[typeof(T)] = proto => exceptionSpec; }
/// <summary> /// Creates a null-check exception specification. /// </summary> /// <param name="parameterIndex"> /// The index of the instruction parameter that is null checked. /// </param> /// <param name="exceptionType"> /// The type of exception that is thrown if and when /// a null check fails. /// </param> public NullCheckExceptionSpecification( int parameterIndex, IType exceptionType) : this(parameterIndex, ExceptionSpecification.Exactly(exceptionType)) { }
static RuleBasedPrototypeExceptionSpecs() { Default = new RuleBasedPrototypeExceptionSpecs(); // Instruction prototypes that never throw. Default.Register <AllocaArrayPrototype>(ExceptionSpecification.NoThrow); Default.Register <AllocaPrototype>(ExceptionSpecification.NoThrow); Default.Register <BoxPrototype>(ExceptionSpecification.NoThrow); Default.Register <ConstantPrototype>(ExceptionSpecification.NoThrow); Default.Register <CopyPrototype>(ExceptionSpecification.NoThrow); Default.Register <DynamicCastPrototype>(ExceptionSpecification.NoThrow); Default.Register <GetStaticFieldPointerPrototype>(ExceptionSpecification.NoThrow); Default.Register <LoadPrototype>(ExceptionSpecification.NoThrow); Default.Register <ReinterpretCastPrototype>(ExceptionSpecification.NoThrow); Default.Register <StorePrototype>(ExceptionSpecification.NoThrow); // Instruction prototypes that may throw because of implicit null checks. Default.Register <GetFieldPointerPrototype>( new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny)); Default.Register <NewDelegatePrototype>( proto => proto.Lookup == MethodLookup.Virtual ? new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny) : ExceptionSpecification.NoThrow); Default.Register <UnboxPrototype>( new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny)); // Call-like instruction prototypes. // TODO: use the callee's exception specification. Default.Register <CallPrototype>(ExceptionSpecification.ThrowAny); Default.Register <NewObjectPrototype>(ExceptionSpecification.ThrowAny); Default.Register <IndirectCallPrototype>(ExceptionSpecification.ThrowAny); // Arithmetic intrinsics never throw. foreach (var name in ArithmeticIntrinsics.Operators.All) { Default.Register( ArithmeticIntrinsics.GetArithmeticIntrinsicName(name), ExceptionSpecification.NoThrow); } // Array intrinsics are a little more complicated. // TODO: model bounds checks somehow. Default.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetElementPointer), ExceptionSpecification.ThrowAny); Default.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.LoadElement), ExceptionSpecification.ThrowAny); Default.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.StoreElement), ExceptionSpecification.ThrowAny); Default.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.GetLength), new NullCheckExceptionSpecification(0, ExceptionSpecification.ThrowAny)); Default.Register( ArrayIntrinsics.Namespace.GetIntrinsicName(ArrayIntrinsics.Operators.NewArray), ExceptionSpecification.NoThrow); // Exception intrinsics. Default.Register( ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Capture), ExceptionSpecification.NoThrow); Default.Register( ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.GetCapturedException), ExceptionSpecification.NoThrow); Default.Register( ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Rethrow), ExceptionSpecification.ThrowAny); Default.Register( ExceptionIntrinsics.Namespace.GetIntrinsicName(ExceptionIntrinsics.Operators.Throw), proto => ExceptionSpecification.Exactly(proto.ParameterTypes[0])); // Object intrinsics. // TODO: model exception thrown by type check. Default.Register( ObjectIntrinsics.Namespace.GetIntrinsicName(ObjectIntrinsics.Operators.UnboxAny), ExceptionSpecification.ThrowAny); }
/// <summary> /// Registers a function that assigns a fixed exception specification /// to a particular type of intrinsic. /// </summary> /// <param name="intrinsicName"> /// The name of the intrinsic to assign the exception /// specifications to. /// </param> /// <param name="exceptionSpec"> /// The exception specification for all intrinsic prototypes with /// name <paramref name="intrinsicName"/>. /// </param> public void Register(string intrinsicName, ExceptionSpecification exceptionSpec) { Register(intrinsicName, proto => exceptionSpec); }
/// <summary> /// Creates an exception specification attribute. /// </summary> /// <param name="specification">An exception specification.</param> public ExceptionSpecificationAttribute(ExceptionSpecification specification) { this.Specification = specification; }