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)); }
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; } }
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(); }