Ejemplo n.º 1
0
 public InteropIntrinsicAttribute(InteropIntrinsicKind intrinsicKind)
 {
     IntrinsicKind = intrinsicKind;
 }
        /// <summary>
        /// Handles general interop operations.
        /// </summary>
        /// <param name="context">The current invocation context.</param>
        /// <param name="kind">The kind of the interop intrinsic.</param>
        /// <returns>The resulting value.</returns>
        protected virtual Value?MakeInterop(InvocationContext context, InteropIntrinsicKind kind)
        {
            var compilationContext = context.CompilationContext;
            var args        = context.GetArgs();
            var genericArgs = context.GetMethodGenericArguments();
            var type        = genericArgs.Length > 0 ? genericArgs[0] : null;
            var llvmType    = context.Unit.GetType(type);
            var builder     = context.Builder;
            var int32Type   = context.LLVMContext.Int32Type;

            switch (kind)
            {
            case InteropIntrinsicKind.DestroyStructure:
                return(new Value(type, BuildStore(builder, args[0].LLVMValue, ConstNull(llvmType))));

            case InteropIntrinsicKind.SizeOf:
                return(new Value(typeof(int), BuildTruncOrBitCast(builder, SizeOf(llvmType), int32Type, string.Empty)));

            case InteropIntrinsicKind.OffsetOf:
            {
                if (type.IsPrimitive)
                {
                    throw compilationContext.GetNotSupportedException(
                              ErrorMessages.CannotTakeFieldOffsetOfPrimitiveType, type);
                }
                // Argument is a GEP
                var testVal   = args[0].LLVMValue;
                var gepSource = GetOperand(testVal, 0);
                // First argument is the string const
                var stringConst = GetOperand(gepSource, 0);
                var stringPtr   = GetAsString(stringConst, out IntPtr size);
                var sizeVal     = size.ToInt32();
                if (sizeVal < 2)
                {
                    throw compilationContext.GetNotSupportedException(
                              ErrorMessages.CannotFindFieldOfType, string.Empty, type);
                }
                var fieldName  = Marshal.PtrToStringAnsi(stringPtr, Math.Max(sizeVal - 1, 0));
                var mappedType = context.Unit.GetObjectType(type);
                var info       = mappedType.ManagedType.GetField(fieldName);
                if (info == null || !mappedType.TryResolveOffset(info, out int offset))
                {
                    throw compilationContext.GetNotSupportedException(
                              ErrorMessages.CannotFindFieldOfType, fieldName, type);
                }

                var index         = ConstInt(int32Type, offset, false);
                var offsetPointer = BuildInBoundsGEP(
                    builder,
                    ConstPointerNull(llvmType),
                    out index,
                    1,
                    string.Empty);
                var intOffset = BuildPtrToInt(builder, offsetPointer, int32Type, string.Empty);

                return(new Value(typeof(int), intOffset));
            }

            default:
                throw compilationContext.GetNotSupportedException(
                          ErrorMessages.NotSupportedIntrinsic, kind);
            }
        }