public static void MarshalToPcode(object value, ref StackElement pcode, DataTypes type)
        {
#if DEBUG
            pcode.AssertClear();
#endif
            switch (type)
            {
            default:
                Debug.Assert(false);     // an unknown data type is a bug on our caller's part
                throw new ArgumentException();

            case DataTypes.eBoolean:
                pcode.Data.Integer = (bool)value ? 1 : 0;
                break;

            case DataTypes.eInteger:
                pcode.Data.Integer = (int)value;
                break;

            case DataTypes.eFloat:
                pcode.Data.Float = (float)value;
                break;

            case DataTypes.eDouble:
                pcode.Data.Double = (double)value;
                break;

            case DataTypes.eArrayOfBoolean:
            case DataTypes.eArrayOfByte:
                pcode.reference.arrayHandleByte = (ArrayHandleByte)value;
                break;

            case DataTypes.eArrayOfInteger:
                pcode.reference.arrayHandleInt32 = (ArrayHandleInt32)value;
                break;

            case DataTypes.eArrayOfFloat:
                pcode.reference.arrayHandleFloat = (ArrayHandleFloat)value;
                break;

            case DataTypes.eArrayOfDouble:
                pcode.reference.arrayHandleDouble = (ArrayHandleDouble)value;
                break;
            }
        }
        public static void MarshalToManaged(ref StackElement value, DataTypes type, out object managed)
        {
            switch (type)
            {
            default:
                Debug.Assert(false);     // an unknown data type is a bug on our caller's part
                throw new ArgumentException();

            case DataTypes.eBoolean:
                managed = value.Data.Integer != 0;
                break;

            case DataTypes.eInteger:
                managed = value.Data.Integer;
                break;

            case DataTypes.eFloat:
                managed = value.Data.Float;
                break;

            case DataTypes.eDouble:
                managed = value.Data.Double;
                break;

            case DataTypes.eArrayOfBoolean:
            case DataTypes.eArrayOfByte:
                managed = value.reference.arrayHandleByte;
                break;

            case DataTypes.eArrayOfInteger:
                managed = value.reference.arrayHandleInt32;
                break;

            case DataTypes.eArrayOfFloat:
                managed = value.reference.arrayHandleFloat;
                break;

            case DataTypes.eArrayOfDouble:
                managed = value.reference.arrayHandleDouble;
                break;
            }
        }
Exemple #3
0
 public void CopyFrom(ref StackElement source)
 {
     Data.int64        = source.Data.int64;
     reference.generic = source.reference.generic;
 }
Exemple #4
0
        public CILObject(
            ManagedFunctionLinkerRec managedFunctionLinker,
            DataTypes[] argsTypes,
            string[] argsNames,
            DataTypes returnType,
            Compiler.ASTExpression ast,
            CILAssembly cilAssembly,
            bool argsByRef)
        {
            this.argsTypes  = argsTypes;
            this.returnType = returnType;

            this.cilAssembly = cilAssembly;

            PcodeMarshal.GetManagedFunctionSignature(
                argsTypes,
                returnType,
                out managedArgsTypes,
                out managedReturnType);
            int methodSequenceNumber = methodNameSequencer++;

            methodName = String.Format("m{0}", methodSequenceNumber);
            MethodBuilder methodBuilder;

            if (!argsByRef)
            {
                methodBuilder = cilAssembly.typeBuilder.DefineMethod(
                    methodName,
                    MethodAttributes.Public | MethodAttributes.Static,
                    managedReturnType,
                    managedArgsTypes);
            }
            else
            {
                Type[] managedArgsTypesByRef = new Type[managedArgsTypes.Length];
                for (int i = 0; i < managedArgsTypesByRef.Length; i++)
                {
                    managedArgsTypesByRef[i] = managedArgsTypes[i].MakeByRefType();
                }
                methodBuilder = cilAssembly.typeBuilder.DefineMethod(
                    methodName,
                    MethodAttributes.Public | MethodAttributes.Static,
                    managedReturnType,
                    managedArgsTypesByRef);
            }

            ILGenerator ilGenerator = methodBuilder.GetILGenerator();

            Dictionary <SymbolRec, LocalBuilder> variableTable = new Dictionary <SymbolRec, LocalBuilder>();

            Dictionary <string, int>          argumentTable = new Dictionary <string, int>();
            Dictionary <string, LocalBuilder> localArgMap   = new Dictionary <string, LocalBuilder>();
            List <LocalBuilder> localArgs = new List <LocalBuilder>();

            if (!argsByRef)
            {
                for (int i = 0; i < argsNames.Length; i++)
                {
                    argumentTable.Add(argsNames[i], i);
                }
            }
            else
            {
                for (int i = 0; i < argsNames.Length; i++)
                {
                    LocalBuilder localForArg = ilGenerator.DeclareLocal(managedArgsTypes[i]);
                    localArgs.Add(localForArg);
                    localArgMap.Add(argsNames[i], localForArg);
                    ilGenerator.Emit(OpCodes.Ldarg, i);
                    switch (argsTypes[i])
                    {
                    default:
                        Debug.Assert(false);
                        throw new ArgumentException();

                    case DataTypes.eBoolean:
                    case DataTypes.eInteger:
                        ilGenerator.Emit(OpCodes.Ldind_I4);
                        break;

                    case DataTypes.eFloat:
                        ilGenerator.Emit(OpCodes.Ldind_R4);
                        break;

                    case DataTypes.eDouble:
                        ilGenerator.Emit(OpCodes.Ldind_R8);
                        break;

                    case DataTypes.eArrayOfBoolean:
                    case DataTypes.eArrayOfByte:
                    case DataTypes.eArrayOfInteger:
                    case DataTypes.eArrayOfFloat:
                    case DataTypes.eArrayOfDouble:
                        ilGenerator.Emit(OpCodes.Ldind_Ref);
                        break;
                    }
                    ilGenerator.Emit(OpCodes.Stloc, localForArg);
                }
            }

            ast.ILGen(
                this,
                new Compiler.ILGenContext(
                    ilGenerator,
                    argumentTable,
                    variableTable,
                    managedFunctionLinker,
                    argsByRef,
                    localArgMap));

            if (argsByRef)
            {
                for (int i = 0; i < argsNames.Length; i++)
                {
                    ilGenerator.Emit(OpCodes.Ldarg, i);
                    ilGenerator.Emit(OpCodes.Ldloc, localArgs[i]);
                    switch (argsTypes[i])
                    {
                    default:
                        Debug.Assert(false);
                        throw new ArgumentException();

                    case DataTypes.eBoolean:
                    case DataTypes.eInteger:
                        ilGenerator.Emit(OpCodes.Stind_I4);
                        break;

                    case DataTypes.eFloat:
                        ilGenerator.Emit(OpCodes.Stind_R4);
                        break;

                    case DataTypes.eDouble:
                        ilGenerator.Emit(OpCodes.Stind_R8);
                        break;

                    case DataTypes.eArrayOfBoolean:
                    case DataTypes.eArrayOfByte:
                    case DataTypes.eArrayOfInteger:
                    case DataTypes.eArrayOfFloat:
                    case DataTypes.eArrayOfDouble:
                        ilGenerator.Emit(OpCodes.Stind_Ref);
                        break;
                    }
                }
            }

            ilGenerator.Emit(OpCodes.Ret);


            // Generate shim (see explanation at InvokeShim)

            methodNameShim = String.Format("s{0}", methodSequenceNumber);
            MethodBuilder methodBuilderShim = cilAssembly.typeBuilder.DefineMethod(
                methodNameShim,
                MethodAttributes.Public | MethodAttributes.Static,
                typeof(void),
                new Type[0]);
            ILGenerator ilGeneratorShim = methodBuilderShim.GetILGenerator();

            ilGeneratorShim.Emit(OpCodes.Call, typeof(CILThreadLocalStorage).GetMethod("get_CurrentShimArg", BindingFlags.Public | BindingFlags.Static));
            LocalBuilder localShimArg = ilGeneratorShim.DeclareLocal(typeof(StackElement[]));

            ilGeneratorShim.Emit(OpCodes.Stloc, localShimArg);
            // Compute pointer to last valid stack element (retval slot). In the process, provide a null check
            // and a covering array bounds check. (Subsequent references are done by pointer arithmetic to avoid
            // redundant bounds checks.)
            LocalBuilder ptrToRetVal = null;

            if (Environment.Is64BitProcess)
            {
                ptrToRetVal = ilGeneratorShim.DeclareLocal(typeof(StackElement).MakeByRefType());
                ilGeneratorShim.Emit(OpCodes.Ldloc, localShimArg);
                ilGeneratorShim.Emit(OpCodes.Ldc_I4, (int)argsTypes.Length); // retaddr/retval slot
                ilGeneratorShim.Emit(OpCodes.Ldelema, typeof(StackElement));
                ilGeneratorShim.Emit(OpCodes.Stloc, ptrToRetVal);
            }
            for (int i = 0; i < argsTypes.Length; i++)
            {
                if (Environment.Is64BitProcess)
                {
                    ilGeneratorShim.Emit(OpCodes.Ldloc, ptrToRetVal);
                    ilGeneratorShim.Emit(OpCodes.Ldc_I4, (int)((i - argsTypes.Length) * StackElement.SizeOf()));
                    ilGeneratorShim.Emit(OpCodes.Add);
                }
                else
                {
                    // pointer arithmetic only works on 64-bit -- suspect bug in 32-bit JIT; generated code is very strange
                    // so fall back to regular array refs
                    ilGeneratorShim.Emit(OpCodes.Ldloc, localShimArg);
                    ilGeneratorShim.Emit(OpCodes.Ldc_I4, (int)i);
                    ilGeneratorShim.Emit(OpCodes.Ldelema, typeof(StackElement));
                }
                LocalBuilder locElemAddr = ilGeneratorShim.DeclareLocal(typeof(StackElement).MakeByRefType());
                ilGeneratorShim.Emit(OpCodes.Stloc, locElemAddr);
                ilGeneratorShim.Emit(OpCodes.Ldloc, locElemAddr);
                bool arrayType;
                switch (argsTypes[i])
                {
                default:
                    Debug.Assert(false);
                    throw new ArgumentException();

                case DataTypes.eBoolean:
                case DataTypes.eInteger:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ScalarOverlayType).GetField("Integer"));
                    arrayType = false;
                    break;

                case DataTypes.eFloat:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ScalarOverlayType).GetField("Float"));
                    arrayType = false;
                    break;

                case DataTypes.eDouble:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ScalarOverlayType).GetField("Double"));
                    arrayType = false;
                    break;

                case DataTypes.eArrayOfBoolean:
                case DataTypes.eArrayOfByte:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ReferenceOverlayType).GetField("arrayHandleByte"));
                    arrayType = true;
                    break;

                case DataTypes.eArrayOfInteger:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ReferenceOverlayType).GetField("arrayHandleInt32"));
                    arrayType = true;
                    break;

                case DataTypes.eArrayOfFloat:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ReferenceOverlayType).GetField("arrayHandleFloat"));
                    arrayType = true;
                    break;

                case DataTypes.eArrayOfDouble:
                    ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                    ilGeneratorShim.Emit(!argsByRef ? OpCodes.Ldfld : OpCodes.Ldflda, typeof(ReferenceOverlayType).GetField("arrayHandleDouble"));
                    arrayType = true;
                    break;
                }
                if (!argsByRef)
                {
                    ilGeneratorShim.Emit(OpCodes.Ldloc, locElemAddr);
                    if (arrayType)
                    {
                        ilGeneratorShim.Emit(OpCodes.Call, typeof(StackElement).GetMethod("ClearArray"));
                    }
                    else
                    {
                        ilGeneratorShim.Emit(OpCodes.Call, typeof(StackElement).GetMethod("ClearScalar"));
                    }
                }
            }
            ilGeneratorShim.Emit(OpCodes.Call, methodBuilder);

            LocalBuilder retVal = ilGeneratorShim.DeclareLocal(managedReturnType);

            ilGeneratorShim.Emit(OpCodes.Stloc, retVal);

            if (Environment.Is64BitProcess)
            {
                ilGeneratorShim.Emit(OpCodes.Ldloc, ptrToRetVal);
                ilGeneratorShim.Emit(OpCodes.Ldc_I4, (int)((!argsByRef ? 0 : argsTypes.Length) - argsTypes.Length) * StackElement.SizeOf());
                ilGeneratorShim.Emit(OpCodes.Add);
            }
            else
            {
                // pointer arithmetic only works on 64-bit -- suspect bug in 32-bit JIT; generated code is very strange
                // so fall back to regular array refs
                ilGeneratorShim.Emit(OpCodes.Ldloc, localShimArg);
                ilGeneratorShim.Emit(OpCodes.Ldc_I4, (int)(!argsByRef ? 0 : argsTypes.Length));
                ilGeneratorShim.Emit(OpCodes.Ldelema, typeof(StackElement));
            }
            switch (returnType)
            {
            default:
                Debug.Assert(false);
                throw new ArgumentException();

            case DataTypes.eBoolean:
            case DataTypes.eInteger:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ScalarOverlayType).GetField("Integer"));
                break;

            case DataTypes.eFloat:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ScalarOverlayType).GetField("Float"));
                break;

            case DataTypes.eDouble:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("Data"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ScalarOverlayType).GetField("Double"));
                break;

            case DataTypes.eArrayOfBoolean:
            case DataTypes.eArrayOfByte:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ReferenceOverlayType).GetField("arrayHandleByte"));
                break;

            case DataTypes.eArrayOfInteger:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ReferenceOverlayType).GetField("arrayHandleInt32"));
                break;

            case DataTypes.eArrayOfFloat:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ReferenceOverlayType).GetField("arrayHandleFloat"));
                break;

            case DataTypes.eArrayOfDouble:
                ilGeneratorShim.Emit(OpCodes.Ldflda, typeof(StackElement).GetField("reference"));
                ilGeneratorShim.Emit(OpCodes.Ldloc, retVal);
                ilGeneratorShim.Emit(OpCodes.Stfld, typeof(ReferenceOverlayType).GetField("arrayHandleDouble"));
                break;
            }

            if (!argsByRef)
            {
                ilGeneratorShim.Emit(OpCodes.Ldc_I4_0);
                ilGeneratorShim.Emit(OpCodes.Call, typeof(CILThreadLocalStorage).GetMethod("set_CurrentShimStackPtr", BindingFlags.Public | BindingFlags.Static));
            }

            ilGeneratorShim.Emit(OpCodes.Ret);
        }