public static int RegisterCallConversionInfo(ThunkKind thunkKind,
                                                     IntPtr targetPointer,
                                                     IntPtr instantiatingArg,
                                                     ArgIteratorData argIteratorData,
                                                     bool[] paramsByRefForced)
        {
            Debug.Assert(argIteratorData != null);

            CallConversionInfo newConversionInfo = new CallConversionInfo();

            newConversionInfo._registrationKind      = CallConversionInfoRegistrationKind.UsesArgIteratorData;
            newConversionInfo._thunkKind             = thunkKind;
            newConversionInfo._targetFunctionPointer = targetPointer;
            newConversionInfo._instantiatingArg      = instantiatingArg;
            newConversionInfo._argIteratorData       = argIteratorData;
            newConversionInfo._paramsByRefForced     = paramsByRefForced;
            newConversionInfo._signatureParsed       = true;

            return(AddConverter(newConversionInfo));
        }
Ejemplo n.º 2
0
        public void GetCallRefMap(MethodDesc method, bool isUnboxingStub)
        {
            TransitionBlock transitionBlock = TransitionBlock.FromTarget(method.Context.Target);

            MethodSignature signature = method.Signature;

            bool hasThis = (signature.Flags & MethodSignatureFlags.Static) == 0;

            // This pointer is omitted for string constructors
            bool fCtorOfVariableSizedObject = hasThis && method.OwningType.IsString && method.IsConstructor;

            if (fCtorOfVariableSizedObject)
            {
                hasThis = false;
            }

            bool       isVarArg   = false;
            TypeHandle returnType = new TypeHandle(signature.ReturnType);

            TypeHandle[] parameterTypes = new TypeHandle[signature.Length];
            for (int parameterIndex = 0; parameterIndex < parameterTypes.Length; parameterIndex++)
            {
                parameterTypes[parameterIndex] = new TypeHandle(signature[parameterIndex]);
            }
            CallingConventions callingConventions = (hasThis ? CallingConventions.ManagedInstance : CallingConventions.ManagedStatic);
            bool hasParamType = method.RequiresInstArg() && !isUnboxingStub;

            // On X86 the Array address method doesn't use IL stubs, and instead has a custom calling convention
            if ((method.Context.Target.Architecture == TargetArchitecture.X86) &&
                method.IsArrayAddressMethod())
            {
                hasParamType = true;
            }

            bool extraFunctionPointerArg = false;

            bool[]          forcedByRefParams   = new bool[parameterTypes.Length];
            bool            skipFirstArg        = false;
            bool            extraObjectFirstArg = false;
            ArgIteratorData argIteratorData     = new ArgIteratorData(hasThis, isVarArg, parameterTypes, returnType);

            ArgIterator argit = new ArgIterator(
                method.Context,
                argIteratorData,
                callingConventions,
                hasParamType,
                extraFunctionPointerArg,
                forcedByRefParams,
                skipFirstArg,
                extraObjectFirstArg);

            int nStackBytes = argit.SizeOfFrameArgumentArray();

            // Allocate a fake stack
            CORCOMPILE_GCREFMAP_TOKENS[] fakeStack = new CORCOMPILE_GCREFMAP_TOKENS[transitionBlock.SizeOfTransitionBlock + nStackBytes];

            // Fill it in
            FakeGcScanRoots(method, argit, fakeStack, isUnboxingStub);

            // Encode the ref map
            uint nStackSlots;

            if (_target.Architecture == TargetArchitecture.X86)
            {
                uint cbStackPop = argit.CbStackPop();
                WriteStackPop(cbStackPop / (uint)_target.PointerSize);

                nStackSlots = (uint)(nStackBytes / _target.PointerSize + _transitionBlock.NumArgumentRegisters);
            }
            else
            {
                nStackSlots = (uint)((transitionBlock.SizeOfTransitionBlock + nStackBytes - _transitionBlock.OffsetOfFirstGCRefMapSlot) / _target.PointerSize);
            }

            for (uint pos = 0; pos < nStackSlots; pos++)
            {
                int offset = _transitionBlock.OffsetFromGCRefMapPos(checked ((int)pos));
                CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[offset];

                if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP)
                {
                    WriteToken(pos, (byte)token);
                }
            }

            Flush();
        }
        //
        // Lazily parse the method signature, and construct the call converter data
        //
        private void EnsureCallConversionInfoLoaded()
        {
            if (_signatureParsed)
            {
                return;
            }

            lock (this)
            {
                // Check if race was won by another thread and the signature got parsed
                if (_signatureParsed)
                {
                    return;
                }

                TypeSystemContext context = TypeSystemContextFactory.Create();
                {
                    Instantiation typeInstantiation   = Instantiation.Empty;
                    Instantiation methodInstantiation = Instantiation.Empty;

                    if (_typeArgs != null && _typeArgs.Length > 0)
                    {
                        typeInstantiation = context.ResolveRuntimeTypeHandles(_typeArgs);
                    }
                    if (_methodArgs != null && _methodArgs.Length > 0)
                    {
                        methodInstantiation = context.ResolveRuntimeTypeHandles(_methodArgs);
                    }

                    bool       hasThis;
                    TypeDesc[] parameters;
                    bool[]     paramsByRefForced;
                    if (!TypeLoaderEnvironment.Instance.GetCallingConverterDataFromMethodSignature(context, _methodSignature, typeInstantiation, methodInstantiation, out hasThis, out parameters, out paramsByRefForced))
                    {
                        Debug.Assert(false);
                        Environment.FailFast("Failed to get type handles for parameters in method signature");
                    }
                    Debug.Assert(parameters != null && parameters.Length >= 1);

                    bool[] byRefParameters = new bool[parameters.Length];
                    RuntimeTypeHandle[] parameterHandles = new RuntimeTypeHandle[parameters.Length];

                    for (int j = 0; j < parameters.Length; j++)
                    {
                        ByRefType parameterAsByRefType = parameters[j] as ByRefType;
                        if (parameterAsByRefType != null)
                        {
                            parameterAsByRefType.ParameterType.RetrieveRuntimeTypeHandleIfPossible();
                            parameterHandles[j] = parameterAsByRefType.ParameterType.RuntimeTypeHandle;
                            byRefParameters[j]  = true;
                        }
                        else
                        {
                            parameters[j].RetrieveRuntimeTypeHandleIfPossible();
                            parameterHandles[j] = parameters[j].RuntimeTypeHandle;
                            byRefParameters[j]  = false;
                        }

                        Debug.Assert(!parameterHandles[j].IsNull());
                    }

                    // Build thunk data
                    TypeHandle   thReturnType = new TypeHandle(CallConverterThunk.GetByRefIndicatorAtIndex(0, byRefParameters), parameterHandles[0]);
                    TypeHandle[] thParameters = null;
                    if (parameters.Length > 1)
                    {
                        thParameters = new TypeHandle[parameters.Length - 1];
                        for (int i = 1; i < parameters.Length; i++)
                        {
                            thParameters[i - 1] = new TypeHandle(CallConverterThunk.GetByRefIndicatorAtIndex(i, byRefParameters), parameterHandles[i]);
                        }
                    }

                    _argIteratorData = new ArgIteratorData(hasThis, false, thParameters, thReturnType);

                    // StandardToStandard thunks don't actually need any parameters to change their ABI
                    // so don't force any params to be adjusted
                    if (!StandardToStandardThunk)
                    {
                        _paramsByRefForced = paramsByRefForced;
                    }
                }
                TypeSystemContextFactory.Recycle(context);

                _signatureParsed = true;
            }
        }
Ejemplo n.º 4
0
        public void GetCallRefMap(MethodDesc method)
        {
            TransitionBlock transitionBlock = TransitionBlock.FromTarget(method.Context.Target);

            bool       hasThis    = (method.Signature.Flags & MethodSignatureFlags.Static) == 0;
            bool       isVarArg   = false;
            TypeHandle returnType = new TypeHandle(method.Signature.ReturnType);

            TypeHandle[] parameterTypes = new TypeHandle[method.Signature.Length];
            for (int parameterIndex = 0; parameterIndex < parameterTypes.Length; parameterIndex++)
            {
                parameterTypes[parameterIndex] = new TypeHandle(method.Signature[parameterIndex]);
            }
            CallingConventions callingConventions = (hasThis ? CallingConventions.ManagedInstance : CallingConventions.ManagedStatic);
            bool hasParamType            = method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg();
            bool extraFunctionPointerArg = false;

            bool[]          forcedByRefParams   = new bool[parameterTypes.Length];
            bool            skipFirstArg        = false;
            bool            extraObjectFirstArg = false;
            ArgIteratorData argIteratorData     = new ArgIteratorData(hasThis, isVarArg, parameterTypes, returnType);

            ArgIterator argit = new ArgIterator(
                method.Context,
                argIteratorData,
                callingConventions,
                hasParamType,
                extraFunctionPointerArg,
                forcedByRefParams,
                skipFirstArg,
                extraObjectFirstArg);

            int nStackBytes = argit.SizeOfFrameArgumentArray();

            // Allocate a fake stack
            CORCOMPILE_GCREFMAP_TOKENS[] fakeStack = new CORCOMPILE_GCREFMAP_TOKENS[transitionBlock.SizeOfTransitionBlock + nStackBytes];

            // Fill it in
            FakeGcScanRoots(method, argit, fakeStack);

            // Encode the ref map
            uint nStackSlots;

            if (_target.Architecture == TargetArchitecture.X86)
            {
                uint cbStackPop = argit.CbStackPop();
                WriteStackPop(cbStackPop / (uint)_target.PointerSize);

                nStackSlots = (uint)(nStackBytes / _target.PointerSize + _transitionBlock.NumArgumentRegisters);
            }
            else
            {
                nStackSlots = (uint)((transitionBlock.SizeOfTransitionBlock + nStackBytes - _transitionBlock.OffsetOfFirstGCRefMapSlot) / _target.PointerSize);
            }

            for (uint pos = 0; pos < nStackSlots; pos++)
            {
                int ofs;

                if (_target.Architecture == TargetArchitecture.X86)
                {
                    ofs = (int)(pos < _transitionBlock.NumArgumentRegisters ?
                                _transitionBlock.OffsetOfArgumentRegisters + _transitionBlock.SizeOfArgumentRegisters - (pos + 1) * _target.PointerSize :
                                _transitionBlock.OffsetOfArgs + (pos - _transitionBlock.NumArgumentRegisters) * _target.PointerSize);
                }
                else
                {
                    ofs = (int)(_transitionBlock.OffsetOfFirstGCRefMapSlot + pos * _target.PointerSize);
                }

                CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[ofs];

                if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP)
                {
                    WriteToken(pos, (byte)token);
                }
            }

            Flush();
        }