/// <summary>
            /// Generate the body for MoveNext()
            /// </summary>
            internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
            {
                F.CurrentMethod = moveNextMethod;

                int initialState;
                GeneratedLabelSymbol initialLabel;

                AddState(out initialState, out initialLabel);

                var exceptionLocal = F.SynthesizedLocal(F.WellKnownType(WellKnownType.System_Exception), GeneratedNames.AsyncExceptionFieldName());

                BoundStatement rewrittenBody = (BoundStatement)Visit(body);

                rewrittenBody = (BoundStatement) new AwaitLoweringRewriterPass1(F).Visit(rewrittenBody);
                rewrittenBody = (BoundStatement) new AwaitLoweringRewriterPass2(F, CompilationState).Visit(rewrittenBody);

                UnloweredSpillNodeVerifier.Verify(rewrittenBody);

                var bodyBuilder = ArrayBuilder <BoundStatement> .GetInstance();

                bodyBuilder.Add(
                    F.Try(
                        F.Block(
                            ReadOnlyArray <LocalSymbol> .Empty,
                            // switch (state) ...
                            Dispatch(),
                            // TODO(t-liam) - debugging support...
                            // dev11(LanguageAnalysis\Compiler\ResumableRewriter.cpp:325) does codegen here to add a
                            // debug nop and the 'NoCullNormalExit' label
                            F.Label(initialLabel),
                            // [body]
                            rewrittenBody
                            ),
                        F.CatchBlocks(
                            // TODO(t-liam) - debugging support...
                            // dev11(LanguageAnalysis\Compiler\ResumableRewriter.cpp:391)
                            // // Async void method generated catch handlers have their IL start offset
                            // // recorded to the PDB for special exception handling in the debugger.
                            // // Mark the EXPRHANDLER as such so we know to record its offset later.
                            F.Catch(
                                F.WellKnownType(WellKnownType.System_Exception),
                                exceptionLocal,
                                F.Block(
                                    // state = finishedState
                                    F.Assignment(F.Field(F.This(), state), F.Literal(StateMachineStates.FinishedStateMachine)),
                                    // builder.SetException(ex)
                                    F.ExpressionStatement(
                                        F.Call(
                                            F.Field(F.This(), asyncMethodBuilderField),
                                            asyncMethodBuilderMemberCollection.SetException,
                                            ReadOnlyArray <BoundExpression> .CreateFrom(F.Local(exceptionLocal)))),
                                    F.Return()
                                    )
                                )
                            )
                        ));

                // ReturnLabel (for the rewritten return expressions in the user's method body)
                bodyBuilder.Add(F.Label(exprReturnLabel));

                // state = finishedState
                bodyBuilder.Add(F.Assignment(F.Field(F.This(), state), F.Literal(StateMachineStates.FinishedStateMachine)));

                // builder.SetResult([RetVal])
                bodyBuilder.Add(
                    F.ExpressionStatement(
                        F.Call(
                            F.Field(F.This(), asyncMethodBuilderField),
                            asyncMethodBuilderMemberCollection.SetResult,
                            method.IsGenericTaskReturningAsync()
                                ? ReadOnlyArray <BoundExpression> .CreateFrom(F.Local(exprRetValue))
                                : ReadOnlyArray <BoundExpression> .Empty)));

                bodyBuilder.Add(F.Return());

                var newBody = bodyBuilder.ToReadOnlyAndFree();

                F.CloseMethod(
                    F.SequencePoint(
                        body.Syntax,
                        F.Block(
                            exprRetValue != null ? ReadOnlyArray <LocalSymbol> .CreateFrom(exprRetValue) : ReadOnlyArray <LocalSymbol> .Empty,
                            newBody)));
            }
        public ScriptResult Execute(
            string code,
            string[] scriptArgs,
            AssemblyReferences references,
            IEnumerable <string> namespaces,
            ScriptPackSession scriptPackSession)
        {
            Guard.AgainstNullArgument("scriptPackSession", scriptPackSession);
            Guard.AgainstNullArgument("references", references);

            Logger.Debug("Starting to create execution components");
            Logger.Debug("Creating script host");

            var executionReferences = references.Union(scriptPackSession.References);

            SessionState <Session> sessionState;

            var isFirstExecution = !scriptPackSession.State.ContainsKey(SessionKey);

            if (isFirstExecution)
            {
                code = code.DefineTrace();
                var host = _scriptHostFactory.CreateScriptHost(
                    new ScriptPackManager(scriptPackSession.Contexts), scriptArgs);

                ScriptLibraryWrapper.SetHost(host);
                Logger.Debug("Creating session");

                var hostType = host.GetType();
                ScriptEngine.AddReference(hostType.Assembly);
                var session       = ScriptEngine.CreateSession(host, hostType);
                var allNamespaces = namespaces.Union(scriptPackSession.Namespaces).Distinct();

                foreach (var reference in executionReferences.Paths)
                {
                    Logger.DebugFormat("Adding reference to {0}", reference);
                    session.AddReference(reference);
                }

                foreach (var assembly in executionReferences.Assemblies)
                {
                    Logger.DebugFormat("Adding reference to {0}", assembly.FullName);
                    session.AddReference(assembly);
                }

                foreach (var @namespace in allNamespaces)
                {
                    Logger.DebugFormat("Importing namespace {0}", @namespace);
                    session.ImportNamespace(@namespace);
                }

                sessionState = new SessionState <Session>
                {
                    References = executionReferences,
                    Session    = session,
                    Namespaces = new HashSet <string>(allNamespaces)
                };

                scriptPackSession.State[SessionKey] = sessionState;
            }
            else
            {
                Logger.Debug("Reusing existing session");
                sessionState = (SessionState <Session>)scriptPackSession.State[SessionKey];

                if (sessionState.References == null)
                {
                    sessionState.References = new AssemblyReferences();
                }

                if (sessionState.Namespaces == null)
                {
                    sessionState.Namespaces = new HashSet <string>();
                }

                var newReferences = executionReferences.Except(sessionState.References);

                foreach (var reference in newReferences.Paths)
                {
                    Logger.DebugFormat("Adding reference to {0}", reference);
                    sessionState.Session.AddReference(reference);
                    sessionState.References = sessionState.References.Union(new[] { reference });
                }

                foreach (var assembly in newReferences.Assemblies)
                {
                    Logger.DebugFormat("Adding reference to {0}", assembly.FullName);
                    sessionState.Session.AddReference(assembly);
                    sessionState.References = sessionState.References.Union(new[] { assembly });
                }

                var newNamespaces = namespaces.Except(sessionState.Namespaces);

                foreach (var @namespace in newNamespaces)
                {
                    Logger.DebugFormat("Importing namespace {0}", @namespace);
                    sessionState.Session.ImportNamespace(@namespace);
                    sessionState.Namespaces.Add(@namespace);
                }
            }

            Logger.Debug("Starting execution");

            var result = Execute(code, sessionState.Session);

            if (result.InvalidNamespaces.Any())
            {
                var pendingNamespacesField = sessionState.Session.GetType().GetField(
                    "pendingNamespaces",
                    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

                if (pendingNamespacesField != null)
                {
                    var pendingNamespacesValue = (ReadOnlyArray <string>)pendingNamespacesField
                                                 .GetValue(sessionState.Session);

                    //no need to check this for null as ReadOnlyArray is a value type
                    if (pendingNamespacesValue.Any())
                    {
                        var fixedNamespaces = pendingNamespacesValue.ToList();

                        foreach (var @namespace in result.InvalidNamespaces)
                        {
                            sessionState.Namespaces.Remove(@namespace);
                            fixedNamespaces.Remove(@namespace);
                        }
                        pendingNamespacesField.SetValue(
                            sessionState.Session, ReadOnlyArray <string> .CreateFrom(fixedNamespaces));
                    }
                }
            }

            Logger.Debug("Finished execution");
            return(result);
        }
            private BoundExpression VisitAwaitExpression(BoundAwaitExpression node, bool resultsDiscarded)
            {
                var expression = (BoundExpression)Visit(node.Expression);

                MethodSymbol getAwaiter        = VisitMethodSymbol(node.GetAwaiter);
                MethodSymbol getResult         = VisitMethodSymbol(node.GetResult);
                MethodSymbol isCompletedMethod = (node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
                TypeSymbol   type = VisitType(node.Type);

                LocalSymbol awaiterTemp;

                if (getResult == null)
                {
                    awaiterTemp = F.SynthesizedLocal(DynamicTypeSymbol.Instance, name: null);
                }
                else if (type.IsDynamic())
                {
                    var awaiterType = ((NamedTypeSymbol)getAwaiter.ReturnType).OriginalNamedTypeDefinition.Construct(F.SpecialType(SpecialType.System_Object));
                    awaiterTemp       = F.SynthesizedLocal(awaiterType, null);
                    getResult         = ((MethodSymbol)getResult.OriginalDefinition).AsMember(awaiterType);
                    isCompletedMethod = ((MethodSymbol)isCompletedMethod.OriginalDefinition).AsMember(awaiterType);
                }
                else
                {
                    awaiterTemp = F.SynthesizedLocal(getAwaiter.ReturnType, name: null);
                }

                var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, "GetAwaiter")),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

                BoundExpression getResultCall = MakeCallMaybeDynamic(
                    F.Local(awaiterTemp),
                    getResult,
                    "GetResult",
                    resultsDiscarded: resultsDiscarded);

                var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));

                BoundExpression onAwaitFinished;

                if (!resultsDiscarded && type.SpecialType != SpecialType.System_Void)
                {
                    // $resultTemp = $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    // $resultTemp
                    LocalSymbol resultTemp = F.SynthesizedLocal(type, null);
                    onAwaitFinished = F.Sequence(
                        resultTemp,
                        F.AssignmentExpression(F.Local(resultTemp), getResultCall),
                        nullAwaiter,
                        F.Local(resultTemp));
                }
                else
                {
                    // $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    onAwaitFinished = F.Sequence(
                        ReadOnlyArray <LocalSymbol> .Empty,
                        getResultCall,
                        nullAwaiter);
                }

                return(F.SpillSequence(
                           ReadOnlyArray <LocalSymbol> .CreateFrom(awaiterTemp),
                           ReadOnlyArray <BoundSpillTemp> .Empty,
                           ReadOnlyArray <FieldSymbol> .Empty,
                           ReadOnlyArray <BoundStatement> .CreateFrom(awaitIfIncomplete),
                           onAwaitFinished));
            }
            private BoundStatement GenerateAwaitOnCompletedDynamic(LocalSymbol awaiterTemp)
            {
                //  temp $criticalNotifyCompletedTemp = $awaiterTemp as ICriticalNotifyCompletion
                //  if (
                //      $criticalNotifyCompletedTemp != null
                //     ) {
                //    this.builder.AwaitUnsafeOnCompleted<
                //         ICriticalNotifyCompletion,TSM>(ref $criticalNotifyCompletedTemp, ref this)
                //  } else {
                //    temp $notifyCompletionTemp = (INotifyCompletion)$awaiterTemp
                //       this.builder.AwaitOnCompleted<INotifyCompletion,TSM>(
                //         ref $notifyCompletionTemp, ref this)
                //       free $notifyCompletionTemp
                //  }
                //  free $criticalNotifyCompletedTemp

                var criticalNotifyCompletedTemp = F.SynthesizedLocal(
                    F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion),
                    null);

                var notifyCompletionTemp = F.SynthesizedLocal(
                    F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion),
                    null);

                return(F.Block(
                           ReadOnlyArray <LocalSymbol> .CreateFrom(criticalNotifyCompletedTemp),

                           F.Assignment(
                               F.Local(criticalNotifyCompletedTemp),
                               F.As(F.Local(awaiterTemp), criticalNotifyCompletedTemp.Type)),

                           F.If(
                               condition: F.ObjectEqual(F.Local(criticalNotifyCompletedTemp), F.Null(criticalNotifyCompletedTemp.Type)),

                               thenClause: F.Block(
                                   ReadOnlyArray <LocalSymbol> .CreateFrom(notifyCompletionTemp),
                                   F.Assignment(
                                       F.Local(notifyCompletionTemp),
                                       F.Convert(notifyCompletionTemp.Type, F.Local(awaiterTemp))),
                                   F.ExpressionStatement(
                                       F.Call(
                                           F.Field(F.This(), asyncMethodBuilderField),
                                           asyncMethodBuilderMemberCollection.AwaitOnCompleted.Construct(
                                               notifyCompletionTemp.Type,
                                               F.This().Type),
                                           new BoundExpression[] { F.Local(notifyCompletionTemp), F.This() })),
                                   F.Assignment(
                                       F.Local(notifyCompletionTemp),
                                       F.NullOrDefault(notifyCompletionTemp.Type))),

                               elseClause: F.Block(
                                   F.ExpressionStatement(
                                       F.Call(
                                           F.Field(F.This(), asyncMethodBuilderField),
                                           asyncMethodBuilderMemberCollection.AwaitUnsafeOnCompleted.Construct(
                                               criticalNotifyCompletedTemp.Type,
                                               F.This().Type),
                                           new BoundExpression[] { F.Local(criticalNotifyCompletedTemp), F.This() })))),

                           F.Assignment(
                               F.Local(criticalNotifyCompletedTemp),
                               F.NullOrDefault(criticalNotifyCompletedTemp.Type))));
            }
Beispiel #5
0
 protected override ReadOnlyArray <ParameterSymbol> MakeParameters(Binder binder, DelegateDeclarationSyntax syntax, DiagnosticBag diagnostics)
 {
     return(ReadOnlyArray <ParameterSymbol> .CreateFrom(
                new SynthesizedParameterSymbol(this, binder.GetSpecialType(SpecialType.System_Object, diagnostics, syntax), 0, RefKind.None, "object"),
                new SynthesizedParameterSymbol(this, binder.GetSpecialType(SpecialType.System_IntPtr, diagnostics, syntax), 1, RefKind.None, "method")));
 }
 internal AnonymousTypeSpecializedPropertySymbol(SubstitutedNamedTypeSymbol containingType, PropertySymbol originalDefinition, AnonymousTypeField field)
     : base(containingType, originalDefinition)
 {
     this.locations = ReadOnlyArray <Location> .CreateFrom(field.Location);
 }
Beispiel #7
0
 public override ReadOnlyArray <Symbol> GetMembers()
 {
     return(ReadOnlyArray <Symbol> .CreateFrom(this.ctorMethod));
 }
Beispiel #8
0
 public override ReadOnlyArray <Symbol> GetMembers(string name)
 {
     return(CommonMemberNames.InstanceConstructorName.Equals(name)
             ? ReadOnlyArray <Symbol> .CreateFrom(this.ctorMethod)
             : ReadOnlyArray <Symbol> .Empty);
 }
Beispiel #9
0
        static CommonScriptEngine()
        {
            DefaultReferenceSearchPaths = ReadOnlyArray <string> .CreateFrom(RuntimeEnvironment.GetRuntimeDirectory());

            globalAssemblyNamePrefix = "\u211B*" + Guid.NewGuid().ToString() + "-";
        }
Beispiel #10
0
 /// <summary>
 /// Returns a list of imported namespaces.
 /// </summary>
 public ReadOnlyArray <string> GetImportedNamespaces()
 {
     return(ReadOnlyArray <string> .CreateFrom(importedNamespaces));
 }
Beispiel #11
0
 /// <summary>
 /// Returns a list of assemblies that are currently referenced by the engine.
 /// </summary>
 public ReadOnlyArray <MetadataReference> GetReferences()
 {
     return(ReadOnlyArray <MetadataReference> .CreateFrom(references));
 }
Beispiel #12
0
 public void SetReferenceSearchPaths(IEnumerable <string> paths)
 {
     SetReferenceSearchPaths(ReadOnlyArray <string> .CreateFrom(paths));
 }
Beispiel #13
0
        /// <summary>
        /// The rewrites are as follows:
        ///
        /// x++
        ///     temp = x
        ///     x = temp + 1
        ///     return temp
        /// x--
        ///     temp = x
        ///     x = temp - 1
        ///     return temp
        /// ++x
        ///     temp = x + 1
        ///     x = temp
        ///     return temp
        /// --x
        ///     temp = x - 1
        ///     x = temp
        ///     return temp
        ///
        /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that
        /// will be used.  The temp is of the same type as x, but the sum/difference may be wider, in which case a
        /// conversion is required.
        /// </summary>
        /// <param name="node">The unary operator expression representing the increment/decrement.</param>
        /// <param name="isPrefix">True for prefix, false for postfix.</param>
        /// <param name="isIncrement">True for increment, false for decrement.</param>
        /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns>
        private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement)
        {
            BoundExpression operand     = node.Operand;
            TypeSymbol      operandType = operand.Type; //type of the variable being incremented

            Debug.Assert(operandType == node.Type);

            ConstantValue      constantOne;
            BinaryOperatorKind binaryOperatorKind;

            MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind);
            binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;

            Debug.Assert(constantOne != null);
            Debug.Assert(constantOne.SpecialType != SpecialType.None);
            Debug.Assert(binaryOperatorKind.OperandTypes() != 0);

            TypeSymbol      constantType = compilation.GetSpecialType(constantOne.SpecialType);
            BoundExpression boundOne     = new BoundLiteral(
                syntax: null,
                syntaxTree: null,
                constantValueOpt: constantOne,
                type: constantType);

            LocalSymbol     tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol);
            BoundExpression boundTemp  = new BoundLocal(
                syntax: null,
                syntaxTree: null,
                localSymbol: tempSymbol,
                constantValueOpt: null,
                type: operandType);

            // NOTE: the LHS may have a narrower type than the operator expects, but that
            // doesn't seem to cause any problems.  If a problem does arise, just add an
            // explicit BoundConversion.
            BoundExpression newValue = new BoundBinaryOperator(
                syntax: null,
                syntaxTree: null,
                operatorKind: binaryOperatorKind,
                left: isPrefix ? operand : boundTemp,
                right: boundOne,
                constantValueOpt: null,
                type: constantType);

            if (constantType != operandType)
            {
                newValue = new BoundConversion(
                    syntax: null,
                    syntaxTree: null,
                    operand: newValue,
                    conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric,
                    symbolOpt: null,
                    @checked: false,
                    explicitCastInCode: false,
                    constantValueOpt: null,
                    type: operandType);
            }

            ReadOnlyArray <BoundExpression> assignments = ReadOnlyArray <BoundExpression> .CreateFrom(
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : boundTemp,
                    right : isPrefix ? newValue : operand,
                    type : operandType),
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : operand,
                    right : isPrefix ? boundTemp : newValue,
                    type : operandType));

            return(new BoundSequence(
                       syntax: node.Syntax,
                       syntaxTree: node.SyntaxTree,
                       locals: ReadOnlyArray <LocalSymbol> .CreateFrom(tempSymbol),
                       sideEffects: assignments,
                       value: boundTemp,
                       type: operandType));
        }