Пример #1
0
        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);
        }
Пример #2
0
        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;
        }
Пример #3
0
        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);
            }
        }