/// <summary> /// For a shared (canonical) instance method on a generic valuetype, gets a method that can be used to call the /// method given a boxed version of the generic valuetype as 'this' pointer. /// </summary> public MethodDesc GetSpecialUnboxingThunk(MethodDesc targetMethod, ModuleDesc ownerModuleOfThunk) { Debug.Assert(targetMethod.IsSharedByGenericInstantiations); Debug.Assert(!targetMethod.Signature.IsStatic); Debug.Assert(!targetMethod.HasInstantiation); TypeDesc owningType = targetMethod.OwningType; Debug.Assert(owningType.IsValueType); var owningTypeDefinition = (MetadataType)owningType.GetTypeDefinition(); // Get a reference type that has the same layout as the boxed valuetype. var typeKey = new BoxedValuetypeHashtableKey(owningTypeDefinition, ownerModuleOfThunk); BoxedValueType boxedTypeDefinition = _boxedValuetypeHashtable.GetOrCreateValue(typeKey); // Get a method on the reference type with the same signature as the target method (but different // calling convention, since 'this' will be a reference type). var targetMethodDefinition = targetMethod.GetTypicalMethodDefinition(); var methodKey = new UnboxingThunkHashtableKey(targetMethodDefinition, boxedTypeDefinition); GenericUnboxingThunk thunkDefinition = _unboxingThunkHashtable.GetOrCreateValue(methodKey); // Find the thunk on the instantiated version of the reference type. Debug.Assert(owningType != owningTypeDefinition); InstantiatedType boxedType = boxedTypeDefinition.MakeInstantiatedType(owningType.Instantiation); MethodDesc thunk = GetMethodForInstantiatedType(thunkDefinition, boxedType); Debug.Assert(!thunk.HasInstantiation); return(thunk); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { case Code.Box: (var value, var type) = state.Pop(); var boxedObjectType = new BoxedValueType(Tptr.PtrKind.Pk_pointer, new Tstruct("System.Object"), value, type); // The value in question is boxed into a generic object, which we allocate. (var node, var boxedObjectVariable) = CreateObjectAllocationNode( boxedObjectType, state); RegisterNode(state, node); state.PushExpr(boxedObjectVariable, boxedObjectType); state.PushInstruction(instruction.Next, node); state.AppendToPreviousNode = true; return(true); default: return(false); } }
public MethodDesc GetUnboxingThunk(MethodDesc targetMethod, ModuleDesc ownerModuleOfThunk) { TypeDesc owningType = targetMethod.OwningType; Debug.Assert(owningType.IsValueType); var owningTypeDefinition = (MetadataType)owningType.GetTypeDefinition(); // Get a reference type that has the same layout as the boxed valuetype. var typeKey = new BoxedValuetypeHashtableKey(owningTypeDefinition, ownerModuleOfThunk); BoxedValueType boxedTypeDefinition = _boxedValuetypeHashtable.GetOrCreateValue(typeKey); // Get a method on the reference type with the same signature as the target method (but different // calling convention, since 'this' will be a reference type). var targetMethodDefinition = targetMethod.GetTypicalMethodDefinition(); var methodKey = new UnboxingThunkHashtableKey(targetMethodDefinition, boxedTypeDefinition); UnboxingThunk thunkDefinition = _nonGenericUnboxingThunkHashtable.GetOrCreateValue(methodKey); // Find the thunk on the instantiated version of the reference type. if (owningType != owningTypeDefinition) { InstantiatedType boxedType = boxedTypeDefinition.MakeInstantiatedType(owningType.Instantiation); MethodDesc thunk = GetMethodForInstantiatedType(thunkDefinition, boxedType); //TODO: this might be triggered by a struct that implements an interface with a generic method Debug.Assert(!thunk.HasInstantiation); return(thunk); } else { //TODO: this might be triggered by a struct that implements an interface with a generic method Debug.Assert(!thunkDefinition.HasInstantiation); return(thunkDefinition); } }
public UnboxingThunk(BoxedValueType owningType, MethodDesc targetMethod) { Debug.Assert(targetMethod.OwningType.IsValueType); Debug.Assert(!targetMethod.Signature.IsStatic); _owningType = owningType; _targetMethod = targetMethod; }
public GenericUnboxingThunk(BoxedValueType owningType, MethodDesc targetMethod) { Debug.Assert(targetMethod.OwningType.IsValueType); Debug.Assert(!targetMethod.Signature.IsStatic); _owningType = owningType; _targetMethod = targetMethod; _nakedTargetMethod = new ValueTypeInstanceMethodWithHiddenParameter(targetMethod); }
public UnboxingThunkHashtableKey(MethodDesc targetMethod, BoxedValueType owningType) { TargetMethod = targetMethod; OwningType = owningType; }
public BoxedValueField(BoxedValueType owningType) { _owningType = owningType; }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { case Code.Box: (var value, var type) = state.Pop(); var boxedValueIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var boxedObjectVariable = new VarExpression(boxedValueIdentifier); var boxedObjectType = new BoxedValueType(Tptr.PtrKind.Pk_pointer, new Tstruct("System.Object"), value, type); var callFlags = new Call.CallFlags(false, false, false); // The value in question is boxed into a generic object. var objectAllocationCall = new Call(boxedValueIdentifier, boxedObjectType, new ConstExpression(ProcedureName.BuiltIn__new), new List <Call.CallArg> { new Call.CallArg( new SizeofExpression( boxedObjectType.StripPointer(), "exact"), boxedObjectType) }, callFlags, state.CurrentLocation); var objectConstructorCall = new Call(state.GetIdentifier(Identifier.IdentKind.Normal), new Tvoid(), new ConstExpression(new ProcedureName(".ctor", new List <string>(), "System.Object", "System.Void", false)), new List <Call.CallArg> { new Call.CallArg(boxedObjectVariable, boxedObjectType) }, callFlags, state.CurrentLocation); var node = new StatementNode(state.CurrentLocation, StatementNode.StatementNodeKind.Call, state.ProcDesc, comment: "System.Void System.Object::.ctor()"); node.Instructions.Add(objectAllocationCall); node.Instructions.Add(objectConstructorCall); RegisterNode(state, node); state.PushExpr(boxedObjectVariable, boxedObjectType); state.PushInstruction(instruction.Next, node); state.AppendToPreviousNode = true; return(true); default: return(false); } }