internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.SetGlobal, 1, stack.Count); } CompileIKVM.GlobalInfo setter; try { setter = context.GlobalSetters[this.Index]; } catch (System.IndexOutOfRangeException x) { throw new CompilerException($"Global at index {this.Index} does not exist.", x); } if (setter == null) { throw new CompilerException($"Global at index {this.Index} is immutable."); } var type = stack.Pop(); if (type != setter.Type) { throw new StackTypeInvalidException(OpCode.SetGlobal, setter.Type, type); } context.EmitLoadThis(); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, setter.Builder); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { if (context.GlobalGetters == null) { throw new CompilerException("Can't use GetGlobal without a global section."); } CompileIKVM.GlobalInfo getter; try { getter = context.GlobalGetters[this.Index]; } catch (System.IndexOutOfRangeException x) { throw new CompilerException($"Global at index {this.Index} does not exist.", x); } if (getter.IsMutable) { context.EmitLoadThis(); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, getter.Builder); context.Stack.Push(getter.Type); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { base.CompileIKVM(context, universe); context.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_0); context.Emit(IKVM.Reflection.Emit.OpCodes.Ceq); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 2) { throw new StackTooSmallException(this.OpCode, 2, stack.Count); } var type = stack.Pop(); if (type != this.Type) { throw new StackTypeInvalidException(this.OpCode, this.Type, type); } type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(this.OpCode, ValueType.Int32, type); } Int32Constant.Emit(context, (int)this.Offset); context.EmitLoadThis(); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, this.IKVMCreateStoreMethod(this.StoreHelper, context, universe)); }
internal override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 2) { throw new StackTooSmallException(this.OpCode, 2, stack.Count); } var typeB = stack.Pop(); var typeA = stack.Pop(); if (typeA != this.ValueType) { throw new StackTypeInvalidException(this.OpCode, this.ValueType, typeA); } if (typeA != typeB) { throw new StackParameterMismatchException(this.OpCode, typeA, typeB); } stack.Push(ValueType.Int32); context.Emit(this.IKVMEmittedOpCode); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count == 0) { throw new StackTooSmallException(this.OpCode, 1, 0); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(this.OpCode, ValueType.Int32, type); } if (this.Offset != 0) { Int32Constant.Emit(context, (int)this.Offset); context.Emit(IKVM.Reflection.Emit.OpCodes.Add_Ovf_Un); } this.IKVMEmitRangeCheck(context, universe); context.EmitLoadThis(); context.Emit(IKVM.Reflection.Emit.OpCodes.Ldfld, context.Memory); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, Runtime.UnmanagedMemory.IKVMStartGetter(universe)); context.Emit(IKVM.Reflection.Emit.OpCodes.Add); byte alignment; switch (this.Flags & Options.Align8) { default: //Impossible to hit, but needed to avoid compiler error the about alignment variable. case Options.Align1: alignment = 1; break; case Options.Align2: alignment = 2; break; case Options.Align4: alignment = 4; break; case Options.Align8: alignment = 8; break; } if (alignment != 4) { context.Emit(IKVM.Reflection.Emit.OpCodes.Unaligned, alignment); } context.Emit(this.IKVMEmittedOpCode); var conversion = this.IKVMConversionOpCode; if (conversion != IKVM.Reflection.Emit.OpCodes.Nop) { context.Emit(conversion); } stack.Push(this.Type); }
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 loopStart = context.DefineLabel(); context.Labels.Add(checked ((uint)context.Depth.Count), loopStart); context.Depth.Push(Type); context.MarkLabel(loopStart); context.LoopLabels.Add(loopStart); }
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 sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var afterElse = context.DefineLabel(); context.Emit(IKVM.Reflection.Emit.OpCodes.Br, afterElse); var target = checked ((uint)context.Depth.Count) - 1; context.MarkLabel(context.Labels[target]); context.Labels[target] = afterElse; }
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 == 0) { throw new StackTooSmallException(OpCode.Drop, 1, 0); } stack.Pop(); context.Emit(IKVM.Reflection.Emit.OpCodes.Pop); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { Assert(context != null); var stack = context.Stack; Assert(stack != null); if (stack.Count < 3) { throw new StackTooSmallException(OpCode.Select, 3, stack.Count); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.Select, ValueType.Int32, type); } var typeB = stack.Pop(); var typeA = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (typeA != typeB) { throw new StackParameterMismatchException(OpCode.Select, typeA, typeB); } HelperMethod helper; switch (typeA) { default: //This shouldn't be possible due to previous validations. Fail("Unknown ValueType."); return; case ValueType.Int32: helper = HelperMethod.SelectInt32; break; case ValueType.Int64: helper = HelperMethod.SelectInt64; break; case ValueType.Float32: helper = HelperMethod.SelectFloat32; break; case ValueType.Float64: helper = HelperMethod.SelectFloat64; break; } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, IKVMCreateSelectHelper(helper, context, universe)); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(this.OpCode, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != this.ValueType) { throw new StackTypeInvalidException(this.OpCode, this.ValueType, type); } context.Emit(this.IKVMEmittedOpCode); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Int32CountOneBits, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.Int32CountOneBits, ValueType.Int32, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, IKVMCreateHelper(HelperMethod.Int32CountOneBits, context, universe)); }
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 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) { var stack = context.Stack; if (stack.Count == 0) { throw new StackTooSmallException(this.OpCode, 1, 0); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Float32) { throw new StackTypeInvalidException(this.OpCode, ValueType.Float32, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Conv_R8); context.Emit(IKVM.Reflection.Emit.OpCodes.Call, this.IKVMMethodInfo); context.Emit(IKVM.Reflection.Emit.OpCodes.Conv_R4); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(this.OpCode, 1, stack.Count); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(this.OpCode, ValueType.Int32, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Conv_U8); stack.Push(ValueType.Int64); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count == 0) { throw new StackTooSmallException(OpCode.Float32DemoteFloat64, 1, 0); } var type = stack.Pop(); if (type != ValueType.Float64) { throw new StackTypeInvalidException(OpCode.Float32DemoteFloat64, ValueType.Float64, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Conv_R4); stack.Push(ValueType.Float32); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { if (this.Index >= context.Methods.Length) { throw new CompilerException($"Function for index {this.Index} requseted, the assembly contains only {context.Methods.Length}."); } var signature = context.FunctionSignatures[this.Index]; var paramTypes = signature.RawParameterTypes; var returnTypes = signature.RawReturnTypes; var stack = context.Stack; if (stack.Count < paramTypes.Length) { throw new StackTooSmallException(this.OpCode, paramTypes.Length, stack.Count); } for (var i = paramTypes.Length - 1; i >= 0; i--) { var type = stack.Pop(); if (type != paramTypes[i]) { throw new StackTypeInvalidException(this.OpCode, paramTypes[i], type); } } for (var i = 0; i < returnTypes.Length; i++) { stack.Push(returnTypes[i]); } var target = context.Methods[this.Index]; if (target is IKVM.Reflection.Emit.MethodBuilder) //Indicates a dynamically generated method. { context.EmitLoadThis(); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, target); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count == 0) { throw new StackTooSmallException(OpCode.If, 1, 0); } var type = stack.Pop(); if (type != ValueType.Int32) { throw new StackTypeInvalidException(OpCode.If, ValueType.Int32, type); } var label = context.DefineLabel(); context.Labels.Add(checked ((uint)context.Depth.Count), label); context.Depth.Push(Type); context.Emit(IKVM.Reflection.Emit.OpCodes.Brfalse, label); }
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); } ]); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 2) { throw new StackTooSmallException(this.OpCode, 2, stack.Count); } var typeB = stack.Pop(); var typeA = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (typeA != this.ValueType) { throw new StackTypeInvalidException(this.OpCode, this.ValueType, typeA); } if (typeA != typeB) { throw new StackParameterMismatchException(this.OpCode, typeA, typeB); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, this.IKVMMethodInfo); }
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.Labels.Add(checked ((uint)context.Depth.Count), context.DefineLabel()); context.Depth.Push(Type); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.TeeLocal, 1, stack.Count); } var setType = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (setType != context.Locals[this.Index]) { throw new StackTypeInvalidException(OpCode.TeeLocal, context.Locals[this.Index], setType); } context.Emit(IKVM.Reflection.Emit.OpCodes.Dup); var localIndex = this.Index - context.Signature.ParameterTypes.Length; if (localIndex < 0) { //Referring to a parameter. if (this.Index <= byte.MaxValue) { context.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, checked ((byte)this.Index)); } else { context.Emit(IKVM.Reflection.Emit.OpCodes.Starg, checked ((ushort)this.Index)); } } else { //Referring to a local. switch (localIndex) { default: if (localIndex > 65534) // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.stloc { throw new CompilerException($"Implementation limit exceeded: maximum accessible local index is 65534, tried to access {localIndex}."); } if (localIndex <= byte.MaxValue) { context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_S, (byte)localIndex); } else { context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc, checked ((ushort)localIndex)); } break; case 0: context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_0); break; case 1: context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_1); break; case 2: context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_2); break; case 3: context.Emit(IKVM.Reflection.Emit.OpCodes.Stloc_3); break; } } }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { context.Emit(IKVM.Reflection.Emit.OpCodes.Nop); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { Assert(context != null); Assert(context.Depth != null); var stack = context.Stack; Assert(stack != null); var blockType = context.Depth.Count == 0 ? BlockType.Empty : context.Depth.Pop(); if (context.Depth.Count == 0) { if (context.Previous == OpCode.Return) { return; //WebAssembly requires functions to end on "end", but an immediately previous return is allowed. } var returns = context.Signature.RawReturnTypes; var returnsLength = returns.Length; if (returnsLength != stack.Count) { throw new StackSizeIncorrectException(OpCode.End, returnsLength, stack.Count); } Assert(returnsLength == 0 || returnsLength == 1); //WebAssembly doesn't currently offer multiple returns, which should be blocked earlier. if (returnsLength == 1) { var type = stack.Pop(); if (type != returns[0]) { throw new StackTypeInvalidException(OpCode.End, returns[0], type); } } context.Emit(IKVM.Reflection.Emit.OpCodes.Ret); } else { if (blockType.TryToValueType(out var expectedType)) { var type = stack.Peek(); if (type != expectedType) { throw new StackTypeInvalidException(OpCode.End, expectedType, type); } } var depth = checked ((uint)context.Depth.Count); var label = context.Labels[depth]; if (!context.LoopLabels.Contains(label)) //Loop labels are marked where defined. { context.MarkLabel(label); } else { context.LoopLabels.Remove(label); } context.Labels.Remove(depth); } }
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); }