/// <summary> /// Constructor. /// </summary> public WeakSymbolRef(string label, Part part, LocalVariableType varType) { Debug.Assert(label != null); Label = label; ValuePart = part; VarType = varType; }
private unsafe static FuncEvalResult CallParameterizedFunctionOrNewParameterizedObject(ref long myFuncEvalId, byte *parameterBuffer, uint parameterBufferSize, bool isConstructor) { InvokeFunctionData invokeFunctionData = new InvokeFunctionData(); LowLevelNativeFormatReader reader = new LowLevelNativeFormatReader(parameterBuffer, parameterBufferSize); myFuncEvalId = s_funcEvalId = (long)reader.GetUnsignedLong(); uint parameterCount = reader.GetUnsigned(); invokeFunctionData.parameterValues = new byte[parameterCount][]; for (int i = 0; i < parameterCount; i++) { uint parameterValueSize = reader.GetUnsigned(); byte[] parameterValue = new byte[parameterValueSize]; for (int j = 0; j < parameterValueSize; j++) { uint parameterByte = reader.GetUnsigned(); parameterValue[j] = (byte)parameterByte; } invokeFunctionData.parameterValues[i] = parameterValue; } ulong[] debuggerPreparedExternalReferences; BuildDebuggerPreparedExternalReferences(reader, out debuggerPreparedExternalReferences); bool hasThis; TypeDesc[] parameters; bool[] parametersWithGenericDependentLayout; bool result = TypeSystemHelper.CallingConverterDataFromMethodSignature( reader, debuggerPreparedExternalReferences, out hasThis, out parameters, out parametersWithGenericDependentLayout ); invokeFunctionData.types = new RuntimeTypeHandle[parameters.Length]; for (int i = 0; i < invokeFunctionData.types.Length; i++) { invokeFunctionData.types[i] = parameters[i].GetRuntimeTypeHandle(); } 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(invokeFunctionData.types[i], false, false); } if (isConstructor) { // TODO, FuncEval, deal with Nullable objects invokeFunctionData.thisObj = RuntimeAugments.RawNewObject(invokeFunctionData.types[1]); } LocalVariableSet.SetupArbitraryLocalVariableSet <InvokeFunctionData>(InvokeFunction, ref invokeFunctionData, argumentTypes); return(invokeFunctionData.result); }
private unsafe static void CallParameterizedFunctionOrNewParameterizedObject(byte *parameterBuffer, uint parameterBufferSize, bool isConstructor) { TypesAndValues typesAndValues = new TypesAndValues(); uint offset = 0; NativeReader reader = new NativeReader(parameterBuffer, parameterBufferSize); uint parameterCount; offset = reader.DecodeUnsigned(offset, out parameterCount); typesAndValues.parameterValues = new byte[parameterCount][]; for (int i = 0; i < parameterCount; i++) { uint parameterValueSize; 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; } ulong[] debuggerPreparedExternalReferences; offset = BuildDebuggerPreparedExternalReferences(reader, offset, out debuggerPreparedExternalReferences); 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]; for (int i = 0; i < typesAndValues.types.Length; i++) { typesAndValues.types[i] = parameters[i].GetRuntimeTypeHandle(); } 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); } if (isConstructor) { typesAndValues.thisObj = RuntimeAugments.NewObject(typesAndValues.types[1]); } LocalVariableSet.SetupArbitraryLocalVariableSet <TypesAndValues>(HighLevelDebugFuncEvalHelperWithVariables, ref typesAndValues, argumentTypes); }
private static void HighLevelDebugFuncEvalHelperWithVariables(ref TypesAndValues param, ref LocalVariableSet arguments) { for (int i = 0; i < param.parameterValues.Length; i++) { unsafe { IntPtr input = arguments.GetAddressOfVarData(i + 1); byte * pInput = (byte *)input; fixed(byte *pParam = param.parameterValues[i]) { for (int j = 0; j < param.parameterValues[i].Length; j++) { pInput[j] = pParam[j]; } } } } // Obtain the target method address from the runtime IntPtr targetAddress = RuntimeAugments.RhpGetFuncEvalTargetAddress(); LocalVariableType[] returnAndArgumentTypes = new LocalVariableType[param.types.Length]; for (int i = 0; i < returnAndArgumentTypes.Length; i++) { returnAndArgumentTypes[i] = new LocalVariableType(param.types[i], false, false); } // Hard coding static here DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(Internal.Runtime.CallConverter.CallingConvention.ManagedStatic, returnAndArgumentTypes, returnAndArgumentTypes.Length); // Invoke the target method Internal.Runtime.CallInterceptor.CallInterceptor.MakeDynamicCall(targetAddress, dynamicCallSignature, arguments); unsafe { // Box the return IntPtr input = arguments.GetAddressOfVarData(0); object returnValue = RuntimeAugments.RhBoxAny(input, (IntPtr)param.types[0].ToEETypePtr()); IntPtr returnValueHandlePointer = IntPtr.Zero; uint returnHandleIdentifier = 0; // The return value could be null if the target function returned null if (returnValue != null) { GCHandle returnValueHandle = GCHandle.Alloc(returnValue); returnValueHandlePointer = GCHandle.ToIntPtr(returnValueHandle); returnHandleIdentifier = RuntimeAugments.RhpRecordDebuggeeInitiatedHandle(returnValueHandlePointer); } ReturnToDebugger(returnHandleIdentifier, returnValueHandlePointer); } }
private static void HighLevelDebugFuncEvalHelperWithVariables(ref TypesAndValues param, ref LocalVariableSet arguments) { for (int i = 0; i < param.parameterValues.Length; i++) { arguments.SetVar <int>(i + 1, param.parameterValues[i]); } // Obtain the target method address from the runtime IntPtr targetAddress = RuntimeAugments.RhpGetFuncEvalTargetAddress(); LocalVariableType[] returnAndArgumentTypes = new LocalVariableType[param.types.Length]; for (int i = 0; i < returnAndArgumentTypes.Length; i++) { returnAndArgumentTypes[i] = new LocalVariableType(param.types[i], false, false); } // Hard coding static here DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(Internal.Runtime.CallConverter.CallingConvention.ManagedStatic, returnAndArgumentTypes, returnAndArgumentTypes.Length); // Invoke the target method Internal.Runtime.CallInterceptor.CallInterceptor.MakeDynamicCall(targetAddress, dynamicCallSignature, arguments); unsafe { // Box the return IntPtr input = arguments.GetAddressOfVarData(0); object returnValue = RuntimeAugments.RhBoxAny(input, (IntPtr)param.types[0].ToEETypePtr()); GCHandle returnValueHandle = GCHandle.Alloc(returnValue); IntPtr returnValueHandlePointer = GCHandle.ToIntPtr(returnValueHandle); uint returnHandleIdentifier = RuntimeAugments.RhpRecordDebuggeeInitiatedHandle(returnValueHandlePointer); // Signal to the debugger the func eval completes FuncEvalCompleteCommand *funcEvalCompleteCommand = stackalloc FuncEvalCompleteCommand[1]; funcEvalCompleteCommand->commandCode = 0; funcEvalCompleteCommand->returnHandleIdentifier = returnHandleIdentifier; funcEvalCompleteCommand->returnAddress = (long)returnValueHandlePointer; IntPtr funcEvalCompleteCommandPointer = new IntPtr(funcEvalCompleteCommand); RuntimeAugments.RhpSendCustomEventToDebugger(funcEvalCompleteCommandPointer, Unsafe.SizeOf <FuncEvalCompleteCommand>()); } // debugger magic will make sure this function never returns, instead control will be transferred back to the point where the FuncEval begins }
private static void HighLevelDebugFuncEvalHelper() { int integerParameterValue = 0; uint parameterBufferSize = RuntimeImports.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); } RuntimeImports.RhpSendCustomEventToDebugger(writeParameterCommandPointer, Unsafe.SizeOf <WriteParameterCommand>()); // .. debugger magic ... the debuggerBuffer will be filled with parameter data unsafe { integerParameterValue = Unsafe.Read <int>(debuggerBufferPointer.ToPointer()); } // Hard coding a single argument of type int here LocalVariableType[] argumentTypes = new LocalVariableType[2]; argumentTypes[0] = new LocalVariableType(typeof(void).TypeHandle, false, false); argumentTypes[1] = new LocalVariableType(typeof(int).TypeHandle, false, false); LocalVariableSet.SetupArbitraryLocalVariableSet <int>(HighLevelDebugFuncEvalHelperWithVariables, ref integerParameterValue, argumentTypes); }
private static void HighLevelDebugFuncEvalHelperWithVariables(ref int param, ref LocalVariableSet arguments) { // Hard coding the argument integer here! arguments.SetVar <int>(1, param); // Obtain the target method address from the runtime IntPtr targetAddress = RuntimeImports.RhpGetFuncEvalTargetAddress(); // Hard coding a single void return here LocalVariableType[] returnAndArgumentTypes = new LocalVariableType[2]; returnAndArgumentTypes[0] = new LocalVariableType(typeof(void).TypeHandle, false, false); returnAndArgumentTypes[1] = new LocalVariableType(typeof(int).TypeHandle, false, false); // Hard coding static here DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(Internal.Runtime.CallConverter.CallingConvention.ManagedStatic, returnAndArgumentTypes, returnAndArgumentTypes.Length); // Invoke the target method Internal.Runtime.CallInterceptor.CallInterceptor.MakeDynamicCall(targetAddress, dynamicCallSignature, arguments); // Signal to the debugger the func eval completes IntPtr funcEvalCompleteCommandPointer; unsafe { FuncEvalCompleteCommand funcEvalCompleteCommand = new FuncEvalCompleteCommand { commandCode = 0 }; funcEvalCompleteCommandPointer = new IntPtr(&funcEvalCompleteCommand); } RuntimeImports.RhpSendCustomEventToDebugger(funcEvalCompleteCommandPointer, Unsafe.SizeOf <FuncEvalCompleteCommand>()); // debugger magic will make sure this function never returns, instead control will be transferred back to the point where the FuncEval begins }
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 static void HighLevelDebugFuncEvalHelperWithVariables(ref TypesAndValues param, ref LocalVariableSet arguments) { // Offset begins with 1 because we always skip setting the return value before we call the function int offset = 1; if (param.thisObj != null) { // For constructors - caller does not pass the this pointer, instead, we constructed param.thisObj and pass it as the first argument arguments.SetVar <object>(offset, param.thisObj); offset++; } for (int i = 0; i < param.parameterValues.Length; i++) { unsafe { IntPtr input = arguments.GetAddressOfVarData(i + offset); byte * pInput = (byte *)input; fixed(byte *pParam = param.parameterValues[i]) { for (int j = 0; j < param.parameterValues[i].Length; j++) { pInput[j] = pParam[j]; } } } } // Obtain the target method address from the runtime IntPtr targetAddress = RuntimeAugments.RhpGetFuncEvalTargetAddress(); LocalVariableType[] returnAndArgumentTypes = new LocalVariableType[param.types.Length]; for (int i = 0; i < returnAndArgumentTypes.Length; i++) { returnAndArgumentTypes[i] = new LocalVariableType(param.types[i], false, false); } // Hard coding static here DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(Internal.Runtime.CallConverter.CallingConvention.ManagedStatic, returnAndArgumentTypes, returnAndArgumentTypes.Length); // Invoke the target method Exception ex = null; try { Internal.Runtime.CallInterceptor.CallInterceptor.MakeDynamicCall(targetAddress, dynamicCallSignature, arguments); } catch (Exception e) { ex = e; } unsafe { bool isVoid = (RuntimeTypeHandle.Equals(param.types[0], typeof(void).TypeHandle)); object returnValue = null; IntPtr returnValueHandlePointer = IntPtr.Zero; uint returnHandleIdentifier = 0; if (ex != null) { returnValue = ex; } else if (param.thisObj != null) { // For constructors - the debugger would like to get 'this' back returnValue = param.thisObj; } else if (!isVoid) { IntPtr input = arguments.GetAddressOfVarData(0); returnValue = RuntimeAugments.RhBoxAny(input, param.types[0].Value); } // The return value could be null if the target function returned null if (returnValue != null) { GCHandle returnValueHandle = GCHandle.Alloc(returnValue); returnValueHandlePointer = GCHandle.ToIntPtr(returnValueHandle); returnHandleIdentifier = RuntimeAugments.RhpRecordDebuggeeInitiatedHandle(returnValueHandlePointer); } ReturnToDebuggerWithReturn(returnHandleIdentifier, returnValueHandlePointer, ex != null); } }
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); } }
private unsafe static void InvokeFunction(ref InvokeFunctionData invokeFunctionData, ref LocalVariableSet arguments) { // Offset begins with 1 because we always skip setting the return value before we call the function int offset = 1; if (invokeFunctionData.thisObj != null) { // For constructors - caller does not pass the this pointer, instead, we constructed param.thisObj and pass it as the first argument arguments.SetVar <object>(offset, invokeFunctionData.thisObj); offset++; } for (int i = 0; i < invokeFunctionData.parameterValues.Length; i++) { IntPtr input = arguments.GetAddressOfVarData(i + offset); byte * pInput = (byte *)input; fixed(byte *pParam = invokeFunctionData.parameterValues[i]) { for (int j = 0; j < invokeFunctionData.parameterValues[i].Length; j++) { pInput[j] = pParam[j]; } } } // Obtain the target method address from the runtime IntPtr targetAddress = RuntimeAugments.RhpGetFuncEvalTargetAddress(); LocalVariableType[] returnAndArgumentTypes = new LocalVariableType[invokeFunctionData.types.Length]; for (int i = 0; i < returnAndArgumentTypes.Length; i++) { returnAndArgumentTypes[i] = new LocalVariableType(invokeFunctionData.types[i], false, false); } DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(invokeFunctionData.callingConvention, returnAndArgumentTypes, returnAndArgumentTypes.Length); // Invoke the target method Exception ex = null; try { Internal.Runtime.CallInterceptor.CallInterceptor.MakeDynamicCall(targetAddress, dynamicCallSignature, arguments); } catch (Exception e) { ex = e; } bool isVoid = (RuntimeTypeHandle.Equals(invokeFunctionData.types[0], typeof(void).TypeHandle)); object returnValue = null; if (ex != null) { returnValue = ex; } else if (invokeFunctionData.thisObj != null) { // For constructors - the debugger would like to get 'this' back returnValue = invokeFunctionData.thisObj; } else if (!isVoid) { IntPtr input = arguments.GetAddressOfVarData(0); returnValue = RuntimeAugments.RhBoxAny(input, invokeFunctionData.types[0].Value); } // Note that the return value could be null if the target function returned null invokeFunctionData.result = new FuncEvalResult(returnValue, ex != null); }