public Signature(IKVM.Reflection.Universe universe, Reader reader, uint typeIndex) { this.TypeIndex = typeIndex; reader.ReadVarInt7(); //Function Type var parameters = this.ParameterTypes = new System.Type[reader.ReadVarUInt32()]; var ikvmParameters = this.IKVMParameterTypes = new IKVM.Reflection.Type[parameters.Length]; var rawParameters = this.RawParameterTypes = new ValueType[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { parameters[i] = (rawParameters[i] = (ValueType)reader.ReadVarInt7()).ToSystemType(); ikvmParameters[i] = universe.Import(parameters[i]); } var returns = this.ReturnTypes = new System.Type[reader.ReadVarUInt1()]; var ikvmReturns = this.IKVMReturnTypes = new IKVM.Reflection.Type[returns.Length]; var rawReturns = this.RawReturnTypes = new ValueType[returns.Length]; if (returns.Length > 1) { throw new ModuleLoadException("Multiple returns are not supported.", reader.Offset - 1); } for (var i = 0; i < returns.Length; i++) { returns[i] = (rawReturns[i] = (ValueType)reader.ReadVarInt7()).ToSystemType(); ikvmReturns[i] = universe.Import(returns[i]); } }
private IKVM.Reflection.Emit.MethodBuilder IKVMCreateStoreMethod(HelperMethod helper, IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var builder = context.ExportsBuilder.DefineMethod( $"☣ {helper}", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(void)), new[] { universe.Import(typeof(uint)), //Address universe.Import(this.Type.ToSystemType()), //Value universe.Import(typeof(uint)), //Offset context.ExportsBuilder.AsType(), } ); var il = builder.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_2); il.Emit(IKVM.Reflection.Emit.OpCodes.Add_Ovf_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_3); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, IKVMCreateRangeCheck(this.RangeCheckHelper, context, universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_3); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, context.Memory); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, Runtime.UnmanagedMemory.IKVMStartGetter(universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Add); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); il.Emit(this.IKVMEmittedOpCode); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(builder); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 2) { throw new StackTooSmallException(OpCode.Int64RotateLeft, 2, stack.Count); } var typeB = stack.Pop(); var typeA = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (typeA != ValueType.Int64) { throw new StackTypeInvalidException(OpCode.Int64RotateLeft, ValueType.Int64, typeA); } if (typeA != typeB) { throw new StackParameterMismatchException(OpCode.Int64RotateLeft, typeA, typeB); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Int64RotateLeft, (helper, c) => { var builder = c.ExportsBuilder.DefineMethod( "☣ Int64RotateLeft", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(ulong)), new[] { universe.Import(typeof(ulong)), universe.Import(typeof(long)), } ); var il = builder.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Conv_I4); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 63); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Shl); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 64); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Conv_I4); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 63); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(builder); } ]); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Float32CopySign, 1, stack.Count); } var type = stack.Pop(); if (type != ValueType.Float32) { throw new StackTypeInvalidException(OpCode.Float32CopySign, ValueType.Float32, type); } type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Float32) { throw new StackTypeInvalidException(OpCode.Float32CopySign, ValueType.Float32, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Float32CopySign, (helper, c) => { var builder = c.ExportsBuilder.DefineMethod( "☣ Float32CopySign", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(float)), new[] { universe.Import(typeof(float)), universe.Import(typeof(float)), } ); var il = builder.GetILGenerator(); var value = il.DeclareLocal(universe.Import(typeof(uint))); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarga_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldind_U4); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x7fffffff); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarga_S, 1); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldind_U4); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x80000000); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldloca_S, value); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldind_R4); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(builder); } ]); }
internal static IKVM.Reflection.Emit.MethodBuilder IKVMCreateHelper(HelperMethod helper, IKVMCompilationContext context, IKVM.Reflection.Universe universe) { Assert(context != null); var result = context.ExportsBuilder.DefineMethod( "☣ Int32CountOneBits", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(uint)), new[] { universe.Import(typeof(uint)) }); //All modern CPUs have a fast instruction specifically for this process, but there's no way to use it from .NET. //This algorithm is from https://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer var il = result.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x55555555); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x33333333); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_2); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x33333333); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Add); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_4); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Add); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x0f0f0f0f); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4, 0x01010101); il.Emit(IKVM.Reflection.Emit.OpCodes.Mul); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 24); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(result); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Int64CountTrailingZeroes, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Int64) { throw new StackTypeInvalidException(OpCode.Int64CountTrailingZeroes, ValueType.Int64, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Int64CountTrailingZeroes, (helper, c) => { Assert(c != null); var result = context.ExportsBuilder.DefineMethod( "☣ Int64CountTrailingZeroes", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(long)), new[] { universe.Import(typeof(ulong)) }); //All modern CPUs have a fast instruction specifically for this process, but there's no way to use it from .NET. //Based on the algorithm found here: http://aggregate.org/MAGIC/#Trailing%20Zero%20Count var il = result.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Neg); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Conv_I8); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, Int64CountOneBits.IKVMCreateHelper(HelperMethod.Int64CountOneBits, context, universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(result); } ]); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { Assert(context != null); var returns = context.Signature.RawReturnTypes; var stack = context.Stack; Assert(stack != null); var returnsLength = returns.Length; Assert(returnsLength == 0 || returnsLength == 1); //WebAssembly doesn't currently offer multiple returns, which should be blocked earlier. var stackCount = stack.Count; if (stackCount < returnsLength) { throw new StackTooSmallException(OpCode.Return, returnsLength, 0); } if (stackCount > returnsLength) { if (returnsLength == 0) { for (var i = 0; i < stackCount - returnsLength; i++) { context.Emit(IKVM.Reflection.Emit.OpCodes.Pop); } } else { var value = context.DeclareLocal(universe.Import(returns[0].ToSystemType())); context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc, value.LocalIndex); for (var i = 0; i < stackCount - returnsLength; i++) { context.Emit(IKVM.Reflection.Emit.OpCodes.Pop); } context.Emit(IKVM.Reflection.Emit.OpCodes.Ldloc, value.LocalIndex); } } else if (returnsLength == 1) { var type = stack.Pop(); if (type != returns[0]) { throw new StackTypeInvalidException(OpCode.Return, returns[0], type); } } context.Emit(IKVM.Reflection.Emit.OpCodes.Ret); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Float32ReinterpretInt32, 1, stack.Count); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.Float32ReinterpretInt32, ValueType.Int32, type); } stack.Push(ValueType.Float32); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Float32ReinterpretInt32, (helper, c) => { var builder = c.ExportsBuilder.DefineMethod( "☣ Float32ReinterpretInt32", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(float)), new[] { universe.Import(typeof(int)), } ); var il = builder.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarga_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldind_R4); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(builder); } ]); }
public Signature(ValueType returnType) { IKVM.Reflection.Universe universe = new IKVM.Reflection.Universe(); this.TypeIndex = uint.MaxValue; this.ParameterTypes = new System.Type[0]; this.IKVMParameterTypes = new IKVM.Reflection.Type[0]; this.RawParameterTypes = new ValueType[0]; this.ReturnTypes = new[] { returnType.ToSystemType() }; this.IKVMReturnTypes = new IKVM.Reflection.Type[this.ReturnTypes.Length]; for (int i = 0; i < this.ReturnTypes.Length; i++) { this.IKVMReturnTypes[i] = universe.Import(this.ReturnTypes[i]); } this.RawReturnTypes = new[] { returnType }; }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var signature = context.Types[this.Type]; var paramTypes = signature.RawParameterTypes; var returnTypes = signature.RawReturnTypes; var stack = context.Stack; if (stack.Count < paramTypes.Length) { throw new StackTooSmallException(OpCode.CallIndirect, paramTypes.Length, stack.Count); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.CallIndirect, ValueType.Int32, type); } for (var i = paramTypes.Length - 1; i >= 0; i--) { type = stack.Pop(); if (type != paramTypes[i]) { throw new StackTypeInvalidException(OpCode.CallIndirect, paramTypes[i], type); } } for (var i = 0; i < returnTypes.Length; i++) { stack.Push(returnTypes[i]); } Int32Constant.Emit(context, checked ((int)this.Type)); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.GetFunctionPointer]); context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc, context.IndirectPointerLocal.LocalIndex); context.EmitLoadThis(); context.Emit(IKVM.Reflection.Emit.OpCodes.Ldloc, context.IndirectPointerLocal.LocalIndex); context.EmitCalli( signature.IKVMReturnTypes.Length == 0 ? universe.Import(typeof(void)) : signature.IKVMReturnTypes[0], signature.IKVMParameterTypes.Concat(new[] { context.ExportsBuilder.AsType() }).ToArray( )); }
internal static IKVM.Reflection.MethodInfo IKVMStartGetter(IKVM.Reflection.Universe universe) { IKVM.Reflection.MethodInfo info = new RegeneratingWeakReference <IKVM.Reflection.MethodInfo>(() => universe.Import(typeof(UnmanagedMemory)).GetTypeInfo().DeclaredProperties.Where(prop => prop.Name == nameof(Start)).First().GetMethod); return(info); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Int32CountLeadingZeroes, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.Int32CountLeadingZeroes, ValueType.Int32, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Int32CountLeadingZeroes, (helper, c) => { Assert(c != null); var result = context.ExportsBuilder.DefineMethod( "☣ Int32CountLeadingZeroes", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(uint)), new[] { universe.Import(typeof(uint)) }); //All modern CPUs have a fast instruction specifically for this process, but there's no way to use it from .NET. //This algorithm is from https://stackoverflow.com/questions/10439242/count-leading-zeroes-in-an-int32 var il = result.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_2); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_4); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_8); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 16); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 32); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, Int32CountOneBits.IKVMCreateHelper(HelperMethod.Int32CountOneBits, context, universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(result); } ]); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { context.Emit(IKVM.Reflection.Emit.OpCodes.Newobj, universe.Import(typeof(UnreachableException)).GetTypeInfo().DeclaredConstructors.First(c => c.GetParameters().Length == 0)); context.Emit(IKVM.Reflection.Emit.OpCodes.Throw); }
static IKVM.Reflection.Emit.MethodBuilder IKVMCreateSelectHelper(HelperMethod helper, IKVMCompilationContext context, IKVM.Reflection.Universe universe) { Assert(context != null); IKVM.Reflection.Emit.MethodBuilder builder; switch (helper) { default: Fail("Attempted to obtain an unknown helper method."); return(null); case HelperMethod.SelectInt32: builder = context.ExportsBuilder.DefineMethod( "☣ Select Int32", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(int)), new[] { universe.Import(typeof(int)), universe.Import(typeof(int)), universe.Import(typeof(int)), } ); break; case HelperMethod.SelectInt64: builder = context.ExportsBuilder.DefineMethod( "☣ Select Int64", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(long)), new[] { universe.Import(typeof(long)), universe.Import(typeof(long)), universe.Import(typeof(int)), } ); break; case HelperMethod.SelectFloat32: builder = context.ExportsBuilder.DefineMethod( "☣ Select Float32", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(float)), new[] { universe.Import(typeof(float)), universe.Import(typeof(float)), universe.Import(typeof(int)), } ); break; case HelperMethod.SelectFloat64: builder = context.ExportsBuilder.DefineMethod( "☣ Select Float64", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(double)), new[] { universe.Import(typeof(double)), universe.Import(typeof(double)), universe.Import(typeof(int)), } ); break; } var il = builder.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_2); var @true = il.DefineLabel(); il.Emit(IKVM.Reflection.Emit.OpCodes.Brtrue_S, @true); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); il.MarkLabel(@true); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(builder); }