예제 #1
0
        /// <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);
        }
 /// <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);
        }