示例#1
0
        public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
        {
            OpMethod xMethod       = (OpMethod)aOpCode;
            string   xCurrentLabel = GetLabel(aMethod, aOpCode);
            var      xType         = xMethod.Value.DeclaringType;

            Assemble(Assembler, aMethod, xMethod, xCurrentLabel, xType, xMethod.Value);
        }
示例#2
0
        public static void Assemble(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor)
        {
            // call cctor:
            if (aMethod != null)
            {
                var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault();
                if (xCctor != null)
                {
                    XS.Call(LabelName.Get(xCctor));
                    ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck");
                    XS.Label(".AfterCCTorExceptionCheck");
                }
            }

            if (objectType.IsValueType)
            {
                #region Valuetypes

                XS.Comment("ValueType");

                /*
                 * Current sitation on stack:
                 *   $ESP       Arg
                 *   $ESP+..    other items
                 *
                 * What should happen:
                 *  + The stack should be increased to allow space to contain:
                 *         + .ctor arguments
                 *         + struct _pointer_ (ref to start of emptied space)
                 *         + empty space for struct
                 *  + arguments should be copied to the new place
                 *  + old place where arguments were should be cleared
                 *  + pointer should be set
                 *  + call .ctor
                 */

                // Size of return value - we need to make room for this on the stack.
                uint xStorageSize = Align(SizeOfType(objectType), 4);
                XS.Comment("StorageSize: " + xStorageSize);
                if (xStorageSize == 0)
                {
                    throw new Exception("ValueType storage size cannot be 0.");
                }

                //var xStorageSize = aCtorDeclTypeInfo.StorageSize;

                uint xArgSize       = 0;
                var  xParameterList = constructor.GetParameters();
                foreach (var xParam in xParameterList)
                {
                    xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4);
                }
                XS.Comment("ArgSize: " + xArgSize);

                // Set ESP so we can push the struct ptr
                int xShift = (int)(xArgSize - xStorageSize);
                XS.Comment("Shift: " + xShift);
                if (xShift < 0)
                {
                    XS.Sub(XSRegisters.ESP, (uint)Math.Abs(xShift));
                }
                else if (xShift > 0)
                {
                    XS.Add(XSRegisters.ESP, (uint)xShift);
                }

                // push struct ptr
                XS.Push(XSRegisters.ESP);

                // Shift args
                foreach (var xParam in xParameterList)
                {
                    uint xArgSizeForThis = Align(SizeOfType(xParam.ParameterType), 4);
                    for (int i = 1; i <= xArgSizeForThis / 4; i++)
                    {
                        new CPUx86.Push {
                            DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xStorageSize
                        };
                    }
                }

                new Call(aAssembler).Execute(aMethod, xMethod);

                // Need to put these *after* the call because the Call pops the args from the stack
                // and we have mucked about on the stack, so this makes it right before the next
                // op.

                #endregion Valuetypes
            }
            else
            {
                // If not ValueType, then we need gc

                var xParams = constructor.GetParameters();

                // array length + 8
                bool xHasCalcSize = false;

                #region Special string handling
                // try calculating size:
                if (constructor.DeclaringType == typeof(string))
                {
                    if (xParams.Length == 1 &&
                        xParams[0].ParameterType == typeof(char[]))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceIsIndirect: true);

                        // EAX contains a memory handle now, lets dereference it to a pointer
                        XS.Set(EAX, EAX, sourceIsIndirect: true);
                        XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceDisplacement: 8);
                        XS.Set(XSRegisters.EDX, 2);
                        XS.Multiply(XSRegisters.EDX);
                        XS.Push(XSRegisters.EAX);
                    }
                    else if (xParams.Length == 3 &&
                             (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) &&
                             xParams[1].ParameterType == typeof(int) &&
                             xParams[2].ParameterType == typeof(int))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceIsIndirect: true);
                        XS.ShiftLeft(XSRegisters.EAX, 1);
                        XS.Push(XSRegisters.EAX);
                    }
                    else if (xParams.Length == 2 &&
                             xParams[0].ParameterType == typeof(char) &&
                             xParams[1].ParameterType == typeof(int))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceIsIndirect: true);
                        XS.ShiftLeft(XSRegisters.EAX, 1);
                        XS.Push(XSRegisters.EAX);
                    }
                    else
                    {
                        throw new NotImplementedException("In NewObj, a string ctor implementation is missing!");
                    }
                }
                #endregion Special string handling

                uint xMemSize   = GetStorageSize(objectType);
                int  xExtraSize = 12; // additional size for set values after alloc
                XS.Push((uint)(xMemSize + xExtraSize));
                if (xHasCalcSize)
                {
                    XS.Pop(XSRegisters.EAX);
                    XS.Add(ESP, EAX, destinationIsIndirect: true);
                }

                // todo: probably we want to check for exceptions after calling Alloc
                XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef));
                XS.Label(".AfterAlloc");
                XS.Push(ESP, isIndirect: true);
                XS.Push(ESP, isIndirect: true);

                // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes

                //? ?? uint xObjSize;// = 0;
                //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values
                //where item.NeedsGC
                //select item ).Count();

                //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values
                //where item.NeedsGC
                //select item ).Count();
                int xGCFieldCount = objectType.GetFields().Count(x => x.FieldType.IsValueType);

                // todo: use a cleaner approach here. this class shouldnt assemble the string
                string strTypeId = GetTypeIDLabel(constructor.DeclaringType);

                XS.Pop(XSRegisters.EAX);
                XS.Set(EAX, EAX, sourceIsIndirect: true);
                XS.Set(EBX, strTypeId, sourceIsIndirect: true);
                XS.Set(EAX, EBX, destinationIsIndirect: true);
                XS.Set(EAX, (uint)InstanceTypeEnum.NormalObject, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Set(EAX, (uint)xGCFieldCount, destinationDisplacement: 8, size: RegisterSize.Int32);
                uint xSize = (uint)(from item in xParams
                                    let xQSize = Align(SizeOfType(item.ParameterType), 4)
                                                 select(int) xQSize).Take(xParams.Length).Sum();

                foreach (var xParam in xParams)
                {
                    uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4);
                    new Comment(aAssembler, String.Format("Arg {0}: {1}", xParam.Name, xParamSize));
                    for (int i = 0; i < xParamSize; i += 4)
                    {
                        new CPUx86.Push {
                            DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4)
                        };
                    }
                }

                XS.Call(LabelName.Get(constructor));
                // should the complete error handling happen by ILOp.EmitExceptionLogic?
                if (aMethod != null)
                {
                    // todo: only happening for real methods now, not for ctor's ?
                    XS.Test(XSRegisters.ECX, 2);
                    string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString();
                    XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel);

                    //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ )
                    //{
                    //    new CPUx86.Add
                    //    {
                    //        DestinationReg = CPUx86.Registers.ESP,
                    //        SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0
                    //             ? aCtorMethodInfo.Arguments[ i ].Size
                    //             : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 )
                    //    };
                    //}
                    PushAlignedParameterSize(constructor);

                    // an exception occurred, we need to cleanup the stack, and jump to the exit
                    XS.Add(XSRegisters.ESP, 4);

                    //new Comment(aAssembler, "[ Newobj.Execute cleanup start count = " + aAssembler.Stack.Count.ToString() + " ]");
                    //foreach( var xStackInt in Assembler.Stack )
                    //{
                    //    new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = ( uint )xStackInt.Size };
                    //}

                    new Comment(aAssembler, "[ Newobj.Execute cleanup end ]");
                    Jump_Exception(aMethod);
                    XS.Label(xNoErrorLabel);
                }
                XS.Pop(XSRegisters.EAX);

                //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ )
                //{
                //    new CPUx86.Add
                //    {
                //        DestinationReg = CPUx86.Registers.ESP,
                //        SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0
                //             ? aCtorMethodInfo.Arguments[ i ].Size
                //             : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 )
                //    };
                //}
                PushAlignedParameterSize(constructor);

                XS.Push(XSRegisters.EAX);
            }
        }
示例#3
0
        public static void Assemble(Assembler aAssembler, _MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor)
        {
            // call cctor:
            if (aMethod != null)
            {
                var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? Array.Empty <ConstructorInfo>()).SingleOrDefault();
                if (xCctor != null)
                {
                    XS.Call(LabelName.Get(xCctor));
                    EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck");
                    XS.Label(".AfterCCTorExceptionCheck");
                }
            }

            if (objectType.IsValueType)
            {
                #region Valuetypes

                XS.Comment("ValueType");
                XS.Comment("Type: " + objectType);

                /*
                 * Current sitation on stack:
                 *   $ESP       Arg
                 *   $ESP+..    other items
                 *
                 * What should happen:
                 *  + The stack should be increased to allow space to contain:
                 *         + .ctor arguments
                 *         + struct _pointer_ (ref to start of emptied space)
                 *         + empty space for struct
                 *  + arguments should be copied to the new place
                 *  + old place where arguments were should be cleared
                 *  + pointer should be set
                 *  + call .ctor
                 */

                // Size of return value - we need to make room for this on the stack.
                uint xStorageSize = Align(SizeOfType(objectType), 4);
                XS.Comment("StorageSize: " + xStorageSize);
                if (xStorageSize == 0)
                {
                    throw new Exception("ValueType storage size cannot be 0.");
                }

                uint xArgSize       = 0;
                var  xParameterList = constructor.GetParameters();
                foreach (var xParam in xParameterList)
                {
                    xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4);
                }
                XS.Comment("ArgSize: " + xArgSize);

                // set source of args copy
                XS.Set(ESI, ESP);

                // allocate space for struct
                XS.Sub(ESP, xStorageSize + 4);

                // set destination and count of args copy
                XS.Set(EDI, ESP);
                XS.Set(ECX, xArgSize / 4);

                // move the args to their new location
                new CPUx86.Movs {
                    Size = 32, Prefixes = CPUx86.InstructionPrefixes.Repeat
                };

                // set struct ptr
                XS.Set(EAX, ESP);
                XS.Add(EAX, xArgSize + 4);
                XS.Set(ESP, EAX, destinationDisplacement: (int)xArgSize);

                XS.Push(EAX);

                var xOpType = new OpType(xMethod.OpCode, xMethod.Position, xMethod.NextPosition, xMethod.Value.DeclaringType, xMethod.CurrentExceptionRegion);
                new Initobj(aAssembler).Execute(aMethod, xOpType);

                new Call(aAssembler).Execute(aMethod, xMethod);

                // Need to put these *after* the call because the Call pops the args from the stack
                // and we have mucked about on the stack, so this makes it right before the next
                // op.

                #endregion Valuetypes
            }
            else
            {
                // If not ValueType, then we need gc

                var xParams = constructor.GetParameters();

                // array length + 8
                bool xHasCalcSize = false;

                #region Special string handling
                // try calculating size:
                if (constructor.DeclaringType == typeof(string))
                {
                    if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[]))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceDisplacement: 4, sourceIsIndirect: true); // address
                        XS.Set(EAX, EAX, sourceDisplacement: 8, sourceIsIndirect: true); // element count
                        XS.Set(EDX, 2);                                                  // element size
                        XS.Multiply(EDX);
                        XS.Push(EAX);
                    }
                    else if (xParams.Length == 3 &&
                             (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) &&
                             xParams[1].ParameterType == typeof(int) &&
                             xParams[2].ParameterType == typeof(int))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceIsIndirect: true);
                        XS.ShiftLeft(EAX, 1);
                        XS.Push(EAX);
                    }
                    else if (xParams.Length == 2 &&
                             xParams[0].ParameterType == typeof(char) &&
                             xParams[1].ParameterType == typeof(int))
                    {
                        xHasCalcSize = true;
                        XS.Set(EAX, ESP, sourceIsIndirect: true);
                        XS.ShiftLeft(EAX, 1);
                        XS.Push(EAX);
                    }

                    /*
                     * TODO see if something is needed in stack / register to make them really work
                     */
                    else if (xParams.Length == 3 &&
                             (xParams[0].ParameterType == typeof(sbyte *) &&
                              xParams[1].ParameterType == typeof(int) &&
                              xParams[2].ParameterType == typeof(int)))
                    {
                        xHasCalcSize = true;
                        XS.Push(ESP, isIndirect: true);
                    }
                    else if (xParams.Length == 1 && xParams[0].ParameterType == typeof(sbyte *))
                    {
                        xHasCalcSize = true;
                        /* xParams[0] contains a C / ASCII Z string the following ASM is de facto the C strlen() function */
                        var xSByteCountLabel = currentLabel + ".SByteCount";

                        XS.Set(EAX, ESP, sourceIsIndirect: true);
                        XS.Or(ECX, 0xFFFFFFFF);

                        XS.Label(xSByteCountLabel);

                        XS.Increment(EAX);
                        XS.Increment(ECX);

                        XS.Compare(EAX, 0, destinationIsIndirect: true);
                        XS.Jump(CPUx86.ConditionalTestEnum.NotEqual, xSByteCountLabel);

                        XS.Push(ECX);
                    }
                    else
                    {
                        throw new NotImplementedException("In NewObj, a string ctor implementation is missing!");
                    }
                }
                #endregion Special string handling

                uint xMemSize   = GetStorageSize(objectType);
                int  xExtraSize = 12; // additional size for set values after alloc
                XS.Push((uint)(xMemSize + xExtraSize));
                if (xHasCalcSize)
                {
                    XS.Pop(EAX);
                    XS.Add(ESP, EAX, destinationIsIndirect: true);
                }

                // todo: probably we want to check for exceptions after calling Alloc
                XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef));
                XS.Label(".AfterAlloc");
                XS.Push(ESP, isIndirect: true);
                XS.Push(ESP, isIndirect: true);
                // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes

                // todo: use a cleaner approach here. this class shouldnt assemble the string
                string strTypeId = GetTypeIDLabel(constructor.DeclaringType);

                XS.Pop(EAX);
                XS.Set(EBX, strTypeId, sourceIsIndirect: true);
                XS.Set(EAX, EBX, destinationIsIndirect: true);
                XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.NormalObject, destinationDisplacement: 4, destinationIsIndirect: true, size: RegisterSize.Int32);
                XS.Set(EAX, xMemSize, destinationDisplacement: 8, destinationIsIndirect: true, size: RegisterSize.Int32);
                uint xSize = (uint)(from item in xParams
                                    let xQSize = Align(SizeOfType(item.ParameterType), 4)
                                                 select(int) xQSize).Take(xParams.Length).Sum();
                XS.Push(0);

                foreach (var xParam in xParams)
                {
                    uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4);
                    XS.Comment($"Arg {xParam.Name}: {xParamSize}");
                    for (int i = 0; i < xParamSize; i += 4)
                    {
                        XS.Push(ESP, isIndirect: true, displacement: (int)(xSize + 8));
                    }
                }


                XS.Call(LabelName.Get(constructor));
                // should the complete error handling happen by ILOp.EmitExceptionLogic?
                if (aMethod != null)
                {
                    // todo: only happening for real methods now, not for ctor's ?
                    XS.Test(ECX, 2);
                    string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString();
                    XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel);

                    PushAlignedParameterSize(constructor);

                    // an exception occurred, we need to cleanup the stack, and jump to the exit
                    XS.Add(ESP, 4);

                    new Comment(aAssembler, "[ Newobj.Execute cleanup end ]");
                    Jump_Exception(aMethod);
                    XS.Label(xNoErrorLabel);
                }
                XS.Pop(EAX);

                PushAlignedParameterSize(constructor);

                XS.Push(EAX);
                XS.Push(0);
            }
        }