Esempio n. 1
0
        /// <summary>
        /// Evaluates this thunk in a new named context
        /// </summary>
        /// <remarks>
        /// V1-specific. Still used to evaluate configuration-related files in V2 (and for the whole V1 legacy evaluation).
        /// </remarks>
        public EvaluationResult LegacyEvaluateWithNewNamedContext(ImmutableContextBase context, ModuleLiteral module, FullSymbol contextName, LineInfo location, bool forceWaitForResult = false)
        {
            // There is no captured template value in V1
            var factory = new MutableContextFactory(this, contextName, module, templateValue: null, location: location, forceWaitForResult: forceWaitForResult);

            return(EvaluateWithNewNamedContextAndTemplate(context, ref factory));
        }
Esempio n. 2
0
        /// <summary>
        /// Evaluates this thunk in a new named context
        /// </summary>
        /// <remarks>
        /// V1-specific. Still used to evaluate configuration-related files in V2 (and for the whole V1 legacy evaluation).
        /// </remarks>
        public EvaluationResult LegacyEvaluateWithNewNamedContext(ImmutableContextBase context, ModuleLiteral module, FullSymbol contextName, LineInfo location)
        {
            // There is no captured template value in V1
            var factory = MutableContextFactory.Create(this, contextName, module, templateValue: null, location: location);

            return(EvaluateWithNewNamedContextAndTemplate(context, ref factory));
        }
Esempio n. 3
0
        /// <summary>
        /// Evaluates this thunk in a new named context
        /// </summary>
        /// <remarks>
        /// V2-specific.
        /// </remarks>
        public EvaluationResult EvaluateWithNewNamedContext(Context context, ModuleLiteral module, FullSymbol contextName, LineInfo location)
        {
            Contract.Assert(CapturedTemplateReference != null);

            // We evaluate the captured template that was captured for this thunk in the same way (context and module) the thunk will be
            using (var frame = EvaluationStackFrame.Empty())
            {
                var templateValue = CapturedTemplateReference.Eval(context, module, frame);
                if (templateValue.IsErrorValue)
                {
                    return(EvaluationResult.Error);
                }

                var factory = new MutableContextFactory(this, contextName, module, templateValue.Value, location);
                return(EvaluateWithNewNamedContextAndTemplate(context, ref factory));
            }
        }
Esempio n. 4
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);
        }
Esempio n. 5
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));
        }
Esempio n. 6
0
        /// <summary>
        /// Evaluates thunk by lazily creating the context only if the thunk has not been evaluated yet.
        /// </summary>
        public EvaluationResult Evaluate(ImmutableContextBase context, ModuleLiteral env, EvaluationStackFrame args, ref MutableContextFactory factory)
        {
            context.EvaluationScheduler.CancellationToken.ThrowIfCancellationRequested();

            QualifierValue qualifier = env.GetFileQualifier() ?? env.Qualifier;

            // Looking in the optimized map if the qualifier id is small enough.
            QualifiedValue qualifiedEntry;

            if (qualifier.QualifierId.IsValid && qualifier.QualifierId.Id < TableSize)
            {
                qualifiedEntry = GetQualifiedValue(qualifier.QualifierId.Id);
            }
            else
            {
                // Falling back to more memory intensive concurrent dictionary.
                EnsureDictionaryIsInitialized();
                qualifiedEntry = m_qualifiedDictionary.GetOrAdd(qualifier.QualifierId, new QualifiedValue());
            }

            var qualifiedValue = qualifiedEntry.Value;

            var result = (qualifiedValue == null || qualifiedValue is Evaluation)
                ? QualifiedEvaluate(ref qualifiedEntry.Value, context, env, args, ref factory)
                : (EvaluationResult)qualifiedValue;

            // Cancel evaluation if (1) result is an error value, (2) we are configured to cancel evaluation after first failure, and (3) cancellation hasn't already been requested
            if (result.IsErrorValue &&
                context.FrontEndHost.FrontEndConfiguration.CancelEvaluationOnFirstFailure() &&
                !context.EvaluationScheduler.CancellationToken.IsCancellationRequested)
            {
                context.Logger.EvaluationCancellationRequestedAfterFirstFailure(context.LoggingContext);
                context.EvaluationScheduler.Cancel();
            }

            return(result);
        }
Esempio n. 7
0
 private EvaluationResult EvaluateWithNewNamedContextAndTemplate(ImmutableContextBase context, ref MutableContextFactory factory)
 {
     using (var frame = EvaluationStackFrame.Empty())
     {
         return(Evaluate(
                    context: context,
                    env: factory.Module,
                    args: frame,
                    factory: ref factory));
     }
 }