Skip to content

Commit

Permalink
more fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
bfarmer67 committed Sep 3, 2024
1 parent f4c1335 commit 14eb49a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 48 deletions.
11 changes: 3 additions & 8 deletions src/Hyperbee.AsyncExpressions/AsyncBlockExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,9 @@ private static BlockExpression ReduceBlock( Expression[] expressions, out Type f
var lastExpr = currentBlockExpressions.Last();
if ( IsTask( lastExpr.Type ) )
{
if ( lastExpr.Type.IsGenericType )
{
finalResultType = lastExpr.Type.GetGenericArguments()[0];
}
else
{
finalResultType = typeof(void); // Task without a result
}
finalResultType = lastExpr.Type.IsGenericType
? lastExpr.Type.GetGenericArguments()[0]
: typeof(void); // Task without a result
}
}

Expand Down
90 changes: 50 additions & 40 deletions src/Hyperbee.AsyncExpressions/StateMachineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ public StateMachineBuilder( ModuleBuilder moduleBuilder, string typeName )

public void GenerateMoveNextMethod( BlockExpression reducedBlock )
{
// Define a parameter expression to represent 'this' within the state machine
var stateMachineInstance = Expression.Parameter( _typeBuilder.AsType(), "stateMachine" );

// Use variables from reducedBlock
var variables = reducedBlock.Variables;

// Define a parameter to represent the instance of the state machine class
var stateMachineInstance = Expression.Parameter( _typeBuilder, "stateMachine" );

var bodyExpressions = new List<Expression>
{
// Initialize the builder field
Expression.Assign( Expression.Field( stateMachineInstance, _builderField ),
Expression.Call( typeof(AsyncTaskMethodBuilder<TResult>), nameof(AsyncTaskMethodBuilder<TResult>.Create), null ) )
};
Expand All @@ -57,55 +58,64 @@ public void GenerateMoveNextMethod( BlockExpression reducedBlock )
for ( var i = 0; i < blocks.Count; i++ )
{
var blockExpr = blocks[i];

var configuredTaskAwaitableType = typeof(ConfiguredTaskAwaitable<>).MakeGenericType( typeof(TResult) );
var configuredTaskAwaiterType = configuredTaskAwaitableType.GetNestedType( "ConfiguredTaskAwaiter" );

var awaiterField = _typeBuilder.DefineField( $"_awaiter_{i}", configuredTaskAwaiterType!, FieldAttributes.Private );

var stateCheck = Expression.Equal( Expression.Field( stateMachineInstance, _stateField ), Expression.Constant( i ) );
var assignAwaiter = Expression.Assign(
Expression.Field( stateMachineInstance, awaiterField ),
Expression.Call(
Expression.Call( blockExpr, nameof(Task.ConfigureAwait), null, Expression.Constant( false ) ),
nameof(ConfiguredTaskAwaitable<TResult>.GetAwaiter), null )
);

var stateMachineProxy = Expression.New( typeof(StateMachineProxy).GetConstructor( new[] { typeof(IAsyncStateMachine) } )!, stateMachineInstance );
var assignProxy = Expression.Assign( Expression.Field( stateMachineInstance, _proxyField ), stateMachineProxy );

var setupContinuation = Expression.Call(
Expression.Field( stateMachineInstance, _builderField ),
nameof(AsyncTaskMethodBuilder<TResult>.AwaitUnsafeOnCompleted),
new Type[] { configuredTaskAwaiterType, typeof(IAsyncStateMachine) },
Expression.Field( stateMachineInstance, awaiterField ),
Expression.Field( stateMachineInstance, _proxyField )
);

var moveToNextState = Expression.Assign( Expression.Field( stateMachineInstance, _stateField ), Expression.Constant( i + 1 ) );

var ifNotCompleted = Expression.IfThenElse(
Expression.IsFalse( Expression.Property( Expression.Field( stateMachineInstance, awaiterField ), nameof(TaskAwaiter.IsCompleted) ) ),
Expression.Block( assignAwaiter, assignProxy, setupContinuation, Expression.Return( Expression.Label( typeof(void) ) ) ),
Expression.Block( assignAwaiter, moveToNextState )
);

bodyExpressions.Add( Expression.IfThen( stateCheck, ifNotCompleted ) );
var blockReturnType = blockExpr.Type;

if ( AsyncBaseExpression.IsTask( blockReturnType ) )
{
var awaiterType = blockReturnType.IsGenericType
? typeof(ConfiguredTaskAwaitable<>).MakeGenericType( blockReturnType.GetGenericArguments()[0] )
: typeof(ConfiguredTaskAwaitable);

var awaiterField = _typeBuilder.DefineField( $"_awaiter_{i}", awaiterType.GetNestedType( "ConfiguredTaskAwaiter" )!, FieldAttributes.Private );

// Assigning awaiter logic
var assignAwaiter = Expression.Assign(
Expression.Field( stateMachineInstance, awaiterField ),
Expression.Call(
Expression.Call( blockExpr, nameof(Task.ConfigureAwait), null, Expression.Constant( false ) ),
awaiterType.GetMethod( "GetAwaiter" )! ) );

// Generate proxy and continuation setup
var stateMachineProxy = Expression.New( typeof(StateMachineProxy).GetConstructor( [typeof(IAsyncStateMachine)] )!, stateMachineInstance );
var assignProxy = Expression.Assign( Expression.Field( stateMachineInstance, _proxyField ), stateMachineProxy );

var setupContinuation = Expression.Call(
Expression.Field( stateMachineInstance, _builderField ),
nameof(AsyncTaskMethodBuilder<TResult>.AwaitUnsafeOnCompleted),
[awaiterType.GetNestedType( "ConfiguredTaskAwaiter" ), typeof(IAsyncStateMachine)],
Expression.Field( stateMachineInstance, awaiterField ),
Expression.Field( stateMachineInstance, _proxyField ) );

var moveToNextState = Expression.Assign( Expression.Field( stateMachineInstance, _stateField ), Expression.Constant( i + 1 ) );

// Check if task is not completed
var ifNotCompleted = Expression.IfThenElse(
Expression.IsFalse( Expression.Property( Expression.Field( stateMachineInstance, awaiterField ), nameof(TaskAwaiter.IsCompleted) ) ),
Expression.Block( assignAwaiter, assignProxy, setupContinuation, Expression.Return( Expression.Label( typeof(void) ) ) ),
Expression.Block( assignAwaiter, moveToNextState ) );

bodyExpressions.Add( Expression.IfThen( Expression.Equal( Expression.Field( stateMachineInstance, _stateField ), Expression.Constant( i ) ), ifNotCompleted ) );
}
else
{
// Handle non-awaitable final block
var assignFinalResult = Expression.Assign( Expression.Field( stateMachineInstance, _finalResultField ), blockExpr );
bodyExpressions.Add( assignFinalResult );
}
}

var setResult = Expression.Call(
Expression.Field( stateMachineInstance, _builderField ),
nameof(AsyncTaskMethodBuilder<TResult>.SetResult),
null,
Expression.Field( stateMachineInstance, _finalResultField )
);
Expression.Field( stateMachineInstance, _finalResultField ) );

bodyExpressions.Add( setResult );

// Include the variables in the block
var stateMachineBody = Expression.Block( variables, bodyExpressions );

// Emit the state machine body to the MoveNext method
// Compile to a method using Emit, replacing CompileToMethod
EmitCompileToMethod( stateMachineBody, _moveNextMethod );
}

Expand Down

0 comments on commit 14eb49a

Please sign in to comment.