@@ -318,6 +318,8 @@ internal static class CachedReflectionInfo
318318 typeof ( PipelineOps ) . GetMethod ( nameof ( PipelineOps . FlushPipe ) , staticFlags ) ;
319319 internal static readonly MethodInfo PipelineOps_InvokePipeline =
320320 typeof ( PipelineOps ) . GetMethod ( nameof ( PipelineOps . InvokePipeline ) , staticFlags ) ;
321+ internal static readonly MethodInfo PipelineOps_InvokePipelineInBackground =
322+ typeof ( PipelineOps ) . GetMethod ( nameof ( PipelineOps . InvokePipelineInBackground ) , staticFlags ) ;
321323 internal static readonly MethodInfo PipelineOps_Nop =
322324 typeof ( PipelineOps ) . GetMethod ( nameof ( PipelineOps . Nop ) , staticFlags ) ;
323325 internal static readonly MethodInfo PipelineOps_PipelineResult =
@@ -1942,7 +1944,8 @@ private Expression CaptureStatementResultsHelper(
19421944 }
19431945
19441946 var pipelineAst = stmt as PipelineAst ;
1945- if ( pipelineAst != null )
1947+ // If it's a pipeline that isn't being backgrounded, try to optimize expression
1948+ if ( pipelineAst != null && ! pipelineAst . Background )
19461949 {
19471950 var expr = pipelineAst . GetPureExpression ( ) ;
19481951 if ( expr != null ) { return Compile ( expr ) ; }
@@ -2983,104 +2986,115 @@ public object VisitPipeline(PipelineAst pipelineAst)
29832986 exprs . Add ( UpdatePosition ( pipelineAst ) ) ;
29842987 }
29852988
2986- var pipeElements = pipelineAst . PipelineElements ;
2987- var firstCommandExpr = ( pipeElements [ 0 ] as CommandExpressionAst ) ;
2988- if ( firstCommandExpr != null && pipeElements . Count == 1 )
2989+ if ( pipelineAst . Background )
29892990 {
2990- if ( firstCommandExpr . Redirections . Count > 0 )
2991- {
2992- exprs . Add ( GetRedirectedExpression ( firstCommandExpr , captureForInput : false ) ) ;
2993- }
2994- else
2995- {
2996- exprs . Add ( Compile ( firstCommandExpr ) ) ;
2997- }
2991+ Expression invokeBackgroundPipe = Expression . Call (
2992+ CachedReflectionInfo . PipelineOps_InvokePipelineInBackground ,
2993+ Expression . Constant ( pipelineAst ) ,
2994+ _functionContext ) ;
2995+ exprs . Add ( invokeBackgroundPipe ) ;
29982996 }
29992997 else
30002998 {
3001- Expression input ;
3002- int i , commandsInPipe ;
3003-
3004- if ( firstCommandExpr != null )
2999+ var pipeElements = pipelineAst . PipelineElements ;
3000+ var firstCommandExpr = ( pipeElements [ 0 ] as CommandExpressionAst ) ;
3001+
3002+ if ( firstCommandExpr != null && pipeElements . Count == 1 )
30053003 {
30063004 if ( firstCommandExpr . Redirections . Count > 0 )
30073005 {
3008- input = GetRedirectedExpression ( firstCommandExpr , captureForInput : true ) ;
3006+ exprs . Add ( GetRedirectedExpression ( firstCommandExpr , captureForInput : false ) ) ;
30093007 }
30103008 else
30113009 {
3012- input = GetRangeEnumerator ( firstCommandExpr . Expression ) ??
3013- Compile ( firstCommandExpr . Expression ) ;
3010+ exprs . Add ( Compile ( firstCommandExpr ) ) ;
30143011 }
3015- i = 1 ;
3016- commandsInPipe = pipeElements . Count - 1 ;
30173012 }
30183013 else
30193014 {
3020- // Compiled code normally never sees AutomationNull. We use that value
3021- // here so that we can tell the difference b/w $null and no input when
3022- // starting the pipeline, in other words, PipelineOps.InvokePipe will
3023- // not pass this value to the pipe.
3024-
3025- input = ExpressionCache . AutomationNullConstant ;
3026- i = 0 ;
3027- commandsInPipe = pipeElements . Count ;
3028- }
3029- Expression [ ] pipelineExprs = new Expression [ commandsInPipe ] ;
3030- CommandBaseAst [ ] pipeElementAsts = new CommandBaseAst [ commandsInPipe ] ;
3031- var commandRedirections = new object [ commandsInPipe ] ;
3032-
3033- for ( int j = 0 ; i < pipeElements . Count ; ++ i , ++ j )
3034- {
3035- var pipeElement = pipeElements [ i ] ;
3036- pipelineExprs [ j ] = Compile ( pipeElement ) ;
3037-
3038- commandRedirections [ j ] = GetCommandRedirections ( pipeElement ) ;
3039- pipeElementAsts [ j ] = pipeElement ;
3040- }
3041-
3042- // The redirections are passed as a CommandRedirection[][] - one dimension for each command in the pipe,
3043- // one dimension because each command may have multiple redirections. Here we create the array for
3044- // each command in the pipe, either a compile time constant or created at runtime if necessary.
3045- Expression redirectionExpr ;
3046- if ( commandRedirections . Any ( r => r is Expression ) )
3047- {
3048- // If any command redirections are non-constant, commandRedirections will have a Linq.Expression in it,
3049- // in which case we must create the array at runtime
3050- redirectionExpr =
3051- Expression . NewArrayInit ( typeof ( CommandRedirection [ ] ) ,
3052- commandRedirections . Select ( r => ( r as Expression ) ?? Expression . Constant ( r , typeof ( CommandRedirection [ ] ) ) ) ) ;
3053- }
3054- else if ( commandRedirections . Any ( r => r != null ) )
3055- {
3056- // There were redirections, but all were compile time constant, so build the array at compile time.
3057- redirectionExpr =
3058- Expression . Constant ( commandRedirections . Map ( r => r as CommandRedirection [ ] ) ) ;
3059- }
3060- else
3061- {
3062- // No redirections.
3063- redirectionExpr = ExpressionCache . NullCommandRedirections ;
3064- }
3065-
3066- if ( firstCommandExpr != null )
3067- {
3068- var inputTemp = Expression . Variable ( input . Type ) ;
3069- temps . Add ( inputTemp ) ;
3070- exprs . Add ( Expression . Assign ( inputTemp , input ) ) ;
3071- input = inputTemp ;
3015+ Expression input ;
3016+ int i , commandsInPipe ;
3017+
3018+ if ( firstCommandExpr != null )
3019+ {
3020+ if ( firstCommandExpr . Redirections . Count > 0 )
3021+ {
3022+ input = GetRedirectedExpression ( firstCommandExpr , captureForInput : true ) ;
3023+ }
3024+ else
3025+ {
3026+ input = GetRangeEnumerator ( firstCommandExpr . Expression ) ??
3027+ Compile ( firstCommandExpr . Expression ) ;
3028+ }
3029+ i = 1 ;
3030+ commandsInPipe = pipeElements . Count - 1 ;
3031+ }
3032+ else
3033+ {
3034+ // Compiled code normally never sees AutomationNull. We use that value
3035+ // here so that we can tell the difference b/w $null and no input when
3036+ // starting the pipeline, in other words, PipelineOps.InvokePipe will
3037+ // not pass this value to the pipe.
3038+
3039+ input = ExpressionCache . AutomationNullConstant ;
3040+ i = 0 ;
3041+ commandsInPipe = pipeElements . Count ;
3042+ }
3043+ Expression [ ] pipelineExprs = new Expression [ commandsInPipe ] ;
3044+ CommandBaseAst [ ] pipeElementAsts = new CommandBaseAst [ commandsInPipe ] ;
3045+ var commandRedirections = new object [ commandsInPipe ] ;
3046+
3047+ for ( int j = 0 ; i < pipeElements . Count ; ++ i , ++ j )
3048+ {
3049+ var pipeElement = pipeElements [ i ] ;
3050+ pipelineExprs [ j ] = Compile ( pipeElement ) ;
3051+
3052+ commandRedirections [ j ] = GetCommandRedirections ( pipeElement ) ;
3053+ pipeElementAsts [ j ] = pipeElement ;
3054+ }
3055+
3056+ // The redirections are passed as a CommandRedirection[][] - one dimension for each command in the pipe,
3057+ // one dimension because each command may have multiple redirections. Here we create the array for
3058+ // each command in the pipe, either a compile time constant or created at runtime if necessary.
3059+ Expression redirectionExpr ;
3060+ if ( commandRedirections . Any ( r => r is Expression ) )
3061+ {
3062+ // If any command redirections are non-constant, commandRedirections will have a Linq.Expression in it,
3063+ // in which case we must create the array at runtime
3064+ redirectionExpr =
3065+ Expression . NewArrayInit ( typeof ( CommandRedirection [ ] ) ,
3066+ commandRedirections . Select ( r => ( r as Expression ) ?? Expression . Constant ( r , typeof ( CommandRedirection [ ] ) ) ) ) ;
3067+ }
3068+ else if ( commandRedirections . Any ( r => r != null ) )
3069+ {
3070+ // There were redirections, but all were compile time constant, so build the array at compile time.
3071+ redirectionExpr =
3072+ Expression . Constant ( commandRedirections . Map ( r => r as CommandRedirection [ ] ) ) ;
3073+ }
3074+ else
3075+ {
3076+ // No redirections.
3077+ redirectionExpr = ExpressionCache . NullCommandRedirections ;
3078+ }
3079+
3080+ if ( firstCommandExpr != null )
3081+ {
3082+ var inputTemp = Expression . Variable ( input . Type ) ;
3083+ temps . Add ( inputTemp ) ;
3084+ exprs . Add ( Expression . Assign ( inputTemp , input ) ) ;
3085+ input = inputTemp ;
3086+ }
3087+
3088+ Expression invokePipe = Expression . Call (
3089+ CachedReflectionInfo . PipelineOps_InvokePipeline ,
3090+ input . Cast ( typeof ( object ) ) ,
3091+ firstCommandExpr != null ? ExpressionCache . FalseConstant : ExpressionCache . TrueConstant ,
3092+ Expression . NewArrayInit ( typeof ( CommandParameterInternal [ ] ) , pipelineExprs ) ,
3093+ Expression . Constant ( pipeElementAsts ) ,
3094+ redirectionExpr ,
3095+ _functionContext ) ;
3096+ exprs . Add ( invokePipe ) ;
30723097 }
3073-
3074- Expression invokePipe = Expression . Call (
3075- CachedReflectionInfo . PipelineOps_InvokePipeline ,
3076- input . Cast ( typeof ( object ) ) ,
3077- firstCommandExpr != null ? ExpressionCache . FalseConstant : ExpressionCache . TrueConstant ,
3078- Expression . NewArrayInit ( typeof ( CommandParameterInternal [ ] ) , pipelineExprs ) ,
3079- Expression . Constant ( pipeElementAsts ) ,
3080- redirectionExpr ,
3081- _functionContext ) ;
3082-
3083- exprs . Add ( invokePipe ) ;
30843098 }
30853099
30863100 return Expression . Block ( temps , exprs ) ;
0 commit comments