private ContinuationClassInfo GetContinuationClass(ModuleDefinition module, TypeReference taskReturnType) { if (taskReturnType.MetadataType == MetadataType.Void) { return(GetContinuationClassCore(module, true)); } ContinuationClassInfo genClassInfo = GetContinuationClassCore(module, false); GenericInstanceType instType = new GenericInstanceType(genClassInfo.ContinuationClass); instType.GenericArguments.Add(taskReturnType); return(new ContinuationClassInfo() { ContinuationClass = instType, CallbackField = GetReferenceForInstantiatedType(genClassInfo.CallbackField, instType), TcsField = GetReferenceForInstantiatedType(genClassInfo.TcsField, instType), Constructor = GetReferenceForInstantiatedType(genClassInfo.Constructor, instType), InvokeMethod = GetReferenceForInstantiatedType(genClassInfo.InvokeMethod, instType) }); }
private ContinuationClassInfo GetContinuationClassCore(ModuleDefinition module, bool isVoid) { if (isVoid && contClassForVoid != null) { return(contClassForVoid); } if (!isVoid && contClassForNonVoid != null) { return(contClassForNonVoid); } ContinuationClassInfo ci = new ContinuationClassInfo(); TypeDefinition classDef = new TypeDefinition("", "<asyncContinuationClass>" + (isVoid ? "" : "`1"), TypeAttributes.Sealed, module.TypeSystem.Object); classDef.CustomAttributes.Add(generatedCodeAttr); TypeReference taskReturnType, selfInst; if (!isVoid) { classDef.GenericParameters.Add(new GenericParameter("T", classDef)); taskReturnType = classDef.GenericParameters[0]; selfInst = new GenericInstanceType(classDef); ((GenericInstanceType)selfInst).GenericArguments.Add(classDef.GenericParameters[0]); } else { taskReturnType = module.TypeSystem.Object; selfInst = classDef; } ci.ContinuationClass = classDef; GenericInstanceType genTaskType = new GenericInstanceType(taskOpenType); genTaskType.GenericArguments.Add(taskReturnType); TypeReference taskType = isVoid ? taskBaseType : genTaskType; FieldDefinition callbackGen = new FieldDefinition("Callback", FieldAttributes.Public, asyncCallbackType); classDef.Fields.Add(callbackGen); ci.CallbackField = callbackGen; var callback = new FieldReference(callbackGen.Name, callbackGen.FieldType, selfInst); var tcsType = new GenericInstanceType(taskCompletionSourceType); tcsType.GenericArguments.Add(isVoid ? module.TypeSystem.Object : taskReturnType); FieldDefinition tcsGen = new FieldDefinition("Tcs", FieldAttributes.Public, tcsType); classDef.Fields.Add(tcsGen); ci.TcsField = tcsGen; var tcs = new FieldReference(tcsGen.Name, tcsGen.FieldType, selfInst); var trySetExceptionRef = new MethodReference("TrySetException", module.TypeSystem.Boolean, tcsType) { HasThis = true }; trySetExceptionRef.Parameters.Add(new ParameterDefinition(iEnumerableExceptionType)); var trySetCanceledRef = new MethodReference("TrySetCanceled", module.TypeSystem.Boolean, tcsType) { HasThis = true }; var trySetResultRef = new MethodReference("TrySetResult", module.TypeSystem.Boolean, tcsType) { HasThis = true }; trySetResultRef.Parameters.Add(new ParameterDefinition(taskCompletionSourceType.GenericParameters[0])); var taskOfTcsTP0 = new GenericInstanceType(taskOpenType); taskOfTcsTP0.GenericArguments.Add(taskCompletionSourceType.GenericParameters[0]); var getTaskRef = new MethodReference("get_Task", taskOfTcsTP0, tcsType) { HasThis = true }; MethodReference get_Result = null; if (!isVoid) { get_Result = new MethodReference("get_Result", taskOpenType.GenericParameters[0], taskType) { HasThis = true } } ; MethodDefinition ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); var il = ctor.Body.GetILProcessor(); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Call, objectCtor); // base() il.Emit(OpCodes.Ret); classDef.Methods.Add(ctor); ci.Constructor = ctor; MethodDefinition invoke = new MethodDefinition("Invoke", MethodAttributes.Public, module.TypeSystem.Void); var taskArg = new ParameterDefinition(taskType); invoke.Parameters.Add(taskArg); il = invoke.Body.GetILProcessor(); il.Emit(OpCodes.Ldarg_1); // task il.Emit(OpCodes.Callvirt, task_get_IsFaultedMethod); var notFaultedCont = Instruction.Create(OpCodes.Ldarg_1); il.Emit(OpCodes.Brfalse_S, notFaultedCont); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, tcs); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Callvirt, task_get_ExceptionMethod); il.Emit(OpCodes.Callvirt, get_InnerExceptionsMethod); il.Emit(OpCodes.Callvirt, trySetExceptionRef); il.Emit(OpCodes.Pop); var callbackCont = Instruction.Create(OpCodes.Ldarg_0); il.Emit(OpCodes.Br_S, callbackCont); il.Append(notFaultedCont); // ldarg.1 il.Emit(OpCodes.Callvirt, task_get_IsCanceledMethod); var notCanceledCont = Instruction.Create(OpCodes.Ldarg_0); il.Emit(OpCodes.Brfalse_S, notCanceledCont); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, tcs); il.Emit(OpCodes.Callvirt, trySetCanceledRef); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Br_S, callbackCont); il.Append(notCanceledCont); // ldarg.0 il.Emit(OpCodes.Ldfld, tcs); il.Emit(OpCodes.Ldarg_1); if (isVoid) { il.Emit(OpCodes.Callvirt, task_WaitMethod); il.Emit(OpCodes.Ldnull); } else { il.Emit(OpCodes.Callvirt, get_Result); } il.Emit(OpCodes.Callvirt, trySetResultRef); il.Emit(OpCodes.Pop); il.Append(callbackCont); // ldarg.0 il.Emit(OpCodes.Ldfld, callback); il.Emit(OpCodes.Dup); var endPopRet = Instruction.Create(OpCodes.Pop); il.Emit(OpCodes.Brfalse_S, endPopRet); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, tcs); il.Emit(OpCodes.Callvirt, getTaskRef); il.Emit(OpCodes.Callvirt, asyncCallbackInvokeMethod); il.Emit(OpCodes.Ret); il.Append(endPopRet); // pop il.Emit(OpCodes.Ret); classDef.Methods.Add(invoke); ci.InvokeMethod = invoke; module.Types.Add(classDef); if (isVoid) { contClassForVoid = ci; } else { contClassForNonVoid = ci; } return(ci); }