示例#1
0
        public void Emit(ILOpcode opcode, ILCodeLabel label)
        {
            Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse ||
                opcode == ILOpcode.brtrue || opcode == ILOpcode.beq ||
                opcode == ILOpcode.bge || opcode == ILOpcode.bgt ||
                opcode == ILOpcode.ble || opcode == ILOpcode.blt ||
                opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un ||
                opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un ||
                opcode == ILOpcode.blt_un || opcode == ILOpcode.leave);

            Emit(opcode);
            _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length));
            EmitUInt32(4);
        }
示例#2
0
 public LabelAndOffset(ILCodeLabel label, int offset)
 {
     Label  = label;
     Offset = offset;
 }
示例#3
0
        public override MethodIL EmitIL()
        {
            const DelegateThunkKind maxThunkKind = DelegateThunkKind.ObjectArrayThunk;

            ILEmitter emitter = new ILEmitter();

            var codeStream = emitter.NewCodeStream();

            ILCodeLabel returnNullLabel = emitter.NewCodeLabel();

            ILCodeLabel[] labels = new ILCodeLabel[(int)maxThunkKind];
            for (DelegateThunkKind i = 0; i < maxThunkKind; i++)
            {
                MethodDesc thunk = _delegateInfo.Thunks[i];
                if (thunk != null)
                    labels[(int)i] = emitter.NewCodeLabel();
                else
                    labels[(int)i] = returnNullLabel;
            }

            codeStream.EmitLdArg(1);
            codeStream.EmitSwitch(labels);

            codeStream.Emit(ILOpcode.br, returnNullLabel);

            for (DelegateThunkKind i = 0; i < maxThunkKind; i++)
            {
                MethodDesc thunk = _delegateInfo.Thunks[i];
                if (thunk != null)
                {
                    codeStream.EmitLabel(labels[(int)i]);

                    codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(thunk.InstantiateAsOpen()));
                    codeStream.Emit(ILOpcode.ret);
                }
            }

            codeStream.EmitLabel(returnNullLabel);
            codeStream.EmitLdc(0);
            codeStream.Emit(ILOpcode.conv_i);
            codeStream.Emit(ILOpcode.ret);

            return emitter.Link(this);
        }
示例#4
0
 public void EmitLabel(ILCodeLabel label)
 {
     label.Place(this, _length);
 }
示例#5
0
        public ILCodeLabel NewCodeLabel()
        {
            var newLabel = new ILCodeLabel();

            return(newLabel);
        }
示例#6
0
 public LabelAndOffset(ILCodeLabel label, int offset)
 {
     Label = label;
     Offset = offset;
 }
        public override MethodIL EmitIL()
        {
            ILEmitter    emitter                   = new ILEmitter();
            ILCodeStream argSetupStream            = emitter.NewCodeStream();
            ILCodeStream thisCallSiteSetupStream   = emitter.NewCodeStream();
            ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream();

            // This function will look like
            //
            // !For each parameter to the method
            //    !if (parameter is In Parameter)
            //       localX is TypeOfParameterX&
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperIn(RuntimeTypeHandle)
            //       stloc localX
            //    !else
            //       localX is TypeOfParameter
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperRef(RuntimeTypeHandle)
            //       stloc localX

            // ldarg.2
            // call DynamicInvokeArgSetupComplete(ref ArgSetupState)

            // *** Thiscall instruction stream starts here ***

            // ldarg.3 // Load targetIsThisCall
            // brfalse Not_this_call

            // ldarg.0 // Load this pointer
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType thiscall(TypeOfParameter1, ...)
            // !if ((ReturnType == void)
            //    ldnull
            // !else
            //    box ReturnType
            // ret

            // *** Static call instruction stream starts here ***

            // Not_this_call:
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType (TypeOfParameter1, ...)
            // !if ((ReturnType == void)
            //    ldnull
            // !else
            //    box ReturnType
            // ret

            ILCodeLabel lStaticCall = emitter.NewCodeLabel();

            thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall
            thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall);
            staticCallSiteSetupStream.EmitLabel(lStaticCall);

            thisCallSiteSetupStream.EmitLdArg(0); // thisPtr

            ILToken tokDynamicInvokeParamHelperRef =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null));
            ILToken tokDynamicInvokeParamHelperIn =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null));

            TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length];

            for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++)
            {
                TypeDesc        paramType    = Context.GetSignatureVariable(paramIndex, true);
                ILToken         tokParamType = emitter.NewToken(paramType);
                ILLocalVariable local        = emitter.NewLocal(paramType.MakeByRefType());

                thisCallSiteSetupStream.EmitLdLoc(local);
                staticCallSiteSetupStream.EmitLdLoc(local);

                argSetupStream.Emit(ILOpcode.ldtoken, tokParamType);

                if (_targetSignature[paramIndex] == DynamicInvokeMethodParameterKind.Reference)
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef);

                    targetMethodSignature[paramIndex] = paramType.MakeByRefType();
                }
                else
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn);

                    thisCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType);
                    staticCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType);

                    targetMethodSignature[paramIndex] = paramType;
                }
                argSetupStream.EmitStLoc(local);
            }

            argSetupStream.EmitLdArg(2); // argSetupState
            argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null)));

            thisCallSiteSetupStream.EmitLdArg(1);   // methodToCall
            staticCallSiteSetupStream.EmitLdArg(1); // methodToCall

            TypeDesc returnType = _targetSignature.HasReturnValue ?
                                  Context.GetSignatureVariable(_targetSignature.Length, true) :
                                  Context.GetWellKnownType(WellKnownType.Void);

            MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature);

            CalliIntrinsic.EmitTransformedCalli(emitter, thisCallSiteSetupStream, thisCallMethodSig);
            //thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig));

            MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature);

            CalliIntrinsic.EmitTransformedCalli(emitter, staticCallSiteSetupStream, staticCallMethodSig);
            //staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig));

            if (_targetSignature.HasReturnValue)
            {
                ILToken tokReturnType = emitter.NewToken(returnType);
                thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
                staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
            }
            else
            {
                thisCallSiteSetupStream.Emit(ILOpcode.ldnull);
                staticCallSiteSetupStream.Emit(ILOpcode.ldnull);
            }

            thisCallSiteSetupStream.Emit(ILOpcode.ret);
            staticCallSiteSetupStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
示例#8
0
        public override MethodIL EmitIL()
        {
            ILEmitter emitter = new ILEmitter();

            var codeStream = emitter.NewCodeStream();

            ILCodeLabel returnNullLabel = emitter.NewCodeLabel();

            bool hasDynamicInvokeThunk = (_delegateInfo.SupportedFeatures & DelegateFeature.DynamicInvoke) != 0 &&
                                         DynamicInvokeMethodThunk.SupportsSignature(_delegateInfo.Signature);

            ILCodeLabel[] labels = new ILCodeLabel[(int)DelegateThunkCollection.MaxThunkKind];
            for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++)
            {
                MethodDesc thunk = _delegateInfo.Thunks[i];
                if (thunk != null ||
                    (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk))
                {
                    labels[(int)i] = emitter.NewCodeLabel();
                }
                else
                {
                    labels[(int)i] = returnNullLabel;
                }
            }

            codeStream.EmitLdArg(1);
            codeStream.EmitSwitch(labels);

            codeStream.Emit(ILOpcode.br, returnNullLabel);

            for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++)
            {
                MethodDesc targetMethod = null;

                // Dynamic invoke thunk is special since we're calling into a shared helper
                if (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk)
                {
                    Debug.Assert(_delegateInfo.Thunks[i] == null);

                    var        sig   = new DynamicInvokeMethodSignature(_delegateInfo.Signature);
                    MethodDesc thunk = Context.GetDynamicInvokeThunk(sig);

                    if (thunk.HasInstantiation)
                    {
                        TypeDesc[] inst = DynamicInvokeMethodThunk.GetThunkInstantiationForMethod(_delegateInfo.Type.InstantiateAsOpen().GetMethod("Invoke", null));
                        targetMethod = Context.GetInstantiatedMethod(thunk, new Instantiation(inst));
                    }
                    else
                    {
                        targetMethod = thunk;
                    }
                }
                else
                {
                    MethodDesc thunk = _delegateInfo.Thunks[i];

                    if (thunk != null)
                    {
                        targetMethod = thunk.InstantiateAsOpen();
                    }
                }

                if (targetMethod != null)
                {
                    codeStream.EmitLabel(labels[(int)i]);
                    codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(targetMethod));
                    codeStream.Emit(ILOpcode.ret);
                }
            }

            codeStream.EmitLabel(returnNullLabel);
            codeStream.EmitLdc(0);
            codeStream.Emit(ILOpcode.conv_i);
            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
        /// <summary>
        /// Marshals a string. Expects the string reference on the stack. Pushes a pointer
        /// to the stack that is safe to pass out to native code.
        /// </summary>
        /// <returns>The type the string was marshalled into.</returns>
        private TypeDesc EmitStringMarshalling()
        {
            PInvokeAttributes charset = _importMetadata.Attributes & PInvokeAttributes.CharSetMask;

            TypeSystemContext context = _targetMethod.Context;

            if (charset == 0)
            {
                // ECMA-335 II.10.1.5 - Default value is Ansi.
                charset = PInvokeAttributes.CharSetAnsi;
            }

            if (charset == PInvokeAttributes.CharSetAuto)
            {
                charset = PInvokeAttributes.CharSetUnicode;
            }

            TypeDesc stringType = context.GetWellKnownType(WellKnownType.String);

            if (charset == PInvokeAttributes.CharSetUnicode)
            {
                //
                // Unicode marshalling. Pin the string and push a pointer to the first character on the stack.
                //

                ILLocalVariable vPinnedString = _emitter.NewLocal(stringType, true);
                ILCodeLabel     lNullString   = _emitter.NewCodeLabel();

                _marshallingCodeStream.EmitStLoc(vPinnedString);
                _marshallingCodeStream.EmitLdLoc(vPinnedString);

                _marshallingCodeStream.Emit(ILOpcode.conv_i);
                _marshallingCodeStream.Emit(ILOpcode.dup);

                // Marshalling a null string?
                _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString);

                // TODO: find a safe, non-awkward way to get to OffsetToStringData
                _marshallingCodeStream.EmitLdc(context.Target.PointerSize + 4);
                _marshallingCodeStream.Emit(ILOpcode.add);

                _marshallingCodeStream.EmitLabel(lNullString);
            }
            else
            {
                //
                // ANSI marshalling. Allocate a byte array, copy characters, pin first element.
                //

                TypeDesc byteType      = context.GetWellKnownType(WellKnownType.Byte);
                TypeDesc byteArrayType = byteType.MakeArrayType();

                MethodDesc getLengthMethod = stringType.GetMethod("get_Length", null);
                MethodDesc getCharsMethod  = stringType.GetMethod("get_Chars", null);

                ILCodeLabel lStart      = _emitter.NewCodeLabel();
                ILCodeLabel lNext       = _emitter.NewCodeLabel();
                ILCodeLabel lNullString = _emitter.NewCodeLabel();
                ILCodeLabel lDone       = _emitter.NewCodeLabel();

                // Check for the simple case: string is null
                ILLocalVariable vStringToMarshal = _emitter.NewLocal(stringType);
                _marshallingCodeStream.EmitStLoc(vStringToMarshal);
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString);

                // TODO: figure out how to reference a helper from here and call the helper instead...

                // byte[] byteArray = new byte[stringToMarshal.Length + 1];
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getLengthMethod));
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.add);
                _marshallingCodeStream.Emit(ILOpcode.newarr, _emitter.NewToken(byteType));
                ILLocalVariable vByteArray = _emitter.NewLocal(byteArrayType);
                _marshallingCodeStream.EmitStLoc(vByteArray);

                // for (int i = 0; i < byteArray.Length - 1; i++)
                //     byteArray[i] = (byte)stringToMarshal[i];
                ILLocalVariable vIterator = _emitter.NewLocal(context.GetWellKnownType(WellKnownType.Int32));
                _marshallingCodeStream.Emit(ILOpcode.ldc_i4_0);
                _marshallingCodeStream.EmitStLoc(vIterator);
                _marshallingCodeStream.Emit(ILOpcode.br, lStart);
                _marshallingCodeStream.EmitLabel(lNext);
                _marshallingCodeStream.EmitLdLoc(vByteArray);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdLoc(vStringToMarshal);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getCharsMethod));
                _marshallingCodeStream.Emit(ILOpcode.conv_u1);
                _marshallingCodeStream.Emit(ILOpcode.stelem_i1);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.add);
                _marshallingCodeStream.EmitStLoc(vIterator);
                _marshallingCodeStream.EmitLabel(lStart);
                _marshallingCodeStream.EmitLdLoc(vIterator);
                _marshallingCodeStream.EmitLdLoc(vByteArray);
                _marshallingCodeStream.Emit(ILOpcode.ldlen);
                _marshallingCodeStream.Emit(ILOpcode.conv_i4);
                _marshallingCodeStream.EmitLdc(1);
                _marshallingCodeStream.Emit(ILOpcode.sub);
                _marshallingCodeStream.Emit(ILOpcode.blt, lNext);
                _marshallingCodeStream.EmitLdLoc(vByteArray);

                // Pin first element and load the byref on the stack.
                _marshallingCodeStream.EmitLdc(0);
                _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(byteType));
                ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(byteArrayType.MakeByRefType(), true);
                _marshallingCodeStream.EmitStLoc(vPinnedFirstElement);
                _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement);
                _marshallingCodeStream.Emit(ILOpcode.conv_i);
                _marshallingCodeStream.Emit(ILOpcode.br, lDone);

                _marshallingCodeStream.EmitLabel(lNullString);
                _marshallingCodeStream.Emit(ILOpcode.ldnull);
                _marshallingCodeStream.Emit(ILOpcode.conv_i);

                _marshallingCodeStream.EmitLabel(lDone);
            }

            return(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
        }
示例#10
0
        private MethodIL EmitIL()
        {
            if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute"))
            {
                throw new NotSupportedException();
            }

            PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
            ILEmitter            emitter = pInvokeILCodeStreams.Emitter;
            ILCodeStream         marshallingCodestream   = pInvokeILCodeStreams.MarshallingCodeStream;
            ILCodeStream         unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream;
            ILCodeStream         cleanupCodestream       = pInvokeILCodeStreams.CleanupCodeStream;

            // Marshalling is wrapped in a finally block to guarantee cleanup
            ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion();

            marshallingCodestream.BeginTry(tryFinally);
            cleanupCodestream.BeginHandler(tryFinally);

            // Marshal the arguments
            bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid;

            for (int i = isHRSwappedRetVal ? 1 : 0; i < _marshallers.Length; i++)
            {
                _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams);
            }

            if (isHRSwappedRetVal)
            {
                _marshallers[0].EmitMarshallingIL(pInvokeILCodeStreams);
            }

            // make the call
            switch (_targetMethod)
            {
            case DelegateMarshallingMethodThunk delegateMethod:
                EmitDelegateCall(delegateMethod, pInvokeILCodeStreams);
                break;

            case CalliMarshallingMethodThunk calliMethod:
                EmitCalli(pInvokeILCodeStreams, calliMethod);
                break;

            default:
                EmitPInvokeCall(pInvokeILCodeStreams);
                break;
            }

            ILCodeLabel lReturn = emitter.NewCodeLabel();

            unmarshallingCodestream.Emit(ILOpcode.leave, lReturn);
            unmarshallingCodestream.EndTry(tryFinally);

            cleanupCodestream.Emit(ILOpcode.endfinally);
            cleanupCodestream.EndHandler(tryFinally);

            cleanupCodestream.EmitLabel(lReturn);

            _marshallers[0].LoadReturnValue(cleanupCodestream);
            cleanupCodestream.Emit(ILOpcode.ret);

            return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired()));
        }
示例#11
0
        public override MethodIL EmitIL()
        {
            // We will generate the following code:
            //
            // object ret;
            // object[] args = new object[parameterCount];
            // args[0] = param0;
            // args[1] = param1;
            //  ...
            // try {
            //      ret = ((Func<object[], object>)dlg.m_helperObject)(args);
            // } finally {
            //      param0 = (T0)args[0];   // only generated for each byref argument
            // }
            // return (TRet)ret;

            ILEmitter    emitter    = new ILEmitter();
            ILCodeStream codeStream = emitter.NewCodeStream();

            TypeDesc objectType      = Context.GetWellKnownType(WellKnownType.Object);
            TypeDesc objectArrayType = objectType.MakeArrayType();

            ILLocalVariable argsLocal = emitter.NewLocal(objectArrayType);

            bool hasReturnValue = !Signature.ReturnType.IsVoid;

            bool hasRefArgs = false;

            if (Signature.Length > 0)
            {
                codeStream.EmitLdc(Signature.Length);
                codeStream.Emit(ILOpcode.newarr, emitter.NewToken(objectType));
                codeStream.EmitStLoc(argsLocal);

                for (int i = 0; i < Signature.Length; i++)
                {
                    TypeDesc paramType    = Signature[i];
                    bool     paramIsByRef = false;

                    if (paramType.IsByRef)
                    {
                        hasRefArgs  |= paramType.IsByRef;
                        paramIsByRef = true;
                        paramType    = ((ByRefType)paramType).ParameterType;
                    }

                    hasRefArgs |= paramType.IsByRef;

                    codeStream.EmitLdLoc(argsLocal);
                    codeStream.EmitLdc(i);
                    codeStream.EmitLdArg(i + 1);

                    ILToken paramToken = emitter.NewToken(paramType);

                    if (paramIsByRef)
                    {
                        codeStream.Emit(ILOpcode.ldobj, paramToken);
                    }
                    codeStream.Emit(ILOpcode.box, paramToken);
                    codeStream.Emit(ILOpcode.stelem_ref);
                }
            }
            else
            {
                MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray");
                codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod));
                codeStream.EmitStLoc(argsLocal);
            }

            ILExceptionRegionBuilder tryFinallyRegion = null;

            if (hasRefArgs)
            {
                // we emit a try/finally to update the args array even if an exception is thrown
                tryFinallyRegion = emitter.NewFinallyRegion();
                codeStream.BeginTry(tryFinallyRegion);
            }

            codeStream.EmitLdArg(0);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField));

            MetadataType funcType         = Context.SystemModule.GetKnownType("System", "Func`2");
            TypeDesc     instantiatedFunc = funcType.MakeInstantiatedType(objectArrayType, objectType);

            codeStream.Emit(ILOpcode.castclass, emitter.NewToken(instantiatedFunc));

            codeStream.EmitLdLoc(argsLocal);

            MethodDesc invokeMethod = instantiatedFunc.GetKnownMethod("Invoke", null);

            codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod));

            ILLocalVariable retLocal = (ILLocalVariable)(-1);

            if (hasReturnValue)
            {
                retLocal = emitter.NewLocal(objectType);
                codeStream.EmitStLoc(retLocal);
            }
            else
            {
                codeStream.Emit(ILOpcode.pop);
            }

            if (hasRefArgs)
            {
                ILCodeLabel returnLabel = emitter.NewCodeLabel();
                codeStream.Emit(ILOpcode.leave, returnLabel);
                codeStream.EndTry(tryFinallyRegion);

                // copy back ref/out args
                codeStream.BeginHandler(tryFinallyRegion);
                for (int i = 0; i < Signature.Length; i++)
                {
                    TypeDesc paramType = Signature[i];
                    if (paramType.IsByRef)
                    {
                        paramType = ((ByRefType)paramType).ParameterType;
                        ILToken paramToken = emitter.NewToken(paramType);

                        // Update parameter
                        codeStream.EmitLdArg(i + 1);
                        codeStream.EmitLdLoc(argsLocal);
                        codeStream.EmitLdc(i);
                        codeStream.Emit(ILOpcode.ldelem_ref);
                        codeStream.Emit(ILOpcode.unbox_any, paramToken);
                        codeStream.Emit(ILOpcode.stobj, paramToken);
                    }
                }
                codeStream.Emit(ILOpcode.endfinally);
                codeStream.EndHandler(tryFinallyRegion);
                codeStream.EmitLabel(returnLabel);
            }

            if (hasReturnValue)
            {
                codeStream.EmitLdLoc(retLocal);
                codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(Signature.ReturnType));
            }

            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
示例#12
0
        public override MethodIL EmitIL()
        {
            TypeDesc owningType = _owningType.InstantiateAsOpen();

            ILEmitter emitter = new ILEmitter();

            TypeDesc   eeTypePtrType     = Context.SystemModule.GetKnownType("System", "EETypePtr");
            MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null);
            ILToken    eeTypePtrToken    = emitter.NewToken(eeTypePtrType);

            var switchStream   = emitter.NewCodeStream();
            var getFieldStream = emitter.NewCodeStream();

            ArrayBuilder <ILCodeLabel> fieldGetters = new ArrayBuilder <ILCodeLabel>();

            foreach (FieldDesc field in owningType.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

                ILCodeLabel label = emitter.NewCodeLabel();
                fieldGetters.Add(label);

                getFieldStream.EmitLabel(label);
                getFieldStream.EmitLdArg(2);

                // We need something we can instantiate EETypePtrOf over. Also, the classlib
                // code doesn't handle pointers.
                TypeDesc boxableFieldType = field.FieldType;
                if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer)
                {
                    boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr);
                }

                MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType);
                getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField));

                getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken);

                getFieldStream.EmitLdArg(0);
                getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field));

                getFieldStream.EmitLdArg(0);

                getFieldStream.Emit(ILOpcode.sub);

                getFieldStream.Emit(ILOpcode.ret);
            }

            if (fieldGetters.Count > 0)
            {
                switchStream.EmitLdArg(1);
                switchStream.EmitSwitch(fieldGetters.ToArray());
            }

            switchStream.EmitLdc(fieldGetters.Count);

            switchStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
示例#13
0
        private void EmitILForAccessor()
        {
            Debug.Assert(_method.OwningType.IsMdArray);

            var codeStream = _emitter.NewCodeStream();
            var context    = _method.Context;

            var int32Type = context.GetWellKnownType(WellKnownType.Int32);

            var totalLocalNum  = _emitter.NewLocal(int32Type);
            var lengthLocalNum = _emitter.NewLocal(int32Type);

            int pointerSize = context.Target.PointerSize;

            int argStartOffset = _method.Kind == ArrayMethodKind.AddressWithHiddenArg ? 2 : 1;

            var         rangeExceptionLabel        = _emitter.NewCodeLabel();
            ILCodeLabel typeMismatchExceptionLabel = null;

            if (_elementType.IsGCPointer)
            {
                // Type check
                if (_method.Kind == ArrayMethodKind.Set)
                {
                    MethodDesc checkArrayStore =
                        context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null);

                    codeStream.EmitLdArg(0);
                    codeStream.EmitLdArg(_rank + argStartOffset);

                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore));
                }
                else if (_method.Kind == ArrayMethodKind.AddressWithHiddenArg)
                {
                    TypeDesc objectType    = context.GetWellKnownType(WellKnownType.Object);
                    TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr");

                    typeMismatchExceptionLabel = _emitter.NewCodeLabel();

                    ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType);

                    ILCodeLabel typeCheckPassedLabel = _emitter.NewCodeLabel();

                    // Codegen will pass a null hidden argument if this is a `constrained.` call to the Address method.
                    // As per ECMA-335 III.2.3, the prefix suppresses the type check.
                    // if (hiddenArg.IsNull)
                    //     goto TypeCheckPassed;
                    codeStream.EmitLdArga(1);
                    codeStream.Emit(ILOpcode.call,
                                    _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsNull", null)));
                    codeStream.Emit(ILOpcode.brtrue, typeCheckPassedLabel);

                    // EETypePtr actualElementType = this.EETypePtr.ArrayElementType;
                    codeStream.EmitLdArg(0);
                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null)));
                    codeStream.EmitStLoc(thisEEType);
                    codeStream.EmitLdLoca(thisEEType);
                    codeStream.Emit(ILOpcode.call,
                                    _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null)));

                    // EETypePtr expectedElementType = hiddenArg.ArrayElementType;
                    codeStream.EmitLdArga(1);
                    codeStream.Emit(ILOpcode.call,
                                    _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null)));

                    // if (expectedElementType != actualElementType)
                    //     ThrowHelpers.ThrowArrayTypeMismatchException();
                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("op_Equality", null)));
                    codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel);

                    codeStream.EmitLabel(typeCheckPassedLabel);
                }
            }

            // Methods on Rank 1 MdArray need to be able to handle `this` that is an SzArray
            // because SzArray is castable to Rank 1 MdArray (but not the other way around).

            ILCodeLabel rangeCheckDoneLabel = null;

            if (_rank == 1)
            {
                TypeDesc        objectType    = context.GetWellKnownType(WellKnownType.Object);
                TypeDesc        eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr");
                ILLocalVariable thisEEType    = _emitter.NewLocal(eetypePtrType);

                codeStream.EmitLdArg(0);
                codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null)));
                codeStream.EmitStLoc(thisEEType);
                codeStream.EmitLdLoca(thisEEType);
                codeStream.Emit(ILOpcode.call,
                                _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsSzArray", null)));

                ILCodeLabel notSzArrayLabel = _emitter.NewCodeLabel();
                codeStream.Emit(ILOpcode.brfalse, notSzArrayLabel);

                // We have an SzArray - do the bounds check differently
                EmitLoadInteriorAddress(codeStream, pointerSize);
                codeStream.Emit(ILOpcode.dup);
                codeStream.Emit(ILOpcode.ldind_i4);
                codeStream.EmitLdArg(argStartOffset);
                codeStream.EmitStLoc(totalLocalNum);
                codeStream.EmitLdLoc(totalLocalNum);
                codeStream.Emit(ILOpcode.ble_un, rangeExceptionLabel);

                codeStream.EmitLdc(pointerSize);
                codeStream.Emit(ILOpcode.add);

                rangeCheckDoneLabel = _emitter.NewCodeLabel();
                codeStream.Emit(ILOpcode.br, rangeCheckDoneLabel);

                codeStream.EmitLabel(notSzArrayLabel);
            }

            for (int i = 0; i < _rank; i++)
            {
                // The first two fields are EEType pointer and total length. Lengths for each dimension follows.
                int lengthOffset = (2 * pointerSize + i * sizeof(int));

                EmitLoadInteriorAddress(codeStream, lengthOffset);
                codeStream.Emit(ILOpcode.ldind_i4);
                codeStream.EmitStLoc(lengthLocalNum);

                codeStream.EmitLdArg(i + argStartOffset);

                // Compare with length
                codeStream.Emit(ILOpcode.dup);
                codeStream.EmitLdLoc(lengthLocalNum);
                codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel);

                // Add to the running total if we have one already
                if (i > 0)
                {
                    codeStream.EmitLdLoc(totalLocalNum);
                    codeStream.EmitLdLoc(lengthLocalNum);
                    codeStream.Emit(ILOpcode.mul);
                    codeStream.Emit(ILOpcode.add);
                }
                codeStream.EmitStLoc(totalLocalNum);
            }

            // Compute element offset
            // TODO: This leaves unused space for lower bounds to match CoreCLR...
            int firstElementOffset = (2 * pointerSize + 2 * _rank * sizeof(int));

            EmitLoadInteriorAddress(codeStream, firstElementOffset);

            if (rangeCheckDoneLabel != null)
            {
                codeStream.EmitLabel(rangeCheckDoneLabel);
            }

            codeStream.EmitLdLoc(totalLocalNum);
            codeStream.Emit(ILOpcode.conv_u);

            int elementSize = _elementType.GetElementSize().AsInt;

            if (elementSize != 1)
            {
                codeStream.EmitLdc(elementSize);
                codeStream.Emit(ILOpcode.mul);
            }
            codeStream.Emit(ILOpcode.add);

            switch (_method.Kind)
            {
            case ArrayMethodKind.Get:
                codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType));
                break;

            case ArrayMethodKind.Set:
                codeStream.EmitLdArg(_rank + argStartOffset);
                codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType));
                break;

            case ArrayMethodKind.AddressWithHiddenArg:
                break;
            }

            codeStream.Emit(ILOpcode.ret);

            codeStream.EmitLdc(0);
            codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack
            codeStream.Emit(ILOpcode.pop);

            MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException");

            codeStream.EmitCallThrowHelper(_emitter, throwHelper);

            if (typeMismatchExceptionLabel != null)
            {
                codeStream.EmitLabel(typeMismatchExceptionLabel);
                codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException"));
            }
        }
示例#14
0
        public override MethodIL EmitIL()
        {
            ILEmitter    emitter                   = new ILEmitter();
            ILCodeStream argSetupStream            = emitter.NewCodeStream();
            ILCodeStream thisCallSiteSetupStream   = emitter.NewCodeStream();
            ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream();
            ILCodeStream returnCodeStream          = emitter.NewCodeStream();

            // This function will look like
            //
            // !For each parameter to the method
            //    !if (parameter is In Parameter)
            //       localX is TypeOfParameterX&
            //       ldarg.2
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperIn(ref ArgSetupState, RuntimeTypeHandle)
            //       stloc localX
            //    !else
            //       localX is TypeOfParameter
            //       ldarg.2
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperRef(ref ArgSetupState, RuntimeTypeHandle)
            //       stloc localX

            // ldarg.2
            // call DynamicInvokeArgSetupComplete(ref ArgSetupState)

            // *** Thiscall instruction stream starts here ***

            // ldarg.3 // Load targetIsThisCall
            // brfalse Not_this_call

            // ldarg.0 // Load this pointer
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType thiscall(TypeOfParameter1, ...)
            // br Process_return

            // *** Static call instruction stream starts here ***

            // Not_this_call:
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType (TypeOfParameter1, ...)

            // *** Return code stream starts here ***

            // Process_return:
            // !if (ReturnType is Byref)
            //    dup
            //    brfalse ByRefNull
            //    ldobj ReturnType
            // !if ((ReturnType == void)
            //    ldnull
            // !elif (ReturnType is pointer)
            //    System.Reflection.Pointer.Box(ReturnType)
            // !else
            //    box ReturnType
            // ret
            //
            // !if (ReturnType is ByRef)
            //   ByRefNull:
            //   pop
            //   call InvokeUtils.get_NullByRefValueSentinel
            //   ret

            ILCodeLabel lStaticCall    = emitter.NewCodeLabel();
            ILCodeLabel lProcessReturn = emitter.NewCodeLabel();

            thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall
            thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall);
            staticCallSiteSetupStream.EmitLabel(lStaticCall);

            thisCallSiteSetupStream.EmitLdArg(0); // thisPtr

            ILToken tokDynamicInvokeParamHelperRef =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null));
            ILToken tokDynamicInvokeParamHelperIn =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null));

            TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length];

            for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++)
            {
                TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true);
                DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex];

                for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++)
                {
                    paramType = paramType.MakePointerType();
                }

                ILToken         tokParamType = emitter.NewToken(paramType);
                ILLocalVariable local        = emitter.NewLocal(paramType.MakeByRefType());

                thisCallSiteSetupStream.EmitLdLoc(local);
                staticCallSiteSetupStream.EmitLdLoc(local);

                argSetupStream.EmitLdArg(2); // argSetupState
                argSetupStream.Emit(ILOpcode.ldtoken, tokParamType);

                if (paramKind == DynamicInvokeMethodParameterKind.Reference)
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef);

                    targetMethodSignature[paramIndex] = paramType.MakeByRefType();
                }
                else
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn);

                    thisCallSiteSetupStream.EmitLdInd(paramType);
                    staticCallSiteSetupStream.EmitLdInd(paramType);

                    targetMethodSignature[paramIndex] = paramType;
                }
                argSetupStream.EmitStLoc(local);
            }

            argSetupStream.EmitLdArg(2); // argSetupState
            argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null)));

            thisCallSiteSetupStream.EmitLdArg(1);   // methodToCall
            staticCallSiteSetupStream.EmitLdArg(1); // methodToCall

            DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType;
            TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ?
                                  Context.GetSignatureVariable(_targetSignature.Length, true) :
                                  Context.GetWellKnownType(WellKnownType.Void);

            for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++)
            {
                returnType = returnType.MakePointerType();
            }

            if (returnKind == DynamicInvokeMethodParameterKind.Reference)
            {
                returnType = returnType.MakeByRefType();
            }

            MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature);

            thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig));
            thisCallSiteSetupStream.Emit(ILOpcode.br, lProcessReturn);

            MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature);

            staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig));

            returnCodeStream.EmitLabel(lProcessReturn);

            ILCodeLabel lByRefReturnNull = null;

            if (returnKind == DynamicInvokeMethodParameterKind.None)
            {
                returnCodeStream.Emit(ILOpcode.ldnull);
            }
            else
            {
                TypeDesc returnTypeForBoxing = returnType;

                if (returnType.IsByRef)
                {
                    // If this is a byref return, we need to dereference first
                    returnTypeForBoxing = ((ByRefType)returnType).ParameterType;
                    lByRefReturnNull    = emitter.NewCodeLabel();
                    returnCodeStream.Emit(ILOpcode.dup);
                    returnCodeStream.Emit(ILOpcode.brfalse, lByRefReturnNull);
                    returnCodeStream.EmitLdInd(returnTypeForBoxing);
                }

                if (returnTypeForBoxing.IsPointer)
                {
                    // Pointers box differently
                    returnCodeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnTypeForBoxing));
                    MethodDesc getTypeFromHandleMethod =
                        Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null);
                    returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod));

                    MethodDesc pointerBoxMethod =
                        Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null);
                    returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod));
                }
                else
                {
                    ILToken tokReturnType = emitter.NewToken(returnTypeForBoxing);
                    returnCodeStream.Emit(ILOpcode.box, tokReturnType);
                }
            }

            returnCodeStream.Emit(ILOpcode.ret);

            if (lByRefReturnNull != null)
            {
                returnCodeStream.EmitLabel(lByRefReturnNull);
                returnCodeStream.Emit(ILOpcode.pop);
                returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("get_NullByRefValueSentinel", null)));
                returnCodeStream.Emit(ILOpcode.ret);
            }

            return(emitter.Link(this));
        }
示例#15
0
        public void EmitSwitch(ILCodeLabel[] labels)
        {
            Emit(ILOpcode.switch_);
            EmitUInt32(labels.Length);

            int remainingBytes = labels.Length * 4;
            foreach (var label in labels)
            {
                _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length));
                EmitUInt32(remainingBytes);
                remainingBytes -= 4;
            }
        }
示例#16
0
        public override MethodIL EmitIL()
        {
            ILEmitter    emitter    = new ILEmitter();
            ILCodeStream codeStream = emitter.NewCodeStream();

            ArrayType invocationListArrayType = SystemDelegateType.MakeArrayType();

            ILLocalVariable delegateArrayLocal   = emitter.NewLocal(invocationListArrayType);
            ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
            ILLocalVariable iteratorLocal        = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
            ILLocalVariable delegateToCallLocal  = emitter.NewLocal(SystemDelegateType);

            ILLocalVariable returnValueLocal = 0;

            if (Signature.ReturnType.IsSignatureVariable || !Signature.ReturnType.IsVoid)
            {
                returnValueLocal = emitter.NewLocal(Signature.ReturnType);
            }

            // Fill in delegateArrayLocal
            // Delegate[] delegateArrayLocal = (Delegate[])this.m_helperObject

            // ldarg.0 (this pointer)
            // ldfld Delegate.HelperObjectField
            // castclass Delegate[]
            // stloc delegateArrayLocal
            codeStream.EmitLdArg(0);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField));
            codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType));
            codeStream.EmitStLoc(delegateArrayLocal);

            // Fill in invocationCountLocal
            // int invocationCountLocal = this.m_extraFunctionPointerOrData
            // ldarg.0 (this pointer)
            // ldfld Delegate.m_extraFunctionPointerOrData
            // stloc invocationCountLocal
            codeStream.EmitLdArg(0);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField));
            codeStream.EmitStLoc(invocationCountLocal);

            // Fill in iteratorLocal
            // int iteratorLocal = 0;

            // ldc.0
            // stloc iteratorLocal
            codeStream.EmitLdc(0);
            codeStream.EmitStLoc(iteratorLocal);

            // Loop across every element of the array.
            ILCodeLabel startOfLoopLabel = emitter.NewCodeLabel();

            codeStream.EmitLabel(startOfLoopLabel);

            // Implement as do/while loop. We only have this stub in play if we're in the multicast situation
            // Find the delegate to call
            // Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal];

            // ldloc delegateArrayLocal
            // ldloc iteratorLocal
            // ldelem System.Delegate
            // stloc delegateToCallLocal
            codeStream.EmitLdLoc(delegateArrayLocal);
            codeStream.EmitLdLoc(iteratorLocal);
            codeStream.Emit(ILOpcode.ldelem, emitter.NewToken(SystemDelegateType));
            codeStream.EmitStLoc(delegateToCallLocal);

            // Call the delegate
            // returnValueLocal = delegateToCallLocal(...);

            // ldloc delegateToCallLocal
            // ldfld System.Delegate.m_firstParameter
            // ldarg 1, n
            // ldloc delegateToCallLocal
            // ldfld System.Delegate.m_functionPointer
            // calli returnValueType thiscall (all the params)
            // IF there is a return value
            // stloc returnValueLocal

            codeStream.EmitLdLoc(delegateToCallLocal);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField));

            for (int i = 0; i < Signature.Length; i++)
            {
                codeStream.EmitLdArg(i + 1);
            }

            codeStream.EmitLdLoc(delegateToCallLocal);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField));

            codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature));

            if (returnValueLocal != 0)
            {
                codeStream.EmitStLoc(returnValueLocal);
            }

            // Increment iteratorLocal
            // ++iteratorLocal;

            // ldloc iteratorLocal
            // ldc.i4.1
            // add
            // stloc iteratorLocal
            codeStream.EmitLdLoc(iteratorLocal);
            codeStream.EmitLdc(1);
            codeStream.Emit(ILOpcode.add);
            codeStream.EmitStLoc(iteratorLocal);

            // Check to see if the loop is done
            codeStream.EmitLdLoc(invocationCountLocal);
            codeStream.EmitLdLoc(iteratorLocal);
            codeStream.Emit(ILOpcode.bne_un, startOfLoopLabel);

            // Return to caller. If the delegate has a return value, be certain to return that.
            // return returnValueLocal;

            // ldloc returnValueLocal
            // ret
            if (returnValueLocal != 0)
            {
                codeStream.EmitLdLoc(returnValueLocal);
            }

            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
示例#17
0
 public void EmitLabel(ILCodeLabel label)
 {
     label.Place(this, _length);
 }
示例#18
0
        private void EmitILForAccessor()
        {
            Debug.Assert(!_method.OwningType.IsSzArray);

            var codeStream = _emitter.NewCodeStream();
            var context    = _method.Context;

            var int32Type = context.GetWellKnownType(WellKnownType.Int32);

            var totalLocalNum  = _emitter.NewLocal(int32Type);
            var lengthLocalNum = _emitter.NewLocal(int32Type);

            int pointerSize = context.Target.PointerSize;

            var         rangeExceptionLabel        = _emitter.NewCodeLabel();
            ILCodeLabel typeMismatchExceptionLabel = null;

            if (!_elementType.IsValueType)
            {
                // Type check
                if (_method.Kind == ArrayMethodKind.Set)
                {
                    MethodDesc checkArrayStore =
                        context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null);

                    codeStream.EmitLdArg(0);
                    codeStream.EmitLdArg(_rank + 1);

                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore));
                }
                else if (_method.Kind == ArrayMethodKind.Address)
                {
                    TypeDesc objectType    = context.GetWellKnownType(WellKnownType.Object);
                    TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr");

                    MethodDesc eetypePtrOfMethod = eetypePtrType.GetKnownMethod("EETypePtrOf", null)
                                                   .MakeInstantiatedMethod(new Instantiation(new[] { _elementType }));

                    typeMismatchExceptionLabel = _emitter.NewCodeLabel();

                    ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType);

                    // EETypePtr actualElementType = this.EETypePtr.ArrayElementType;
                    codeStream.EmitLdArg(0);
                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null)));
                    codeStream.EmitStLoc(thisEEType);
                    codeStream.EmitLdLoca(thisEEType);
                    codeStream.Emit(ILOpcode.call,
                                    _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null)));

                    // EETypePtr expectedElementType = EETypePtr.EETypePtrOf<_elementType>();
                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrOfMethod));

                    // if (expectedElementType != actualElementType)
                    //     ThrowHelpers.ThrowArrayTypeMismatchException();
                    codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("op_Equality", null)));
                    codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel);
                }
            }

            for (int i = 0; i < _rank; i++)
            {
                // The first two fields are EEType pointer and total length. Lengths for each dimension follows.
                int lengthOffset = (2 * pointerSize + i * int32Type.GetElementSize());

                EmitLoadInteriorAddress(codeStream, lengthOffset);
                codeStream.Emit(ILOpcode.ldind_i4);
                codeStream.EmitStLoc(lengthLocalNum);

                codeStream.EmitLdArg(i + 1);

                // Compare with length
                codeStream.Emit(ILOpcode.dup);
                codeStream.EmitLdLoc(lengthLocalNum);
                codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel);

                // Add to the running total if we have one already
                if (i > 0)
                {
                    codeStream.EmitLdLoc(totalLocalNum);
                    codeStream.EmitLdLoc(lengthLocalNum);
                    codeStream.Emit(ILOpcode.mul);
                    codeStream.Emit(ILOpcode.add);
                }
                codeStream.EmitStLoc(totalLocalNum);
            }

            // Compute element offset
            // TODO: This leaves unused space for lower bounds to match CoreCLR...
            int firstElementOffset = (2 * pointerSize + 2 * _rank * int32Type.GetElementSize());

            EmitLoadInteriorAddress(codeStream, firstElementOffset);

            codeStream.EmitLdLoc(totalLocalNum);

            int elementSize = _elementType.GetElementSize();

            if (elementSize != 1)
            {
                codeStream.EmitLdc(elementSize);
                codeStream.Emit(ILOpcode.mul);
            }
            codeStream.Emit(ILOpcode.add);

            switch (_method.Kind)
            {
            case ArrayMethodKind.Get:
                codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType));
                break;

            case ArrayMethodKind.Set:
                codeStream.EmitLdArg(_rank + 1);
                codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType));
                break;

            case ArrayMethodKind.Address:
                break;
            }

            codeStream.Emit(ILOpcode.ret);

            codeStream.EmitLdc(0);
            codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack
            codeStream.Emit(ILOpcode.pop);

            MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException");

            codeStream.EmitCallThrowHelper(_emitter, throwHelper);

            if (typeMismatchExceptionLabel != null)
            {
                codeStream.EmitLabel(typeMismatchExceptionLabel);
                codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException"));
            }
        }
示例#19
0
 public ILCodeLabel NewCodeLabel()
 {
     var newLabel = new ILCodeLabel();
     return newLabel;
 }
        public override MethodIL EmitIL()
        {
            TypeDesc owningType = _owningType.InstantiateAsOpen();

            ILEmitter emitter = new ILEmitter();

            TypeDesc   eeTypePtrType     = Context.SystemModule.GetKnownType("System", "EETypePtr");
            MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null);
            ILToken    eeTypePtrToken    = emitter.NewToken(eeTypePtrType);

            var switchStream   = emitter.NewCodeStream();
            var getFieldStream = emitter.NewCodeStream();

            ArrayBuilder <ILCodeLabel> fieldGetters = new ArrayBuilder <ILCodeLabel>();

            foreach (FieldDesc field in owningType.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

                ILCodeLabel label = emitter.NewCodeLabel();
                fieldGetters.Add(label);

                getFieldStream.EmitLabel(label);
                getFieldStream.EmitLdArg(2);

                // We need something we can instantiate EETypePtrOf over. Also, the classlib
                // code doesn't handle pointers.
                TypeDesc boxableFieldType = field.FieldType;
                if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer)
                {
                    boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr);
                }

                // The fact that the type is a reference type is sufficient for the callers.
                // Don't unnecessarily create an MethodTable for the field type.
                if (!boxableFieldType.IsSignatureVariable && !boxableFieldType.IsValueType)
                {
                    boxableFieldType = Context.GetWellKnownType(WellKnownType.Object);
                }

                // If this is an enum, it's okay to Equals/GetHashCode the underlying type.
                // Don't unnecessarily create an MethodTable for the enum.
                boxableFieldType = boxableFieldType.UnderlyingType;

                MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType);
                getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField));

                getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken);

                getFieldStream.EmitLdArg(0);
                getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field));

                getFieldStream.EmitLdArg(0);

                getFieldStream.Emit(ILOpcode.sub);

                getFieldStream.Emit(ILOpcode.ret);
            }

            if (fieldGetters.Count > 0)
            {
                switchStream.EmitLdArg(1);
                switchStream.EmitSwitch(fieldGetters.ToArray());
            }

            switchStream.EmitLdc(fieldGetters.Count);

            switchStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }