Example #1
0
        public ObjectInstance Alloc()
        {
            _heapMemory[++_ptr] = new ObjectInstance();

            return _heapMemory[_ptr];
        }
Example #2
0
        private void DoCallWork(bool virtualCall, ObjectInstance thisArg = null, MethodReference methTok = null, object callInfo = null)
        {
            var op = (methTok ?? _instructions[_instructionPtr].Operand) as MethodReference;

            var methDef = op.Resolve();
            {
                if (methDef.IsInternalCall)
                {
                    InvokeInternalCall(methDef);
                    return;
                }
            }
            _callThisArg = thisArg; // for .ctor

            var totalSigArgs = 0;
            if (false)
            {
                
            }
            else
            {
                totalSigArgs = methDef.Parameters.Count + (methDef.HasThis ? 1 : 0);
            }

            // Note that "totalNativeArgs()" includes space for ret buff arg.
            var nSlots = totalSigArgs + 1;
            if (methDef.HasGenericParameters) nSlots++;
            if (methDef.IsVarArg()) nSlots++;

            // Make sure that the operand stack has the required number of arguments.
            // (Note that this is IL args, not native.)
            // 

            // The total number of arguments on the IL stack.  Initially we assume that all the IL arguments
            // the callee expects are on the stack, but may be adjusted downwards if the "this" argument
            // is provided by an allocation (the call is to a constructor).
            var totalArgsOnILStack = totalSigArgs;
            if (_callThisArg != null)
            {
                Debug.Assert(totalArgsOnILStack > 0);
                totalArgsOnILStack--;
            }

            var totalArgs = nSlots;
            var LOCAL_ARG_SLOTS = 8;
            var localArgs = new ObjectInstance[(totalArgs > LOCAL_ARG_SLOTS) ? totalArgs : LOCAL_ARG_SLOTS];
            // Current on-stack argument index.
            var arg = 0;

            // FIXME: stack (mayuki)
            var tmpArgsStack = _opStack.ToArray();
            var curArgSlot = 0;
            if (methDef.HasThis)
            {
                if (_callThisArg != null)
                {
                    localArgs[curArgSlot] = _callThisArg;
                }
                else
                {
                    localArgs[curArgSlot] = tmpArgsStack[tmpArgsStack.Length - (arg+1)];
                    arg++;
                }
                curArgSlot++;
            }

            // Now we do the non-this arguments.
            for (; arg < totalArgsOnILStack; arg++)
            {
                localArgs[curArgSlot] = tmpArgsStack[tmpArgsStack.Length - (arg + 1)];
                curArgSlot++;
            }

            if (methDef.HasThis)
            {
                if (thisArg == null)
                {
                    thisArg = tmpArgsStack[0];
                }
                else
                {
                    thisArg = _callThisArg;
                }
            }

            ObjectInstance retVal;
            MethodDefinition exactMethToCall = methDef;
            if (methDef.DeclaringType.IsInterface)
            {
                var slot = thisArg.MethodTable.InterfaceMethodSlotMap[methDef];
                exactMethToCall = thisArg.MethodTable.MethodSlots[slot].Definition;
            }
            else
            {
                if (virtualCall && methDef.IsVirtual)
                {
                    var methodDesc = _classLoader.LookupMethodDescFromMethodDef(methDef);
                    exactMethToCall = thisArg.MethodTable.MethodSlots[methodDesc.Slot].Definition;
                }
            }

            retVal = InterpretMethodBody(exactMethToCall, true, localArgs, null);

            // retval
            for (var i = 0; i < totalArgsOnILStack; i++)
            {
                _opStack.Pop();
            }

            if (methDef.ReturnType.FullName != "System.Void") // TODO: should refer typevalue enum
            {
                _opStack.Push(retVal);
            }
        }
Example #3
0
        private void ExecuteMethodCore(out ObjectInstance retVal, out bool doJmpCall, out MemberReference jmpCallToken)
        {
            jmpCallToken = null;
            doJmpCall = false;
            retVal = null;

            for (; _instructions.Length > _instructionPtr; _instructionPtr++)
            {
                var inst = _instructions[_instructionPtr];

                if (inst.OpCode == OpCodes.Nop)
                {
                    continue;
                }
                else if (inst.OpCode == OpCodes.Break)
                {
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldarg_0)
                {
                    LdArg(0);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldarg_1)
                {
                    LdArg(1);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldarg_2)
                {
                    LdArg(2);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldarg_3)
                {
                    LdArg(3);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldloc_0)
                {
                    LdLoc(0);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldloc_1)
                {
                    LdLoc(1);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldloc_2)
                {
                    LdLoc(2);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldloc_3)
                {
                    LdLoc(3);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Stloc_0)
                {
                    StLoc(0);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stloc_1)
                {
                    StLoc(1);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stloc_2)
                {
                    StLoc(2);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stloc_3)
                {
                    StLoc(3);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldarg_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    LdArg(index);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldarga_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    LdArgA(index);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Starg_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    StArg(index);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldloc_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    LdLoc(index);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldloca_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    LdLocA(index);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stloc_S)
                {
                    // TODO: get index directly
                    var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
                    StLoc(index);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldnull)
                {
                    Ldnull();
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldc_I4_M1)
                {
                    LdIcon(-1);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_0)
                {
                    LdIcon(0);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_1)
                {
                    LdIcon(1);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_2)
                {
                    LdIcon(2);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_3)
                {
                    LdIcon(3);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_4)
                {
                    LdIcon(4);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_5)
                {
                    LdIcon(5);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_6)
                {
                    LdIcon(6);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_7)
                {
                    LdIcon(7);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_8)
                {
                    LdIcon(8);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4_S)
                {
                    LdIcon(inst.Operand);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldc_I4)
                {
                    LdIcon(inst.Operand);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldstr)
                {
                    LdStr();
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ldfld)
                {
                    LdFld();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldflda)
                {
                    LdFldA();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stfld)
                {
                    StFld();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldsfld)
                {
                    LdSFld();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Ldsflda)
                {
                    LdSFldA();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stsfld)
                {
                    StSFld();
                    continue;
                }
                else if (inst.OpCode == OpCodes.Stobj)
                {
                    StObj();
                    continue;
                }

                // ...
                else if (inst.OpCode == OpCodes.Add)
                {
                    Add(checkOverflow: false, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Add_Ovf)
                {
                    Add(checkOverflow: true, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Add_Ovf_Un)
                {
                    Add(checkOverflow: true, unsigned: true);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Sub)
                {
                    Sub(checkOverflow: false, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Sub_Ovf)
                {
                    Sub(checkOverflow: true, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Sub_Ovf_Un)
                {
                    Sub(checkOverflow: true, unsigned: true);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Mul)
                {
                    Mul(checkOverflow: false, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Mul_Ovf)
                {
                    Mul(checkOverflow: true, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Mul_Ovf_Un)
                {
                    Mul(checkOverflow: true, unsigned: true);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Div)
                {
                    Div(checkOverflow: true, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Div_Un)
                {
                    Div(checkOverflow: true, unsigned: true);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Rem)
                {
                    Rem(checkOverflow: true, unsigned: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Rem_Un)
                {
                    Rem(checkOverflow: true, unsigned: true);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Newobj)
                {
                    NewObj();
                    continue;
                }

                else if (inst.OpCode == OpCodes.Box)
                {
                    // TODO: not implemented yet
                    continue;
                }

                else if (inst.OpCode == OpCodes.Call)
                {
                    Call(virtualCall: false);
                    continue;
                }
                else if (inst.OpCode == OpCodes.Callvirt)
                {
                    Call(virtualCall: true);
                    continue;
                }

                else if (inst.OpCode == OpCodes.Ret)
                {
                    // TODO: use reference or type
                    if (_methInfo2.ReturnType.Namespace == "System" && _methInfo2.ReturnType.Name == "Void")
                    {
                        Debug.Assert(_opStack.Count == 0);
                    }
                    else
                    {
                        Debug.Assert(_opStack.Count != 0);
                        retVal = _opStack.Pop();
                    }

                    return; // goto ExitEvalLoop;
                }

                else if (inst.OpCode == OpCodes.Br_S)
                {
                    // TODO: below code is too slow
                    _instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
                    continue;
                }
                else if (inst.OpCode == OpCodes.Leave_S)
                {
                    _opStack.Clear();
                    throw ThrowHelper.NotImplementedYet;
                }
                else if (inst.OpCode == OpCodes.Brfalse_S)
                {
                    // TODO: below code is too slow
                    var value = _opStack.Pop();
                    if ((value.IsReference && value.IsNull) || value.I == 0)
                    {
                        _instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
                    }
                    continue;
                }
                else if (inst.OpCode == OpCodes.Brtrue_S)
                {
                    // TODO: below code is too slow
                    var value = _opStack.Pop();
                    if ((value.IsReference && !value.IsNull) || value.I != 0)
                    {
                        _instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
                    }
                    continue;
                }

                // case CEE_PREFIX1:
                else if (inst.OpCode == OpCodes.Arglist)
                {
                    throw ThrowHelper.NotImplementedYet;
                }
                else if (inst.OpCode == OpCodes.Ceq)
                {
                    var value2 = _opStack.Pop();
                    var value1 = _opStack.Pop();

                    if (value1.Type == CorInfoType.Class)
                    {
                        _opStack.Push(ObjectInstance.FromClrObject((value1 == value2) ? 1 : 0));
                    }
                    else if (value1.Type == CorInfoType.String)
                    {
                        _opStack.Push(ObjectInstance.FromClrObject((value1.ObjectRef == value2.ObjectRef) ? 1 : 0));
                    }
                    else
                    {
                        _opStack.Push(ObjectInstance.FromClrObject((value1.I == value2.I) ? 1 : 0));
                    }
                    continue;
                }
                else if (inst.OpCode == OpCodes.Cgt)
                {
                    var value2 = _opStack.Pop().I;
                    var value1 = _opStack.Pop().I;
                    _opStack.Push(ObjectInstance.FromClrObject((value1 > value2) ? 1 : 0));
                    continue;
                }
                else if (inst.OpCode == OpCodes.Cgt_Un)
                {
                    var value2 = _opStack.Pop();
                    var value1 = _opStack.Pop();

                    if (value1.Type == CorInfoType.Class)
                    {
                        _opStack.Push(ObjectInstance.FromClrObject((value1 != value2) ? 1 : 0));
                    }
                    else if (value1.Type == CorInfoType.String)
                    {
                        _opStack.Push(ObjectInstance.FromClrObject((value1.ObjectRef != value2.ObjectRef) ? 1 : 0));
                    }
                    else
                    {
                        _opStack.Push(ObjectInstance.FromClrObject(((ulong)value1.I > (ulong)value2.I) ? 1 : 0));
                    }

                    continue;
                }
                else if (inst.OpCode == OpCodes.Clt)
                {
                    var value2 = _opStack.Pop().I;
                    var value1 = _opStack.Pop().I;
                    _opStack.Push(ObjectInstance.FromClrObject((value1 < value2) ? 1 : 0));
                    continue;
                }
                else if (inst.OpCode == OpCodes.Clt_Un)
                {
                    var value2 = (ulong)_opStack.Pop().I;
                    var value1 = (ulong)_opStack.Pop().I;
                    _opStack.Push(ObjectInstance.FromClrObject((value1 < value2) ? 1 : 0));
                    continue;
                }

                else if (inst.OpCode == OpCodes.Throw)
                {
                    Throw();
                    continue;
                }

                throw new InazumaExecutionException("Unknown OpCode: " + inst.OpCode.ToString());
            }
        }
Example #4
0
        private void ExecuteMethod(out ObjectInstance retVal, out bool doJmpCall, out MemberReference jmpCallToken)
        {
            jmpCallToken = null;
            doJmpCall = false;
            retVal = null;

            EvalLoop:
            try
            {
                this.ExecuteMethodCore(out retVal, out doJmpCall, out jmpCallToken);
            }
            catch (InazumaRuntimeException ex)
            {
                // TODO: check throwable
                // TODO: isuncatchable (ThreadAbort)
                var handleEx = false;

                if (_methInfo2.Body.HasExceptionHandlers)
                {
                    var curOffset = _instructions[_instructionPtr].Offset;

                    // Perform a filter scan or regular walk of the EH Table. Filter scan is performed when
                    // we are evaluating a series of filters to handle the exception until the first handler
                    // (filter's or otherwise) that will handle the exception.
                    foreach (var exceptionHandler in _methInfo2.Body.ExceptionHandlers)
                    {
                        var handlerOffset = 0;

                        // First, is the current offset in the try block?
                        if (exceptionHandler.TryStart.Offset <= curOffset && exceptionHandler.TryEnd.Offset >= curOffset)
                        {
                            // CORINFO_EH_CLAUSE_NONE represents 'catch' blocks
                            if (exceptionHandler.FilterStart == null)
                            {
                                // Now, does the catch block handle the thrown exception type?
                                var excType = _classLoader.LoadTypeFromTypeRef(exceptionHandler.CatchType);
                                if (ex.ExceptionObject.MethodTable == excType)
                                {
                                    _opStack.Clear();
                                    _opStack.Push(ex.ExceptionObject);
                                    handlerOffset = _instructions.Select((x, i) => new { Index = i, IsMatched = x == exceptionHandler.HandlerStart }).First(x => x.IsMatched).Index; // TODO: FIXME
                                    handleEx = true;
                                    //_filterNextScan = 0;
                                }
                            }
                            else
                            {
                                throw ThrowHelper.NotImplementedYet;
                            }

                            // Reset the interpreter loop in preparation of calling the handler.
                            if (handleEx)
                            {
                                // Set the IL offset of the handler.
                                _instructionPtr = handlerOffset;

                                // If an exception occurs while attempting to leave a protected scope,
                                // we empty the 'leave' info stack upon entering the handler.
                                // TODO: infoStack

                                // Some things are set up before a call, and must be cleared on an exception caught be the caller.
                                // A method that returns a struct allocates local space for the return value, and "registers" that
                                // space and the type so that it's scanned if a GC happens.  "Unregister" it if we throw an exception
                                // in the call, and handle it in the caller.  (If it's not handled by the caller, the Interpreter is
                                // deallocated, so it's value doesn't matter.)
                                _callThisArg = null;
                                _args.Clear();

                                break;
                            }
                        }
                    }
                }

                if (handleEx)
                {
                    goto EvalLoop;
                }
                else
                {
                    throw;
                }
            }
        }
 public InazumaRuntimeException(ObjectInstance exception)
     : base("Runtime Exception")
 {
     ExceptionObject = exception;
 }