static public void Recycle(TypeSystemContext context) { // Only cache a reasonably small context that is still in Gen0 if (context.LoadFactor > 200 || GC.GetGeneration(context) > 0) { return; } // Flush the type system context from all types being recycled context.FlushTypeBuilderStates(); // No lock needed here - the reference assignment is atomic s_cachedContext.Target = context; }
private unsafe static void RegularFuncEval(byte *parameterBuffer, uint parameterBufferSize) { TypesAndValues typesAndValues = new TypesAndValues(); uint trash; uint parameterCount; uint parameterValueSize; uint eeTypeCount; ulong eeType; uint offset = 0; NativeReader reader = new NativeReader(parameterBuffer, parameterBufferSize); offset = reader.DecodeUnsigned(offset, out trash); // The VertexSequence always generate a length, I don't really need it. offset = reader.DecodeUnsigned(offset, out parameterCount); typesAndValues.parameterValues = new byte[parameterCount][]; for (int i = 0; i < parameterCount; i++) { offset = reader.DecodeUnsigned(offset, out parameterValueSize); byte[] parameterValue = new byte[parameterValueSize]; for (int j = 0; j < parameterValueSize; j++) { uint parameterByte; offset = reader.DecodeUnsigned(offset, out parameterByte); parameterValue[j] = (byte)parameterByte; } typesAndValues.parameterValues[i] = parameterValue; } offset = reader.DecodeUnsigned(offset, out eeTypeCount); ulong[] debuggerPreparedExternalReferences = new ulong[eeTypeCount]; for (int i = 0; i < eeTypeCount; i++) { offset = reader.DecodeUnsignedLong(offset, out eeType); debuggerPreparedExternalReferences[i] = eeType; } TypeSystemContext typeSystemContext = TypeSystemContextFactory.Create(); bool hasThis; TypeDesc[] parameters; bool[] parametersWithGenericDependentLayout; bool result = TypeLoaderEnvironment.Instance.GetCallingConverterDataFromMethodSignature_NativeLayout_Debugger(typeSystemContext, RuntimeSignature.CreateFromNativeLayoutSignatureForDebugger(offset), Instantiation.Empty, Instantiation.Empty, out hasThis, out parameters, out parametersWithGenericDependentLayout, reader, debuggerPreparedExternalReferences); typesAndValues.types = new RuntimeTypeHandle[parameters.Length]; bool needToDynamicallyLoadTypes = false; for (int i = 0; i < typesAndValues.types.Length; i++) { if (!parameters[i].RetrieveRuntimeTypeHandleIfPossible()) { needToDynamicallyLoadTypes = true; break; } typesAndValues.types[i] = parameters[i].GetRuntimeTypeHandle(); } if (needToDynamicallyLoadTypes) { TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock(() => { typeSystemContext.FlushTypeBuilderStates(); GenericDictionaryCell[] cells = new GenericDictionaryCell[parameters.Length]; for (int i = 0; i < cells.Length; i++) { cells[i] = GenericDictionaryCell.CreateTypeHandleCell(parameters[i]); } IntPtr[] eetypePointers; TypeBuilder.ResolveMultipleCells(cells, out eetypePointers); for (int i = 0; i < parameters.Length; i++) { typesAndValues.types[i] = ((EEType *)eetypePointers[i])->ToRuntimeTypeHandle(); } }); } TypeSystemContextFactory.Recycle(typeSystemContext); LocalVariableType[] argumentTypes = new LocalVariableType[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { // TODO, FuncEval, what these false really means? Need to make sure our format contains those information argumentTypes[i] = new LocalVariableType(typesAndValues.types[i], false, false); } LocalVariableSet.SetupArbitraryLocalVariableSet <TypesAndValues>(HighLevelDebugFuncEvalHelperWithVariables, ref typesAndValues, argumentTypes); }
private bool ResolveGenericVirtualMethodTarget(RuntimeTypeHandle targetTypeHandle, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle[] genericArguments, MethodNameAndSignature callingMethodNameAndSignature, out IntPtr methodPointer, out IntPtr dictionaryPointer) { if (IsPregeneratedOrTemplateRuntimeTypeHandle(targetTypeHandle)) { // If the target type isn't dynamic, or at least is template type generated, the static lookup logic is what we want. return(ResolveGenericVirtualMethodTarget_Static(targetTypeHandle, declaringTypeHandle, genericArguments, callingMethodNameAndSignature, out methodPointer, out dictionaryPointer)); } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING methodPointer = IntPtr.Zero; dictionaryPointer = IntPtr.Zero; TypeSystemContext context = TypeSystemContextFactory.Create(); DefType targetType = (DefType)context.ResolveRuntimeTypeHandle(targetTypeHandle); // Method being called... MethodDesc targetVirtualMethod = ResolveTypeHandleAndMethodNameAndSigToVirtualMethodDesc(context, declaringTypeHandle, callingMethodNameAndSignature); if (targetVirtualMethod == null) { // If we can't find the method in the type system, it must only be present in the static environment. Search there instead. TypeSystemContextFactory.Recycle(context); return(ResolveGenericVirtualMethodTarget_Static(targetTypeHandle, declaringTypeHandle, genericArguments, callingMethodNameAndSignature, out methodPointer, out dictionaryPointer)); } MethodDesc dispatchMethod = targetType.FindVirtualFunctionTargetMethodOnObjectType(targetVirtualMethod); if (dispatchMethod == null) { return(false); } Instantiation targetMethodInstantiation = context.ResolveRuntimeTypeHandles(genericArguments); MethodDesc instantiatedDispatchMethod = dispatchMethod.Context.ResolveGenericMethodInstantiation(dispatchMethod.OwningType.IsValueType /* get the unboxing stub */, dispatchMethod.OwningType.GetClosestDefType(), dispatchMethod.NameAndSignature, targetMethodInstantiation, IntPtr.Zero, false); GenericDictionaryCell cell = GenericDictionaryCell.CreateMethodCell(instantiatedDispatchMethod, false); using (LockHolder.Hold(_typeLoaderLock)) { // Now that we hold the lock, we may find that existing types can now find // their associated RuntimeTypeHandle. Flush the type builder states as a way // to force the reresolution of RuntimeTypeHandles which couldn't be found before. context.FlushTypeBuilderStates(); TypeBuilder.ResolveSingleCell(cell, out methodPointer); } TypeSystemContextFactory.Recycle(context); return(true); #else methodPointer = IntPtr.Zero; dictionaryPointer = IntPtr.Zero; Environment.FailFast("GVM Resolution for non template or pregenerated type"); return(false); #endif } }
// This method computes the method pointer and dictionary pointer for a GVM. // Inputs: // - targetTypeHanlde: target type on which the GVM is implemented // - nameAndSignature: name and signature of the GVM method // - genericMethodArgumentHandles: GVM instantiation arguments // Outputs: // - methodPointer: pointer to the GVM's implementation // - dictionaryPointer: (if applicable) pointer to the dictionary to be used with the GVM call public bool TryGetGenericVirtualMethodPointer(RuntimeTypeHandle targetTypeHandle, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles, out IntPtr methodPointer, out IntPtr dictionaryPointer) { methodPointer = dictionaryPointer = IntPtr.Zero; TypeSystemContext context = TypeSystemContextFactory.Create(); DefType targetType = (DefType)context.ResolveRuntimeTypeHandle(targetTypeHandle); Instantiation methodInstantiation = context.ResolveRuntimeTypeHandles(genericMethodArgumentHandles); InstantiatedMethod method = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, nameAndSignature, methodInstantiation, IntPtr.Zero, false); if (!method.CanShareNormalGenericCode()) { // First see if we can find an exact method implementation for the GVM (avoid using USG implementations if we can, // because USG code is much slower). if (TryLookupExactMethodPointerForComponents(targetTypeHandle, nameAndSignature, genericMethodArgumentHandles, out methodPointer)) { Debug.Assert(methodPointer != IntPtr.Zero); TypeSystemContextFactory.Recycle(context); return(true); } } // If we cannot find an exact method entry point, look for an equivalent template and compute the generic dictinoary TemplateLocator templateLocator = new TemplateLocator(); NativeLayoutInfo nativeLayoutInfo = new NativeLayoutInfo(); InstantiatedMethod templateMethod = templateLocator.TryGetGenericMethodTemplate(method, out nativeLayoutInfo.Module, out nativeLayoutInfo.Token); if (templateMethod == null) { return(false); } methodPointer = templateMethod.IsCanonicalMethod(CanonicalFormKind.Universal) ? templateMethod.UsgFunctionPointer : templateMethod.FunctionPointer; if (!TryLookupGenericMethodDictionaryForComponents(targetTypeHandle, nameAndSignature, genericMethodArgumentHandles, out dictionaryPointer)) { using (LockHolder.Hold(_typeLoaderLock)) { // Now that we hold the lock, we may find that existing types can now find // their associated RuntimeTypeHandle. Flush the type builder states as a way // to force the reresolution of RuntimeTypeHandles which couldn't be found before. context.FlushTypeBuilderStates(); if (!TypeBuilder.TryBuildGenericMethod(method, out dictionaryPointer)) { return(false); } } } Debug.Assert(methodPointer != IntPtr.Zero && dictionaryPointer != IntPtr.Zero); if (templateMethod.IsCanonicalMethod(CanonicalFormKind.Universal)) { // Check if we need to wrap the method pointer into a calling convention converter thunk if (!TypeLoaderEnvironment.Instance.MethodSignatureHasVarsNeedingCallingConventionConverter(context, nameAndSignature.Signature)) { TypeSystemContextFactory.Recycle(context); return(true); } RuntimeTypeHandle[] typeArgs = Array.Empty <RuntimeTypeHandle>(); if (RuntimeAugments.IsGenericType(targetTypeHandle)) { RuntimeAugments.GetGenericInstantiation(targetTypeHandle, out typeArgs); } // Create a CallingConventionConverter to call the method correctly IntPtr thunkPtr = CallConverterThunk.MakeThunk( CallConverterThunk.ThunkKind.StandardToGenericInstantiating, methodPointer, nameAndSignature.Signature, dictionaryPointer, typeArgs, genericMethodArgumentHandles); Debug.Assert(thunkPtr != IntPtr.Zero); methodPointer = thunkPtr; // Set dictionaryPointer to null so we don't make a fat function pointer around the whole thing. dictionaryPointer = IntPtr.Zero; // TODO! add a new call converter thunk that will pass the instantiating arg through and use a fat function pointer. // should allow us to make fewer thunks. } TypeSystemContextFactory.Recycle(context); return(true); }
private static void HighLevelDebugFuncEvalHelper() { uint parameterBufferSize = RuntimeAugments.RhpGetFuncEvalParameterBufferSize(); IntPtr writeParameterCommandPointer; IntPtr debuggerBufferPointer; unsafe { byte *debuggerBufferRawPointer = stackalloc byte[(int)parameterBufferSize]; debuggerBufferPointer = new IntPtr(debuggerBufferRawPointer); WriteParameterCommand writeParameterCommand = new WriteParameterCommand { commandCode = 1, bufferAddress = debuggerBufferPointer.ToInt64() }; writeParameterCommandPointer = new IntPtr(&writeParameterCommand); RuntimeAugments.RhpSendCustomEventToDebugger(writeParameterCommandPointer, Unsafe.SizeOf <WriteParameterCommand>()); // .. debugger magic ... the debuggerBuffer will be filled with parameter data TypesAndValues typesAndValues = new TypesAndValues(); uint trash; uint parameterCount; uint parameterValue; uint eeTypeCount; ulong eeType; uint offset = 0; NativeReader reader = new NativeReader(debuggerBufferRawPointer, parameterBufferSize); offset = reader.DecodeUnsigned(offset, out trash); // The VertexSequence always generate a length, I don't really need it. offset = reader.DecodeUnsigned(offset, out parameterCount); typesAndValues.parameterValues = new int[parameterCount]; for (int i = 0; i < parameterCount; i++) { offset = reader.DecodeUnsigned(offset, out parameterValue); typesAndValues.parameterValues[i] = (int)parameterValue; } offset = reader.DecodeUnsigned(offset, out eeTypeCount); for (int i = 0; i < eeTypeCount; i++) { // TODO: Stuff these eeType values into the external reference table offset = reader.DecodeUnsignedLong(offset, out eeType); } TypeSystemContext typeSystemContext = TypeSystemContextFactory.Create(); bool hasThis; TypeDesc[] parameters; bool[] parametersWithGenericDependentLayout; bool result = TypeLoaderEnvironment.Instance.GetCallingConverterDataFromMethodSignature_NativeLayout_Debugger(typeSystemContext, RuntimeSignature.CreateFromNativeLayoutSignatureForDebugger(offset), Instantiation.Empty, Instantiation.Empty, out hasThis, out parameters, out parametersWithGenericDependentLayout, reader); typesAndValues.types = new RuntimeTypeHandle[parameters.Length]; bool needToDynamicallyLoadTypes = false; for (int i = 0; i < typesAndValues.types.Length; i++) { if (!parameters[i].RetrieveRuntimeTypeHandleIfPossible()) { needToDynamicallyLoadTypes = true; break; } typesAndValues.types[i] = parameters[i].GetRuntimeTypeHandle(); } if (needToDynamicallyLoadTypes) { TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock(() => { typeSystemContext.FlushTypeBuilderStates(); GenericDictionaryCell[] cells = new GenericDictionaryCell[parameters.Length]; for (int i = 0; i < cells.Length; i++) { cells[i] = GenericDictionaryCell.CreateTypeHandleCell(parameters[i]); } IntPtr[] eetypePointers; TypeBuilder.ResolveMultipleCells(cells, out eetypePointers); for (int i = 0; i < parameters.Length; i++) { typesAndValues.types[i] = ((EEType *)eetypePointers[i])->ToRuntimeTypeHandle(); } }); } TypeSystemContextFactory.Recycle(typeSystemContext); LocalVariableType[] argumentTypes = new LocalVariableType[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { // TODO: What these false really means? Need to make sure our format contains those information argumentTypes[i] = new LocalVariableType(typesAndValues.types[i], false, false); } LocalVariableSet.SetupArbitraryLocalVariableSet <TypesAndValues>(HighLevelDebugFuncEvalHelperWithVariables, ref typesAndValues, argumentTypes); } }