public FunctionTransformPipeline( AssemblyTranslator translator, QualifiedMemberIdentifier identifier, JSFunctionExpression function, SpecialIdentifiers si ) { Translator = translator; Identifier = identifier; Function = function; SpecialIdentifiers = si; FillPipeline(); if (!Translator.FunctionCache.ActiveTransformPipelines.TryAdd(Identifier, this)) { throw new ThreadStateException(); } if (CheckForStaticAnalysisChanges) { OriginalFunctionBody = Function.Body.ToString(); OriginalSecondPass = Translator.FunctionCache.GetSecondPass(function.Method, function.Method.QualifiedIdentifier); } }
private void CloneArgumentsIfNecessary( IEnumerable<KeyValuePair<ParameterDefinition, JSExpression>> parameters, IList<JSExpression> argumentValues, FunctionAnalysis2ndPass sa ) { var parms = parameters.ToArray(); for (int i = 0, c = parms.Length; i < c; i++) { var pd = parms[i].Key; var argument = parms[i].Value; string parameterName = null; if (pd != null) parameterName = pd.Name; GenericParameter relevantParameter; if (IsParameterCopyNeeded(sa, parameterName, argument, out relevantParameter)) { if (Tracing) Debug.WriteLine(String.Format("struct copy introduced for argument #{0}: {1}", i, argument)); argumentValues[i] = MakeCopyForExpression(argument, relevantParameter); } else { if (Tracing && TypeUtil.IsStruct(argument.GetActualType(TypeSystem))) Debug.WriteLine(String.Format("struct copy elided for argument #{0}: {1}", i, argument)); } } }
protected bool IsParameterCopyNeeded (FunctionAnalysis2ndPass sa, string parameterName, JSExpression expression, out GenericParameter relevantParameter) { if (!IsCopyNeeded(expression, out relevantParameter)) return false; if (sa == null) return true; if (!OptimizeCopies) return true; bool modified = true, escapes = true, isResult = false; if (parameterName != null) { modified = sa.ModifiedVariables.Contains(parameterName); escapes = sa.EscapingVariables.Contains(parameterName); isResult = sa.ResultVariable == parameterName; } return modified || (escapes && !isResult); }
public void VisitNode (JSFunctionExpression fn) { var countRefs = new CountVariableReferences(ReferenceCounts); countRefs.Visit(fn.Body); SecondPass = GetSecondPass(fn.Method); if (SecondPass == null) throw new InvalidDataException("No second-pass static analysis data for function '" + fn.Method.QualifiedIdentifier + "'"); VisitChildren(fn); }
public void VisitNode(JSFunctionExpression fn) { // Create a new visitor for nested function expressions if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) { var nested = new EmulateStructAssignment(TypeSystem, FunctionSource, CLR, OptimizeCopies); nested.Visit(fn); return; } var countRefs = new CountVariableReferences(ReferenceCounts); countRefs.Visit(fn.Body); SecondPass = FunctionSource.GetSecondPass(fn.Method); VisitChildren(fn); }
public bool RunUntilCompletion() { const int lockTimeoutMs = 250; bool completed = false; var entry = Translator.FunctionCache.GetCacheEntry(Identifier); TrackedLockCollection.DeadlockInfo deadlock; var lockResult = entry.StaticAnalysisDataLock.TryBlockingEnter(out deadlock, timeoutMs: lockTimeoutMs); if (!lockResult.Success) { if (deadlock != null) { Console.Error.WriteLine("Failed to lock '{0}' for transform pipeline: {1} {2}", Identifier, lockResult.FailureReason, deadlock); } return(false); } try { while (Pipeline.Count > 0) { var currentStage = Pipeline.Peek(); try { if (currentStage()) { Pipeline.Dequeue(); if (CheckForStaticAnalysisChanges) { var currentSecondPass = Translator.FunctionCache.GetSecondPass(this.Function.Method, this.Function.Method.QualifiedIdentifier); string[] differences; if (!currentSecondPass.Equals(OriginalSecondPass, out differences)) { var currentFunctionBody = Function.Body.ToString(); Console.WriteLine("// Second pass data changed by pipeline stage '" + currentStage.Method.Name + "' - " + String.Join(", ", differences)); Console.WriteLine("// Original function body //"); Console.WriteLine(OriginalFunctionBody); Console.WriteLine("// New function body //"); Console.WriteLine(currentFunctionBody); OriginalSecondPass = currentSecondPass; OriginalFunctionBody = currentFunctionBody; } } } else { SuspendCount += 1; return(completed = false); } } catch (Exception exc) { string functionName; if ((Function.Method != null) && (Function.Method.Reference != null)) { functionName = Function.Method.Reference.FullName; } else { functionName = Function.DisplayName ?? "<unknown>"; } throw new FunctionTransformFailureException(functionName, currentStage.Method.Name, exc); } } return(completed = true); } finally { entry.TransformPipelineHasCompleted |= completed; entry.StaticAnalysisDataLock.Exit(); if (completed) { FunctionTransformPipeline temp; if (!Translator.FunctionCache.ActiveTransformPipelines.TryRemove(Identifier, out temp)) { throw new ThreadStateException(); } } else { if (!Translator.FunctionCache.PendingTransformsQueue.TryEnqueue(Identifier)) { throw new ThreadStateException(); } } } }
protected bool IsArgumentCopyNeeded (FunctionAnalysis2ndPass sa, string parameterName, JSExpression expression, out GenericParameter relevantParameter) { if (!IsCopyNeeded(expression, out relevantParameter)) return false; if (sa == null) return true; if (!OptimizeCopies) return true; bool modified = true, escapes = true, isResult = false; if (parameterName != null) { modified = sa.IsVariableModified(parameterName); escapes = sa.DoesVariableEscape(parameterName, true); isResult = sa.ResultVariable == parameterName; } var result = modified || (escapes && !isResult); if (!result) { if (TraceElidedCopies) Console.WriteLine("argument {0} ('{1}') needs no copy because it isn't modified and doesn't escape", expression, parameterName); } return result; }