Appearance
| 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 |