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(); }
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(); }
internal CallConversionParameters(CallConversionInfo conversionInfo, IntPtr callerTransitionBlockParam) { // Make sure the thred static variable has been initialized for this thread s_pinnedGCHandles = s_pinnedGCHandles ?? new GCHandleContainer(); _conversionInfo = conversionInfo; _callerTransitionBlock = (byte *)callerTransitionBlockParam.ToPointer(); _functionPointerToCall = conversionInfo.TargetFunctionPointer; _instantiatingStubArgument = conversionInfo.InstantiatingStubArgument; _delegateData = default(DelegateData); _calleeArgs = default(ArgIterator); _invokeReturnValue = IntPtr.Zero; _copyReturnValue = true; _dynamicInvokeParams = null; _dynamicInvokeByRefObjectArgs = null; // // Setup input argument iterator for the caller // ArgIteratorData callerIteratorData; if (conversionInfo.IsDelegateDynamicInvokeThunk) { callerIteratorData = s_delegateDynamicInvokeImplArgIteratorData; } else if (conversionInfo.IsReflectionDynamicInvokerThunk) { callerIteratorData = s_reflectionDynamicInvokeImplArgIteratorData; } else { callerIteratorData = conversionInfo.ArgIteratorData; } _callerArgs = new ArgIterator(callerIteratorData, callerIteratorData.HasThis() ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, conversionInfo.CallerHasParamType, conversionInfo.CallerHasExtraParameterWhichIsFunctionTarget, conversionInfo.CallerForcedByRefData, false, false); // Setup input bool forceCalleeHasParamType = false; // If the callee MAY have a param type, we need to know before we create the callee arg iterator // To do this we need to actually load the target address and see if it has the generic method pointer // bit set. if (conversionInfo.CalleeMayHaveParamType) { ArgIterator callerArgsLookupTargetFunctionPointer = new ArgIterator(conversionInfo.ArgIteratorData, conversionInfo.ArgIteratorData.HasThis() ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, conversionInfo.CallerHasParamType, conversionInfo.CallerHasExtraParameterWhichIsFunctionTarget, conversionInfo.CallerForcedByRefData, false, false); // Find the last valid caller offset. That's the offset of the target function pointer. int ofsCallerValid = TransitionBlock.InvalidOffset; while (true) { // Setup argument offsets. int ofsCallerTemp = callerArgsLookupTargetFunctionPointer.GetNextOffset(); // Check to see if we've handled all the arguments that we are to pass to the callee. if (TransitionBlock.InvalidOffset == ofsCallerTemp) { break; } ofsCallerValid = ofsCallerTemp; } if (ofsCallerValid == TransitionBlock.InvalidOffset) { throw new InvalidProgramException(); } int stackSizeCaller = callerArgsLookupTargetFunctionPointer.GetArgSize(); Debug.Assert(stackSizeCaller == IntPtr.Size); void * pSrc = _callerTransitionBlock + ofsCallerValid; IntPtr tempFunctionPointer = *((IntPtr *)pSrc); forceCalleeHasParamType = UpdateCalleeFunctionPointer(tempFunctionPointer); } // Retrieve target function pointer and instantiation argument for delegate thunks if (conversionInfo.IsDelegateThunk) { Debug.Assert(_callerArgs.HasThis() && !_conversionInfo.IsUnboxingThunk); IntPtr locationOfThisPointer = (IntPtr)(_callerTransitionBlock + ArgIterator.GetThisOffset()); _delegateData._delegateObject = (Delegate)Unsafe.As <IntPtr, Object>(ref *(IntPtr *)locationOfThisPointer); Debug.Assert(_delegateData._delegateObject != null); RuntimeAugments.GetDelegateData( _delegateData._delegateObject, out _delegateData._firstParameter, out _delegateData._helperObject, out _delegateData._extraFunctionPointerOrData, out _delegateData._functionPointer); if (conversionInfo.TargetDelegateFunctionIsExtraFunctionPointerOrDataField) { if (conversionInfo.IsOpenInstanceDelegateThunk) { _delegateData._boxedFirstParameter = BoxedCallerFirstArgument; Debug.Assert(_delegateData._boxedFirstParameter != null); _callerArgs.Reset(); IntPtr resolvedTargetFunctionPointer = OpenMethodResolver.ResolveMethod(_delegateData._extraFunctionPointerOrData, _delegateData._boxedFirstParameter); forceCalleeHasParamType = UpdateCalleeFunctionPointer(resolvedTargetFunctionPointer); } else { forceCalleeHasParamType = UpdateCalleeFunctionPointer(_delegateData._extraFunctionPointerOrData); } } else if (conversionInfo.IsMulticastDelegate) { _delegateData._multicastTargetCount = (int)_delegateData._extraFunctionPointerOrData; } } // // Setup output argument iterator for the callee // _calleeArgs = new ArgIterator(conversionInfo.ArgIteratorData, (conversionInfo.ArgIteratorData.HasThis() && !conversionInfo.IsStaticDelegateThunk) ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, forceCalleeHasParamType || conversionInfo.CalleeHasParamType, false, conversionInfo.CalleeForcedByRefData, conversionInfo.IsOpenInstanceDelegateThunk, conversionInfo.IsClosedStaticDelegate); // The function pointer, 'hasParamType', and 'hasThis' flags for the callee arg iterator need to be computed/read from the caller's // input arguments in the case of a reflection invoker thunk (the target method pointer and 'hasThis' flags are // passed in as parameters from the caller, not loaded from a static method signature in native layout) if (conversionInfo.IsReflectionDynamicInvokerThunk) { ComputeCalleeFlagsAndFunctionPointerForReflectionInvokeThunk(); } #if CALLINGCONVENTION_CALLEE_POPS // Ensure that the count of bytes in the stack is available _callerArgs.CbStackPop(); #endif }