private Task <MethodBody> OptimizeBodyOrWaitAsync( IMethod requestedDef, MethodBodyHolder requestedHolder) { lock (graphLock) { if (IsActive(requestedDef) || IsComplete(requestedDef)) { // If the method is already being optimized then we can just // wait for it to finish. If the method has already been optimized, // then we're already done. return(Start(requestedDef)); } else { // The method's not being optimized yet. Claim it by starting its // optimization process. We'll actually optimize the method once // we get out of the lock. Start(requestedDef); } } // Actually optimize the method's body. return(OptimizeBodyAsync(requestedDef, requestedHolder)); }
private async Task <MethodBody> OptimizeBodyAsync( IMethod requestedDef, MethodBodyHolder requestedHolder) { // Get the method's initial body. var body = requestedHolder.Body; // Create optimization state. var state = new OptimizationState(requestedDef, this); // Apply passes from the pipeline until we're done. foreach (var pass in pipeline) { body = await pass.ApplyAsync(body, state); if (pass.IsCheckpoint) { // Update the method body for the method if we've // reached a checkpoint. requestedHolder.Body = body; } } requestedHolder.Body = body; return(body); }
private Task <MethodBody> OptimizeBodyOrWaitAsync( IMethod requestedDef, IMethod requestingDef, MethodBodyHolder requestedHolder) { lock (graphLock) { // Make sure that the method that's requesting the dependency // is marked as started. Start(requestingDef); // Get the dependency set for the requesting method. var requestingDependencies = dependencies[requestingDef]; if (requestingDependencies.Contains(requestedDef) || IsComplete(requestedDef)) { // If the requesting method is already dependent on the // requested method, then we can just proceed. Ditto for // methods that are fully optimized already. return(Start(requestedDef)); } else if (!IsActive(requestedDef)) { // Looks like the method simply isn't being optimized yet. // This will work to our advantage. requestingDependencies.Add(requestedDef); // "Start" the requested method's optimization to avoid // race conditions where two threads try to optimize the // same method. Start(requestedDef); } else { // Okay, so both methods are currently being optimized and the // requesting method is not yet dependent on the requesting // method. What we need to figure out now is whether introducing // a dependency on the requested method would introduce a cycle // in the dependency graph. Such a cycle means a deadlock, so we // absolutely cannot let that happen. if (IsDependentOn(requestingDef, requestedDef)) { // Introducing a dependency would create a cycle. Return // the latest version of the requested method's body and // call it a day. return(Task.FromResult(requestedHolder.Body)); } else { // Introducing a dependency would not create a cycle. Add the // dependency and wait for the other method to finish. requestingDependencies.Add(requestedDef); return(Start(requestedDef)); } } } // The requested method isn't active yet. We'll just optimize it ourselves. return(OptimizeBodyAsync(requestedDef, requestedHolder)); }