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; } }
public void CopyFrom(ref StackElement source) { Data.int64 = source.Data.int64; reference.generic = source.reference.generic; }
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); }