Skip to content
← Back

src/ir/values/async_method_launch.ghul

1
namespace IR.Values is
2
use TypeTyped = Semantic.Types.Typed;
3
use Semantic.Types.Type;
4
5
// Outer-method body of an async function. Newobjs the state
6
// machine with the user's args (instance methods prefix
7
// `ldarg.0` for $outer_self), creates+stashes the builder,
8
// calls `builder.Start(ref this)`, and leaves the Task on the
9
// stack. Caller emits `ret`.
10
//
11
// Stack effect: 0 → 1.
12
class ASYNC_METHOD_LAUNCH: Value, TypeTyped is
13
type: Type;
14
15
state_machine_type: Type;
16
ctor_reference: string;
17
ctor_arg_loads: Value;
18
state_field: Semantic.Symbols.Field;
19
builder_field: Semantic.Symbols.Field;
20
21
// Open-generic `AsyncTaskMethodBuilder`1<!0>` / `Task`1<!0>`.
22
// Needed in `Create()` / `get_Task()` methodref signatures —
23
// calls on a constructed generic value-type need OPEN class-T
24
// in the signature, or the JIT raises MissingMethodException.
25
// Null for void-async, where the builder type is non-generic
26
// and the methodref signatures carry no class-T.
27
unspecialized_builder_type: Type?;
28
unspecialized_task_type: Type?;
29
30
sm_local_name: string;
31
32
init(
33
type: Type,
34
state_machine_type: Type,
35
ctor_reference: string,
36
ctor_arg_loads: Value,
37
state_field: Semantic.Symbols.Field,
38
builder_field: Semantic.Symbols.Field,
39
unspecialized_builder_type: Type?,
40
unspecialized_task_type: Type?,
41
sm_local_name: string
42
) is
43
super.init();
44
45
self.type = type;
46
self.state_machine_type = state_machine_type;
47
self.ctor_reference = ctor_reference;
48
self.ctor_arg_loads = ctor_arg_loads;
49
self.state_field = state_field;
50
self.builder_field = builder_field;
51
self.unspecialized_builder_type = unspecialized_builder_type;
52
self.unspecialized_task_type = unspecialized_task_type;
53
self.sm_local_name = sm_local_name;
54
si
55
56
gen(context: IR.CONTEXT) is
57
let sm_il = state_machine_type.get_il_type();
58
let builder_il = builder_field.type!.get_il_type();
59
let builder_ref = builder_field.get_il_reference();
60
let state_ref = state_field.get_il_reference();
61
62
// Open-class-T forms for the methodref signature slots.
63
// The runtime needs `!0` (class-T of the owner) in the
64
// method signature — substituting the constructed T
65
// there makes the method-lookup fail with
66
// MissingMethodException.
67
let open_builder_il =
68
if let self.unspecialized_builder_type? then
69
unspecialized_builder_type.get_il_type();
70
else
71
builder_il;
72
fi;
73
74
let open_task_il =
75
if let self.unspecialized_task_type? then
76
unspecialized_task_type.get_il_type();
77
else
78
type.get_il_type();
79
fi;
80
81
context.write_line(".locals init ({sm_il} {sm_local_name})");
82
83
// newobj <ctor> — ctor args already on stack via
84
// ctor_arg_loads (a Value whose gen() emits the
85
// appropriate ldargs).
86
gen(ctor_arg_loads, context);
87
context.write_line("newobj {ctor_reference}");
88
context.write_line("stloc {sm_local_name}");
89
90
// Initial state = -1.
91
context.write_line("ldloc {sm_local_name}");
92
context.write_line("ldc.i4.m1");
93
context.write_line("stfld {state_ref}");
94
95
// _builder = AsyncTaskMethodBuilder<T>.Create().
96
context.write_line("ldloc {sm_local_name}");
97
context.write_line("call {open_builder_il} {builder_il}::'Create'()");
98
context.write_line("stfld {builder_ref}");
99
100
// _builder.Start(ref sm).
101
context.write_line("ldloc {sm_local_name}");
102
context.write_line("ldflda {builder_ref}");
103
context.write_line("ldloca {sm_local_name}");
104
context.write_line(
105
"call instance void {builder_il}::'Start'<{sm_il}>(!!0&)"
106
);
107
108
// return _builder.Task.
109
context.write_line("ldloc {sm_local_name}");
110
context.write_line("ldflda {builder_ref}");
111
112
context.write_line(
113
"call instance {open_task_il} {builder_il}::'get_Task'()"
114
);
115
si
116
117
to_string() -> string =>
118
"async-method-launch:[{type}]({state_machine_type})";
119
si
120
si