private void InjectTailCall() { for (var i = 0; i < IL.Index; i++) { var instr = IL[i]; BufferedILInstruction call = null; if (instr.IsInstruction == OpCodes.Ret) { int callIx = -1; for (var j = i - 1; j >= 0; j--) { var atJ = IL[j]; if (atJ.MarksLabel != null) { break; } if (atJ.IsInstruction.HasValue) { if (ExtensionMethods.IsTailableCall(atJ.IsInstruction.Value)) { callIx = j; call = atJ; } break; } } if (callIx == -1) { continue; } if (call.TakesManagedPointer()) { continue; } #if !COREFX // see https://github.com/dotnet/corefx/issues/4543 item 4 if (call.TakesTypedReference()) { continue; } #endif if (call.TakesByRefArgs()) { continue; } InsertInstruction(callIx, OpCodes.Tailcall); i++; } } }
private void InjectTailCall() { for (var i = 0; i < IL.Index; i++) { var instr = IL[i]; BufferedILInstruction call = null; if (instr.IsInstruction == OpCodes.Ret) { int callIx = -1; for (var j = i - 1; j >= 0; j--) { var atJ = IL[j]; if (atJ.MarksLabel != null) { break; } if (atJ.IsInstruction.HasValue) { if (ExtensionMethods.IsTailableCall(atJ.IsInstruction.Value)) { callIx = j; call = atJ; } break; } } if (callIx == -1) { continue; } if (call.TakesManagedPointer()) { continue; } if (call.TakesTypedReference()) { continue; } InsertInstruction(callIx, OpCodes.Tailcall); i++; } } }
private void InjectTailCall() { for (var i = 0; i < IL.Index; i++) { var instr = IL[i]; BufferedILInstruction call = null; if (instr.IsInstruction == OpCodes.Ret) { int callIx = -1; for (var j = i - 1; j >= 0; j--) { var atJ = IL[j]; if (atJ.MarksLabel != null) { break; } if (atJ.IsInstruction.HasValue) { if (ExtensionMethods.IsTailableCall(atJ.IsInstruction.Value)) { callIx = j; call = atJ; } break; } } if (callIx == -1) { continue; } if (call.TakesManagedPointer()) { continue; } // TODO: see https://github.com/dotnet/corefx/issues/4543 item 4 #if !NETSTANDARD if (call.TakesTypedReference()) { continue; } #endif if (call.TakesByRefArgs()) { continue; } var callReturns = call.MethodReturnType; var delegateReturns = ReturnType.Type; // the method's return types not matching // means we can't just turn the call into a jump // since _something_ has to preceed or survive the call to // make the ret legal if (!ExtensionMethods.IsAssignableFrom(delegateReturns, callReturns)) { continue; } // there's one case not being handled explicitly here, // which is the call must consume the _entire_ stack. // we don't have to asset it because the return type // comparison is sufficient: // - if the types match, the stack must be empty // or the following ret will fail to verify (since // there's an extra item of the corret type on the stack) // - if the types _don't_ match, we've already bailed on the // tail injection InsertInstruction(callIx, OpCodes.Tailcall); i++; } } }