public void CreateBorrowAndTerminateLifetimeNodes(LifetimeVariableAssociation lifetimeVariableAssociation) { if (_borrowRequired) { Node parentNode = _facades.First().Terminal.ParentNode; BorrowMode borrowMode = _mutableBorrow ? BorrowMode.Mutable : BorrowMode.Immutable; int borrowInputCount = _facades.Count; Diagram inputParentDiagram = _facades.First().Terminal.ParentDiagram; var explicitBorrow = new ExplicitBorrowNode(inputParentDiagram, borrowMode, borrowInputCount, true, false); AutoBorrowNodeFacade borrowNodeFacade = AutoBorrowNodeFacade.GetNodeFacade(explicitBorrow); foreach (var terminal in explicitBorrow.Terminals) { borrowNodeFacade[terminal] = new SimpleTerminalFacade(terminal, default(TypeVariableReference)); } int index = 0; foreach (var facade in _facades) { Terminal input = facade.Terminal; VariableReference ownerVariable = input.GetFacadeVariable(), borrowVariable; ((AutoborrowingInputTerminalFacade)facade).AddPostBorrowCoercion(ref input, out borrowVariable); InsertBorrowAheadOfTerminal(input, explicitBorrow, index, ownerVariable, borrowVariable); ++index; } List <TerminateLifetimeOutputTerminalFacade> terminates = new List <TerminateLifetimeOutputTerminalFacade>(); foreach (var terminal in parentNode.OutputTerminals) { var terminateFacade = _nodeFacade[terminal] as TerminateLifetimeOutputTerminalFacade; if (terminateFacade != null && _facades.Contains(terminateFacade.InputFacade)) { terminates.Add(terminateFacade); } } if (terminates.Count == borrowInputCount) { Diagram outputParentDiagram = terminates.First().Terminal.ParentDiagram; var terminateLifetime = CreateNodeFacadesHelpers.CreateTerminateLifetimeWithFacades(outputParentDiagram, borrowInputCount, borrowInputCount); index = 0; foreach (var terminate in terminates) { InsertTerminateLifetimeBehindTerminal(terminate.Terminal, terminateLifetime, index, lifetimeVariableAssociation); ++index; } } else if (terminates.Count > 0) { throw new InvalidOperationException("Mismatched terminates and borrows; not sure what to do"); } } }
public void Execute(DfirRoot dfirRoot, CompileCancellationToken cancellationToken) { var lifetimeGraphTree = dfirRoot.GetLifetimeGraphTree(); BoundedLifetimeLiveVariableSet boundedLifetimeLiveVariableSet; while (_lifetimeVariableAssociation.TryGetBoundedLifetimeWithLiveVariables(out boundedLifetimeLiveVariableSet)) { if (lifetimeGraphTree.IsDiagramLifetimeOfAnyLifetimeGraph(boundedLifetimeLiveVariableSet.Lifetime)) { // Since we assume there are no semantic errors at this point, just mark any remaining live variables // in a diagram lifetime as consumed. boundedLifetimeLiveVariableSet.LiveVariables.Select(l => l.Variable).ForEach(_lifetimeVariableAssociation.MarkVariableConsumed); continue; } int inputVariableCount = boundedLifetimeLiveVariableSet.LiveVariables.Count(); IEnumerable <VariableReference> interruptedVariables = _lifetimeVariableAssociation.GetVariablesInterruptedByLifetime(boundedLifetimeLiveVariableSet.Lifetime); int outputVariableCount = interruptedVariables.Count(); Diagram startSearch = boundedLifetimeLiveVariableSet.LiveVariables.First().Terminal.ParentDiagram; LifetimeGraphIdentifier originGraphIdentifier = lifetimeGraphTree.GetBoundedLifetimeGraphIdentifier(boundedLifetimeLiveVariableSet.Lifetime); Diagram originDiagram = originGraphIdentifier.FindDiagramForGraphIdentifier(startSearch); LiveVariable[] liveVariables = boundedLifetimeLiveVariableSet.LiveVariables.ToArray(); for (int i = 0; i < liveVariables.Length; ++i) { LiveVariable liveVariable = liveVariables[i]; while (liveVariable.Terminal.ParentDiagram != originDiagram) { liveVariable = PullLiveVariableUpToNextHigherDiagram(liveVariable); } liveVariables[i] = liveVariable; } TerminateLifetimeNode terminateLifetime = CreateNodeFacadesHelpers.CreateTerminateLifetimeWithFacades(originDiagram, inputVariableCount, outputVariableCount); foreach (var pair in liveVariables.Zip(terminateLifetime.InputTerminals)) { // TODO: maybe assert that liveVariable.Terminal is unwired here? LiveVariable liveVariable = pair.Key; Terminal terminateLifetimeInputTerminal = pair.Value; liveVariable.ConnectToTerminalAsInputAndUnifyVariables(terminateLifetimeInputTerminal, _unificationResultFactory); _lifetimeVariableAssociation.MarkVariableConsumed(liveVariable.Variable); } foreach (var pair in interruptedVariables.Zip(terminateLifetime.OutputTerminals)) { VariableReference interruptedVariable = pair.Key; Terminal terminateLifetimeOutputTerminal = pair.Value; terminateLifetimeOutputTerminal.GetFacadeVariable().MergeInto(interruptedVariable); _lifetimeVariableAssociation.MarkVariableLive(interruptedVariable, terminateLifetimeOutputTerminal); } } }