예제 #1
0
        private EvaluationResult QualifiedEvaluateWithCycleDetection(ref object value, ImmutableContextBase context, ModuleLiteral env, Evaluation currentEvaluation, ref MutableContextFactory factory)
        {
            // Someone else is already busy evaluating this thunk. Let's wait...
            EvaluationStatus result;
            var cycleDetector = context.FrontEndHost.CycleDetector;

            if (cycleDetector != null)
            {
                using (cycleDetector.AddValuePromiseChain(
                           valuePromiseChainGetter: () => GetValuePromiseChain(context, env),
                           cycleAnnouncer: () => currentEvaluation.Cancel(EvaluationStatus.Cycle)))
                {
                    currentEvaluation.Wait(cycleDetector);
                    result = currentEvaluation.Result;
                    if ((result & EvaluationStatus.Value) != 0)
                    {
                        var currentValue = Volatile.Read(ref value);
                        Contract.Assert(currentValue is EvaluationResult);
                        return((EvaluationResult)currentValue);
                    }
                }
            }
            else
            {
                currentEvaluation.Wait();
                result = currentEvaluation.Result;
                if ((result & EvaluationStatus.Value) != 0)
                {
                    var currentValue = Volatile.Read(ref value);
                    Contract.Assert(currentValue is EvaluationResult);
                    return((EvaluationResult)currentValue);
                }
            }

            // Evaluation got canceled --- we hit a cycle (or deadlock)!
            if ((result & EvaluationStatus.Cycle) != 0)
            {
                context.Errors.ReportCycle(env, Expression.Location, factory.ContextName);
                currentEvaluation.SetValue(ref value, EvaluationResult.Error);
                return(EvaluationResult.Error);
            }

            // Evaluation crashed, which means that Expression.Eval had failed, and had thrown an exception.
            if ((result & EvaluationStatus.Crash) != 0)
            {
                // Crash has been reported at the crash site.
                currentEvaluation.SetValue(ref value, EvaluationResult.Error);
                return(EvaluationResult.Error);
            }

            return(EvaluationResult.Error);
        }
예제 #2
0
        private EvaluationResult QualifiedEvaluate(
            ref object value,
            ImmutableContextBase context,
            ModuleLiteral env,
            EvaluationStackFrame args,
            ref MutableContextFactory factory)
        {
            // do we have a real value yet?
            var currentValue      = Volatile.Read(ref value);
            var currentEvaluation = currentValue as Evaluation;

            if (currentValue != currentEvaluation)
            {
                Contract.Assert(currentValue is EvaluationResult);

                // so it's not null, and it's not an evaluation => we have a real value!
                return((EvaluationResult)currentValue);
            }

            // no real value yet, let's try to create a new evaluation
            if (currentEvaluation == null && !factory.ForceWaitForResult)
            {
                var newEvaluation = new Evaluation(
                    context.EvaluatorConfiguration.CycleDetectorStartupDelay,
                    context.EvaluatorConfiguration.CycleDetectorIncreasePriorityDelay);
                currentValue      = Interlocked.CompareExchange(ref value, newEvaluation, null);
                currentEvaluation = currentValue as Evaluation;
                if (currentValue != currentEvaluation)
                {
                    Contract.Assert(currentValue is EvaluationResult);

                    // so it's not null, and it's not an evaluation => we have a real value! (and the CompareExchange must have failed)
                    return((EvaluationResult)currentValue);
                }

                if (currentValue == null)
                {
                    using (var newLocalMutableContext = factory.Create(context))
                    {
                        try
                        {
                            var newValue = Expression.Eval(newLocalMutableContext, env, args);

                            // Evaluation got canceled --- we hit a cycle (or deadlock)!
                            if ((newEvaluation.Result & EvaluationStatus.Cycle) != 0)
                            {
                                newLocalMutableContext.Errors.ReportCycle(env, Expression.Location);
                                newEvaluation.SetValue(ref value, EvaluationResult.Error);
                                return(EvaluationResult.Error);
                            }

                            newEvaluation.SetValue(ref value, newValue);
                            return(newValue);
                        }
                        catch
                        {
                            // No actual value was ever set --- this means that Expression.Eval failed, and most likely threw an exception!
                            // Let's propagate this result, so that anyone else waiting for us gets unblocked.
                            newEvaluation.Cancel(EvaluationStatus.Crash);
                            throw;
                        }
                        finally
                        {
                            Contract.Assert(!newLocalMutableContext.HasChildren);

                            // just before the newly created context get disposed, we want to assert that all of its child contexts have already been disposed
                        }
                    }
                }

                // there's already an ongoing evaluation! (and the CompareExchange must have failed) we fall through...
            }

            if (factory.ForceWaitForResult)
            {
                while (currentEvaluation == null)
                {
                    Thread.Sleep(TimeSpan.FromMilliseconds(10));
                    currentEvaluation = Volatile.Read(ref value) as Evaluation;
                }
            }

            return(QualifiedEvaluateWithCycleDetection(ref value, context, env, currentEvaluation, ref factory));
        }