Skip to content
← Back

src/ir/emitter/srm_structure_walk.ghul

1
namespace IR.Emitter is
2
use System.Reflection.Metadata.EntityHandle
3
use System.Reflection.Metadata.TypeDefinitionHandle
4
use System.Reflection.Metadata.Ecma335.MetadataTokens
5
6
use Semantic.Symbols.Scope
7
use Semantic.Symbols.Classy
8
use Semantic.Symbols.Function
9
use Semantic.Symbols.Field
10
11
// A method this assembly defines together with the interface member
12
// it explicitly implements, held until the owning type has a handle
13
// for the MethodImpl row to name.
14
class SRM_BOUND_METHOD(body: EntityHandle, declaration: EntityHandle)
15
16
// One attribute the compiler applies to a return or parameter slot,
17
// held until the caller knows whether the slot has a Param row.
18
class SRM_SLOT_ATTRIBUTE(
19
assembly_name: string,
20
qualified_name: string,
21
argument_types: Collections.List[Semantic.Types.Type],
22
value: ubyte[]
23
)
24
25
// One trait a type declares, held until its `InterfaceImpl` row
26
// exists to carry the interface's own nullability.
27
class SRM_INTERFACE_ANCESTOR(handle: EntityHandle, ancestor_type: Semantic.Types.Type)
28
29
// One type parameter, held until every row it could be ordered
30
// against exists.
31
//
32
// GenericParam is sorted on its owner, and an owner is a coded index
33
// over TypeDef *and* MethodDef, so the two row kinds interleave by
34
// row number. A type's parameters therefore cannot be written as the
35
// walk reaches the type: a later type's row can sort ahead of an
36
// earlier type's method. Unlike the other sorted side tables, SRM
37
// validates this one rather than ordering it, and rejects the
38
// assembly outright.
39
class SRM_TYPE_PARAMETER(
40
owner: EntityHandle,
41
index: int,
42
name: string,
43
attributes: System.Reflection.GenericParameterAttributes,
44
// The types this parameter is bounded by, empty when unbounded.
45
// Held rather than resolved to handles here: each constraint row
46
// has to follow its parameter's row, and the parameters are not
47
// in that order until they are sorted.
48
bounds: Collections.List[Semantic.Types.Type],
49
// The closure whose mapping the bounds have to be encoded under,
50
// for a parameter belonging to a closure frame. See
51
// SRM_SIGNATURE_ENCODER.frame_mapping - a bound naming the
52
// parameter itself encodes at the parameter's method-level
53
// position otherwise, which on a frame class names a method
54
// that is not there.
55
mapping: Semantic.Symbols.Closure?
56
) is
57
// The coded index the table is sorted on: the owner's row,
58
// tagged with which table it points into.
59
order: int =>
60
MetadataTokens.get_row_number(owner) * 2 +
61
if owner.kind == System.Reflection.Metadata.HandleKind.METHOD_DEFINITION then 1 else 0 fi
62
si
63
64
// Derives the emitted assembly's structure from the symbol table, in
65
// two passes over the same sequence.
66
//
67
// `number` runs before any body is encoded and assigns every type,
68
// method and field its metadata row, so a body can embed a token for
69
// a target whose row does not exist yet. `write_rows` runs after the
70
// tree walk and writes those rows, in the order `number` assumed.
71
// Between the two, the tree walk deposits body offsets against
72
// function symbols.
73
//
74
// A row number is only a prediction until `write_rows` makes it
75
// true, and nothing checks: a member run written in a different
76
// order — or at a different length — than it was numbered reparents
77
// members onto the wrong type and still loads. `number` therefore
78
// records the sequence it used and `write_rows` replays it, rather
79
// than each deriving one from a symbol table that changes between
80
// them: compiling a state machine's body declares the frame fields
81
// that body needs, long after numbering has run.
82
class SRM_STRUCTURE_WALK(_assembly: SRM_ASSEMBLY_EMITTER) is
83
_handles: SRM_HANDLES => _assembly.handles
84
_signatures: SRM_SIGNATURE_ENCODER
85
_blobs: SRM_ATTRIBUTE_BLOB_ENCODER
86
_type_parameters: Collections.LIST[SRM_TYPE_PARAMETER]
87
// The frame's own GetEnumerator and get_Current, recorded as
88
// they are written so the legacy bridges below can call them:
89
// a frame's members are synthesised straight into metadata, so
90
// there is no symbol for the bridge to resolve.
91
_frame_enumerator_members: Collections.MAP[FrameMember, EntityHandle]
92
_frame_element_type: Semantic.Types.Type?
93
94
_pending_overrides: Collections.LIST[SRM_BOUND_METHOD]
95
96
init(..) is
97
_signatures = SRM_SIGNATURE_ENCODER(_assembly)
98
_blobs =
99
SRM_ATTRIBUTE_BLOB_ENCODER(IoC.CONTAINER.instance.innate_symbol_lookup)
100
_type_parameters = Collections.LIST[SRM_TYPE_PARAMETER]()
101
_pending_overrides = Collections.LIST[SRM_BOUND_METHOD]()
102
_frame_enumerator_members = Collections.MAP[FrameMember, EntityHandle]()
103
si
104
105
number(root: Scope) is
106
// <Module> already occupies TypeDef row 1, and its member
107
// runs start at 1 and are empty, so user rows follow it.
108
let next_type mut = _assembly.next_type_row
109
let next_method mut = _assembly.next_method_row
110
let next_field mut = _assembly.next_field_row
111
112
for type in SRM_MEMBER_ORDER.types(root) do
113
let fields = SRM_MEMBER_ORDER.fields(type)
114
let methods = SRM_MEMBER_ORDER.methods(type)
115
116
_handles.emission_plan.add(type, fields, methods)
117
118
if let declared = type.declared then
119
_handles.set_type_definition(declared, MetadataTokens.type_definition_handle(next_type))
120
fi
121
122
next_type = next_type + 1
123
124
for `field in fields do
125
_handles.set_field_definition(`field, MetadataTokens.field_definition_handle(next_field))
126
127
next_field = next_field + 1
128
od
129
130
if _is_unit_variant(type) then
131
_handles.set_unit_variant_instance(
132
type.declared!, MetadataTokens.field_definition_handle(next_field))
133
134
next_field = next_field + 1
135
fi
136
137
// An enum's storage field and its members are fields of
138
// the emitted type but not of the symbol table's, so
139
// they are counted here rather than by the member order.
140
next_field = next_field + _enum_field_count(type)
141
142
for method in methods do
143
_handles.set_method_definition(method, MetadataTokens.method_definition_handle(next_method))
144
145
next_method = next_method + 1
146
od
147
148
if _is_unit_variant(type) then
149
_handles.set_unit_variant_initializer(
150
type.declared!, MetadataTokens.method_definition_handle(next_method))
151
152
next_method = next_method + 1
153
fi
154
155
for member in _synthesised_frame_members(type) do
156
_handles.set_frame_member(
157
cast Semantic.Symbols.STATE_MACHINE_FRAME_BASE?(type.declared)!,
158
member,
159
MetadataTokens.method_definition_handle(next_method))
160
161
next_method = next_method + 1
162
od
163
164
next_method = next_method + _boilerplate_members(type).count
165
next_method = next_method + _trait_bridges(type).count
166
od
167
si
168
169
// An iterable or iterator type satisfies the non-generic
170
// framework interfaces its generic ones derive from with a
171
// member apiece. Neither is a declaration the symbol table
172
// holds, so both passes take them from here, last in the
173
// method run.
174
//
175
// One list, read by both passes, in one order — the same
176
// discipline `FRAME_MEMBERS` keeps, and for the same reason: a
177
// member run written in a different order than it was numbered
178
// reparents members onto the wrong type and still loads.
179
_boilerplate_members(type: SRM_EMITTED_TYPE) -> Collections.List[BoilerplateMember] static is
180
let result = Collections.LIST[BoilerplateMember]()
181
182
let declared = type.declared
183
184
if !declared? then
185
return result
186
fi
187
188
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
189
190
if _declares_trait(declared, lookup.get_unspecialized_iterable_type()) then
191
result.add(BoilerplateMember.ENUMERABLE_GET_ENUMERATOR)
192
fi
193
194
if _declares_trait(declared, lookup.get_unspecialized_iterator_type()) then
195
result.add(BoilerplateMember.ENUMERATOR_GET_CURRENT)
196
fi
197
198
return result
199
si
200
201
// The members a state-machine frame carries that no symbol
202
// declares: MoveNext and the iterator surface every consumer
203
// reaches it through.
204
//
205
// The frame's *constructor* is not among them — `declare()`
206
// declares it into the frame's own scope, so the member order
207
// already yields it and it already has a row.
208
//
209
// One list, read by both passes, in one order. A frame's rows
210
// are numbered from this and written from this, and nothing
211
// checks that the two agree — a member run written in a
212
// different order than it was numbered reparents members onto
213
// the wrong type and still loads.
214
FRAME_MEMBERS: Collections.List[FrameMember] static =>
215
[
216
FrameMember.MOVE_NEXT,
217
FrameMember.GET_CURRENT,
218
FrameMember.GET_ENUMERATOR,
219
FrameMember.DISPOSE,
220
FrameMember.RESET,
221
FrameMember.TO_STRING
222
]
223
224
225
// The members a state machine's frame carries that no symbol
226
// declares, for whichever kind of state machine this type is.
227
// Empty for everything else.
228
//
229
// One list per kind, read by both passes, in one order — a
230
// member run written in a different order than it was numbered
231
// reparents members onto the wrong type and still loads.
232
_synthesised_frame_members(type: SRM_EMITTED_TYPE) -> Collections.List[FrameMember] static is
233
if isa Semantic.Symbols.STATE_MACHINE_FRAME(type.declared) then
234
return FRAME_MEMBERS
235
fi
236
237
if isa Semantic.Symbols.ASYNC_STATE_MACHINE_FRAME(type.declared) then
238
return ASYNC_FRAME_MEMBERS
239
fi
240
241
return Collections.LIST[FrameMember]()
242
si
243
244
// An async frame satisfies `IAsyncStateMachine`, whose two
245
// members it has no symbol for. Its MoveNext returns void,
246
// unlike a generator's.
247
ASYNC_FRAME_MEMBERS: Collections.List[FrameMember] static =>
248
[
249
FrameMember.MOVE_NEXT,
250
FrameMember.SET_STATE_MACHINE
251
]
252
253
_write_async_frame_members(type: SRM_EMITTED_TYPE) is
254
let frame = cast Semantic.Symbols.ASYNC_STATE_MACHINE_FRAME?(type.declared)
255
256
if !frame? then
257
return
258
fi
259
260
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
261
let void = lookup.get_void_type()
262
263
for member in ASYNC_FRAME_MEMBERS do
264
let arguments = Collections.LIST[Semantic.Types.Type]()
265
266
if member == FrameMember.SET_STATE_MACHINE then
267
arguments.add(lookup.get_async_state_machine_interface_type()!)
268
fi
269
270
let handle =
271
_assembly.add_method_definition(
272
SRM_FLAGS.frame_member_attributes(member),
273
cast System.Reflection.MethodImplAttributes(0), // IL, managed
274
_assembly.get_or_add_string(_frame_member_name(member)),
275
_assembly.get_or_add_blob(
276
_signatures.call_signature(void, arguments, true)),
277
_handles.frame_member_body(frame, member) ?? -1,
278
MetadataTokens.parameter_handle(_assembly.next_parameter_row))
279
280
_mark_compiler_generated(cast EntityHandle(handle))
281
od
282
si
283
284
// The rows for a frame's synthesised members, in the order
285
// FRAME_MEMBERS gives and the numbering pass assumed. Each body
286
// was deposited by the tree walk against the same key.
287
_write_frame_members(type: SRM_EMITTED_TYPE) is
288
_frame_enumerator_members.clear()
289
290
let frame = cast Semantic.Symbols.STATE_MACHINE_FRAME?(type.declared)
291
292
if !frame? then
293
return
294
fi
295
296
let element = frame.class_element_type
297
298
// The frame already carries its own `Iterator[T]` as an
299
// ancestor, constructed over the same element type, so
300
// GetEnumerator's return type is read off it rather than
301
// rebuilt from the innate lookup.
302
let iterator = _iterator_ancestor(frame)
303
304
for member in FRAME_MEMBERS do
305
let handle =
306
_assembly.add_method_definition(
307
SRM_FLAGS.frame_member_attributes(member),
308
cast System.Reflection.MethodImplAttributes(0), // IL, managed
309
_assembly.get_or_add_string(_frame_member_name(member)),
310
_assembly.get_or_add_blob(
311
_frame_member_signature(member, element, iterator)),
312
_handles.frame_member_body(frame, member) ?? -1,
313
MetadataTokens.parameter_handle(_assembly.next_parameter_row))
314
315
_mark_compiler_generated(cast EntityHandle(handle))
316
317
if member == FrameMember.GET_ENUMERATOR \/ member == FrameMember.GET_CURRENT then
318
_frame_enumerator_members[member] = cast EntityHandle(handle)
319
fi
320
od
321
322
_frame_element_type = element
323
si
324
325
_iterator_ancestor(frame: Classy) -> Semantic.Types.Type is
326
let unspecialized =
327
IoC.CONTAINER.instance.innate_symbol_lookup.get_unspecialized_iterator_type()
328
329
if let found = frame.find_ancestor(unspecialized) then
330
return found
331
fi
332
333
assert false else
334
"state-machine frame '{frame.name}' does not implement Iterator[T]"
335
336
return unspecialized
337
si
338
339
// The CLR names these members, not ghūl: each satisfies an
340
// interface the frame implements.
341
_frame_member_name(member: FrameMember) -> string static is
342
if member == FrameMember.MOVE_NEXT then
343
return "MoveNext"
344
elif member == FrameMember.GET_CURRENT then
345
return "get_Current"
346
elif member == FrameMember.GET_ENUMERATOR then
347
return "GetEnumerator"
348
elif member == FrameMember.DISPOSE then
349
return "Dispose"
350
elif member == FrameMember.RESET then
351
return "Reset"
352
elif member == FrameMember.SET_STATE_MACHINE then
353
return "SetStateMachine"
354
fi
355
356
return "ToString"
357
si
358
359
_frame_member_signature(
360
member: FrameMember,
361
element: Semantic.Types.Type,
362
iterator: Semantic.Types.Type
363
) -> ubyte[] is
364
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
365
let none = Collections.LIST[Semantic.Types.Type]()
366
367
if member == FrameMember.MOVE_NEXT then
368
return _signatures.call_signature(lookup.get_bool_type(), none, true)
369
elif member == FrameMember.GET_CURRENT then
370
return _signatures.call_signature(element, none, true)
371
elif member == FrameMember.GET_ENUMERATOR then
372
return _signatures.call_signature(iterator, none, true)
373
elif member == FrameMember.DISPOSE \/ member == FrameMember.RESET then
374
return _signatures.call_signature(lookup.get_void_type(), none, true)
375
fi
376
377
return _signatures.call_signature(lookup.get_string_type(), none, true)
378
si
379
380
// A unit variant's interned instance and the static constructor
381
// that fills it are synthesised here rather than read from the
382
// symbol table, so both passes have to place them at the same
383
// point in the type's member runs: last in each.
384
_is_unit_variant(type: SRM_EMITTED_TYPE) -> bool is
385
if let variant: Semantic.Symbols.VARIANT = type.declared then
386
return variant.is_unit_variant
387
fi
388
389
return false
390
si
391
392
write_rows() is
393
// Marks every assembly the compiler produces, so the
394
// reflection-side name mapping can tell a ghūl-compiled
395
// assembly from an ordinary .NET one and skip de-camel-casing
396
// member names that already arrived in ghūl's own case
397
// convention.
398
_mark(_assembly.assembly_handle, "Ghul.Internal.GHUL_COMPILED_ATTRIBUTE")
399
400
for planned in _handles.emission_plan.types do
401
let type = planned.type
402
403
let first_field = MetadataTokens.field_definition_handle(_assembly.next_field_row)
404
let first_method = MetadataTokens.method_definition_handle(_assembly.next_method_row)
405
406
for `field in planned.fields do
407
_write_field(`field)
408
od
409
410
if _is_unit_variant(type) then
411
_write_unit_variant_instance(type.declared!)
412
fi
413
414
_write_enum_fields(type)
415
416
for method in planned.methods do
417
_write_method(method)
418
od
419
420
if _is_unit_variant(type) then
421
_write_unit_variant_initializer(type.declared!)
422
fi
423
424
_write_frame_members(type)
425
_write_async_frame_members(type)
426
427
let boilerplate = _write_boilerplate(type)
428
let bridges = _write_trait_bridges(type)
429
430
let handle =
431
_assembly.add_type_definition(
432
_type_attributes(type),
433
_assembly.get_or_add_string(_namespace_name(type)),
434
_assembly.get_or_add_string(type.name),
435
_base_type(type),
436
first_field,
437
first_method)
438
439
if let declared = type.declared then
440
let names = declared.argument_names
441
442
for i in 0..names.count do
443
_type_parameters.add(
444
SRM_TYPE_PARAMETER(
445
cast EntityHandle(handle),
446
i,
447
names[i],
448
SRM_FLAGS.type_parameter_attributes(
449
declared.get_argument_variance(i),
450
declared.get_argument_constraint_kind(i),
451
declared.get_argument_has_constructor_constraint(i)),
452
declared.get_argument_type_bounds(i),
453
SRM_SIGNATURE_ENCODER.frame_mapping(declared)))
454
od
455
456
for `interface in _interfaces(declared) do
457
let impl_handle =
458
_assembly.add_interface_implementation(handle, `interface.handle)
459
460
_write_slot(
461
cast EntityHandle(impl_handle),
462
_nullable_slot_attributes(`interface.ancestor_type))
463
od
464
fi
465
466
for bound in boilerplate do
467
_assembly.add_method_implementation(handle, bound.body, bound.declaration)
468
od
469
470
for bound in bridges do
471
_assembly.add_method_implementation(handle, bound.body, bound.declaration)
472
od
473
474
for bound in _pending_overrides do
475
_assembly.add_method_implementation(handle, bound.body, bound.declaration)
476
od
477
478
_pending_overrides.clear()
479
480
_write_properties(handle, type)
481
482
_write_marker_attributes(cast EntityHandle(handle), type)
483
od
484
485
_write_type_parameters()
486
si
487
488
// A type's properties, and the map pointing at the run of rows
489
// they occupy.
490
//
491
// Without these an importing compiler sees the accessor methods
492
// and no property at all, and reports the property as a member
493
// that does not exist — a diagnostic that reads as a resolution
494
// problem rather than as missing metadata.
495
//
496
// A property is not a member in its own right at run time: the
497
// getter and setter are ordinary methods and already have their
498
// rows, and the property row only names them. So there is
499
// nothing here for a method body to refer to, and nothing that
500
// has to be numbered before bodies are encoded.
501
_write_properties(parent: TypeDefinitionHandle, type: SRM_EMITTED_TYPE) is
502
let properties = SRM_MEMBER_ORDER.properties(type)
503
504
if properties.count == 0 then
505
return
506
fi
507
508
// PropertyList is a run pointer, so it names the first row
509
// of this type's run. The rows are written immediately
510
// below, in this same iteration, so the two cannot disagree
511
// — unlike the field and method runs, which are numbered in
512
// one pass and written in another.
513
let first = MetadataTokens.property_definition_handle(_assembly.next_property_row)
514
515
for property in properties do
516
let handle =
517
_assembly.add_property(
518
_assembly.get_or_add_string(SRM_FLAGS.property_name(property)),
519
_signatures.property_signature(property))
520
521
if let read = property.read_function then
522
if let accessor = _handles.method_definition(read) then
523
_assembly.add_property_accessor(handle, accessor, true)
524
fi
525
fi
526
527
if let assign = property.assign_function then
528
if let accessor = _handles.method_definition(assign) then
529
_assembly.add_property_accessor(handle, accessor, false)
530
fi
531
fi
532
533
// The reader looks at the property before falling back
534
// to its getter's return slot, so the attributes have to
535
// be here as well as on the accessor.
536
_write_slot(cast EntityHandle(handle), _slot_attributes(property.type))
537
538
// As with a method (see the same check in _write_method):
539
// an explicit or implicit interface implementation (e.g.
540
// Current on IEnumerator[T]) carries the interface's IL
541
// name rather than ghūl's own name for it.
542
if property.il_name !~ property.name then
543
_attach(
544
cast EntityHandle(handle),
545
"ghul-runtime",
546
GHUL_NAME_ATTRIBUTE_NAME,
547
_string_constructor_types(),
548
SRM_ATTRIBUTE_BLOB_ENCODER.encode_string_argument(property.name))
549
fi
550
551
if property.is_internal then
552
_mark_compiler_generated(cast EntityHandle(handle))
553
fi
554
555
if let attributes = property.custom_attributes then
556
_write_attributes(cast EntityHandle(handle), attributes)
557
fi
558
od
559
560
_assembly.add_property_map(parent, first)
561
si
562
563
// The attributes that carry to another assembly what the source
564
// said but the metadata cannot otherwise express: that a type is
565
// a union, a variant, the default variant, closed to extension,
566
// or a namespace's globals carrier.
567
//
568
// Without them an importing compiler reads a union as an
569
// ordinary class and its variants as unrelated types that happen
570
// to share a name prefix — which is why a consumer sees the
571
// union's own name as a namespace rather than as a type.
572
_write_marker_attributes(handle: EntityHandle, type: SRM_EMITTED_TYPE) is
573
let declared = type.declared
574
575
if !declared? then
576
// A globals carrier stands for a namespace rather than
577
// for a declared type, and is marked so that an importer
578
// reads the members inside it as globals rather than as
579
// static members of a class. The carrier itself is also
580
// the compiler's own synthesis, so it carries the BCL's
581
// marker like any other synthesised member.
582
_mark(handle, Semantic.DotNet.GLOBALS_CARRIER.attribute_name)
583
_mark_compiler_generated(handle)
584
585
return
586
fi
587
588
if isa Semantic.Symbols.UNION(declared) then
589
_mark(handle, "Ghul.Internal.UNION_ATTRIBUTE")
590
fi
591
592
if let variant: Semantic.Symbols.VARIANT = declared then
593
_mark(handle, "Ghul.Internal.VARIANT_ATTRIBUTE")
594
595
if let owner: Semantic.Symbols.UNION = variant.owner then
596
if owner.default_variant == variant then
597
_mark(handle, "Ghul.Internal.DEFAULT_VARIANT_ATTRIBUTE")
598
fi
599
fi
600
fi
601
602
if let `class: Semantic.Symbols.CLASS = declared then
603
if !`class.is_open then
604
_mark(handle, "Ghul.Internal.CLOSED_ATTRIBUTE")
605
fi
606
fi
607
608
if let `trait: Semantic.Symbols.TRAIT = declared then
609
if !`trait.is_open then
610
_mark(handle, "Ghul.Internal.CLOSED_ATTRIBUTE")
611
fi
612
fi
613
614
if declared.is_internal then
615
_mark_compiler_generated(handle)
616
fi
617
618
if let attributes = declared.custom_attributes then
619
_write_attributes(handle, attributes)
620
fi
621
si
622
623
// A marker takes no arguments, so they all share one value blob
624
// and differ only in which constructor they name.
625
//
626
// The name is qualified, and split here rather than written as a
627
// namespace and a simple name at each call site: one of these is
628
// already a qualified constant, and a reference built from the
629
// two halves out of step names a type that does not exist while
630
// still emitting cleanly.
631
_mark(parent: EntityHandle, qualified_name: string) is
632
_attach(
633
parent,
634
"ghul-runtime",
635
qualified_name,
636
Collections.LIST[Semantic.Types.Type](),
637
SRM_ASSEMBLY_EMITTER.NO_ARGUMENT_ATTRIBUTE_VALUE)
638
si
639
640
// Marks a synthesised member or type with the BCL's own
641
// CompilerGeneratedAttribute, in System.Runtime rather than
642
// ghul-runtime — see COMPILER_GENERATED_ATTRIBUTE_NAME.
643
_mark_compiler_generated(parent: EntityHandle) is
644
_attach(
645
parent,
646
"System.Runtime",
647
COMPILER_GENERATED_ATTRIBUTE_NAME,
648
Collections.LIST[Semantic.Types.Type](),
649
SRM_ASSEMBLY_EMITTER.NO_ARGUMENT_ATTRIBUTE_VALUE)
650
si
651
652
_attach(
653
parent: EntityHandle,
654
assembly_name: string,
655
qualified_name: string,
656
argument_types: Collections.List[Semantic.Types.Type],
657
value: ubyte[]
658
) is
659
_assembly.add_named_attribute(
660
parent, assembly_name, qualified_name, argument_types, value)
661
si
662
663
_write_type_parameters() is
664
_type_parameters.sort(
665
(left: SRM_TYPE_PARAMETER, right: SRM_TYPE_PARAMETER) -> int is
666
let by_owner = left.order - right.order
667
668
if by_owner != 0 then
669
return by_owner
670
fi
671
672
return left.index - right.index
673
si)
674
675
for type_parameter in _type_parameters do
676
let handle =
677
_assembly.add_generic_parameter(
678
type_parameter.owner,
679
type_parameter.index,
680
type_parameter.name,
681
type_parameter.attributes)
682
683
// GenericParamConstraint is sorted on the parameter it
684
// constrains, so writing each parameter's constraints as
685
// the parameter itself is written keeps the table in
686
// order without a second sort.
687
if type_parameter.bounds.count > 0 then
688
let mapping = type_parameter.mapping
689
690
if mapping? then
691
mapping.map_type_arguments()
692
fi
693
694
try
695
for bound in type_parameter.bounds do
696
_assembly.add_generic_parameter_constraint(
697
handle, _type_token(bound))
698
od
699
finally
700
if mapping? then
701
mapping.unmap_type_arguments()
702
fi
703
yrt
704
fi
705
od
706
si
707
708
_write_field(`field: Field) is
709
let handle =
710
_assembly.add_field_definition(
711
SRM_FLAGS.field_attributes(`field),
712
_assembly.get_or_add_string(`field.name),
713
_assembly.get_or_add_blob(_signatures.field_signature(`field)))
714
715
// A field declares a type the same way a parameter does, so
716
// it needs the same attributes to carry what the type alone
717
// cannot say — a tuple's element names, a reference type's
718
// nullability.
719
_write_slot(cast EntityHandle(handle), _slot_attributes(`field.type))
720
721
if `field.is_internal then
722
_mark_compiler_generated(cast EntityHandle(handle))
723
fi
724
725
if let attributes = `field.custom_attributes then
726
_write_attributes(cast EntityHandle(handle), attributes)
727
fi
728
si
729
730
// An enum is a value type whose members are compile-time
731
// constants, so the symbol table holds them as members of the
732
// enum rather than as fields of anything. The emitted shape is
733
// fixed by ECMA-335: one instance field named `value__` holding
734
// the value, and one static literal per member.
735
_enum_members(type: SRM_EMITTED_TYPE) -> Collections.List[Semantic.Symbols.ENUM_STRUCT_MEMBER] is
736
let result = Collections.LIST[Semantic.Symbols.ENUM_STRUCT_MEMBER]()
737
738
if !isa Semantic.Symbols.ENUM_STRUCT(type.declared) then
739
return result
740
fi
741
742
for symbol in type.scope.symbols do
743
if let member: Semantic.Symbols.ENUM_STRUCT_MEMBER = symbol then
744
result.add(member)
745
fi
746
od
747
748
return result
749
si
750
751
// The `value__` field plus one per member, or none at all when
752
// the type is not an enum.
753
_enum_field_count(type: SRM_EMITTED_TYPE) -> int is
754
if !isa Semantic.Symbols.ENUM_STRUCT(type.declared) then
755
return 0
756
fi
757
758
return _enum_members(type).count + 1
759
si
760
761
_write_enum_fields(type: SRM_EMITTED_TYPE) is
762
if !isa Semantic.Symbols.ENUM_STRUCT(type.declared) then
763
return
764
fi
765
766
let enum_type = type.declared.type!
767
768
_assembly.add_field_definition(
769
SRM_FLAGS.enum_value_attributes(),
770
_assembly.get_or_add_string("value__"),
771
_assembly.get_or_add_blob(
772
_signatures.field_signature(
773
IoC.CONTAINER.instance.innate_symbol_lookup.get_int_type())))
774
775
for member in _enum_members(type) do
776
let handle =
777
_assembly.add_field_definition(
778
SRM_FLAGS.enum_member_attributes(),
779
_assembly.get_or_add_string(member.name),
780
_assembly.get_or_add_blob(_signatures.field_signature(enum_type)))
781
782
// The value is stored as the enum's underlying type, not
783
// as the enum: a Constant row holds a primitive.
784
_assembly.add_constant(
785
cast EntityHandle(handle),
786
cast object?(member.numeric_value)!)
787
od
788
si
789
790
// The interned instance a unit variant hands out. Its type is
791
// the variant applied to its own parameters: a generic variant's
792
// open form names no type the field could hold.
793
_write_unit_variant_instance(variant: Classy) is
794
_assembly.add_field_definition(
795
SRM_FLAGS.unit_variant_instance_attributes(),
796
_assembly.get_or_add_string("_instance"),
797
_assembly.get_or_add_blob(
798
_signatures.field_signature(variant.own_instantiation)))
799
si
800
801
_write_unit_variant_initializer(variant: Classy) is
802
_assembly.add_method_definition(
803
SRM_FLAGS.static_initializer_attributes(),
804
cast System.Reflection.MethodImplAttributes(0), // IL, managed
805
_assembly.get_or_add_string(".cctor"),
806
_assembly.get_or_add_blob(_signatures.static_initializer_signature()),
807
_handles.unit_variant_initializer_body(variant) ?? -1,
808
MetadataTokens.parameter_handle(_assembly.next_parameter_row))
809
si
810
811
_write_method(method: Function) is
812
// A function with no deposited body never had one walked:
813
// an abstract declaration, or a trait member left to its
814
// implementors. -1 is the metadata encoding of "no body".
815
let body_offset = _handles.body_offset(method) ?? -1
816
817
// A MethodDef's ParamList is a run pointer like a TypeDef's
818
// member lists, so it names the next free row even when the
819
// method takes nothing; a nil handle is not an empty run,
820
// it is an invalid index that faults on first read.
821
let first_parameter = MetadataTokens.parameter_handle(_assembly.next_parameter_row)
822
823
// The return slot is parameter zero, and has no row of its
824
// own unless something has to hang off it. Written first so
825
// the run reads in sequence order.
826
let return_slot = _slot_attributes(method.return_type)
827
828
if return_slot.count > 0 then
829
let parameter = _assembly.add_parameter(_assembly.get_or_add_string(""), 0)
830
831
_write_slot(cast EntityHandle(parameter), return_slot)
832
fi
833
834
let names = method.argument_names
835
836
for i in 0..names.count do
837
let parameter =
838
_assembly.add_parameter(_assembly.get_or_add_string(names[i]), i + 1)
839
840
_write_slot(cast EntityHandle(parameter), _slot_attributes(method.arguments[i]))
841
_write_slot(cast EntityHandle(parameter), _pack_attributes(method, i))
842
843
if let attributes = method.find_direct(names[i])?.custom_attributes then
844
_write_attributes(cast EntityHandle(parameter), attributes)
845
fi
846
od
847
848
let covariant_overrides = _class_covariant_overridees(method)
849
850
let attributes =
851
if covariant_overrides.count > 0 then
852
SRM_FLAGS.with_new_slot(SRM_FLAGS.method_attributes(method))
853
else
854
SRM_FLAGS.method_attributes(method)
855
fi
856
857
// A P/Invoke keeps the signature it declares. Without
858
// `preservesig` the runtime reads the return as an HRESULT
859
// and hands the caller nothing, which is a call that runs
860
// and answers the return type's default.
861
let impl_flags =
862
if method.pinvoke? then
863
System.Reflection.MethodImplAttributes.PRESERVE_SIG
864
else
865
cast System.Reflection.MethodImplAttributes(0) // IL, managed
866
fi
867
868
let handle = _assembly.add_method_definition(
869
attributes,
870
impl_flags,
871
_assembly.get_or_add_string(SRM_FLAGS.method_name(method)),
872
_assembly.get_or_add_blob(_signatures.method_signature(method)),
873
body_offset,
874
first_parameter)
875
876
// What a P/Invoke method calls: the module, the entry point
877
// in it, and how to marshal. The row is what makes the
878
// method a call into a shared library rather than one with
879
// no body at all.
880
if let pinvoke = method.pinvoke then
881
_assembly.add_method_import(
882
handle,
883
pinvoke.import_attributes,
884
pinvoke.entry_point,
885
_assembly.get_or_add_module_reference(pinvoke.module))
886
fi
887
888
let type_parameters = method.generic_arguments
889
890
for i in 0..type_parameters.count do
891
_type_parameters.add(
892
SRM_TYPE_PARAMETER(
893
cast EntityHandle(handle),
894
i,
895
type_parameters[i].name ?? "T{i}",
896
// A method's type parameter cannot be variant —
897
// the CLR allows variance only on an interface
898
// or delegate type — so only the kind
899
// constraints reach the row.
900
SRM_FLAGS.type_parameter_attributes(
901
Semantic.Types.TypeVariance.INVARIANT,
902
method.get_argument_constraint_kind(i),
903
method.get_argument_has_constructor_constraint(i)),
904
method.get_argument_type_bounds(i),
905
SRM_SIGNATURE_ENCODER.frame_mapping(method)))
906
od
907
908
// A narrower return takes the overridden slot through an
909
// explicit override, in a slot of its own; the attribute is what
910
// makes the runtime route a call through the base type to a
911
// further override of this method rather than stopping here.
912
if covariant_overrides.count > 0 then
913
for overridee in covariant_overrides do
914
_pending_overrides.add(
915
SRM_BOUND_METHOD(
916
cast EntityHandle(handle),
917
IoC.CONTAINER.instance.ir_context.resolve_call_target(overridee)))
918
od
919
920
_attach(
921
cast EntityHandle(handle),
922
"System.Runtime",
923
PRESERVE_BASE_OVERRIDES_ATTRIBUTE_NAME,
924
Collections.LIST[Semantic.Types.Type](),
925
SRM_ASSEMBLY_EMITTER.NO_ARGUMENT_ATTRIBUTE_VALUE)
926
fi
927
928
if method.is_declared_pure then
929
_mark(cast EntityHandle(handle), PURE_ATTRIBUTE_NAME)
930
fi
931
932
if method.is_declared_stable then
933
_mark(cast EntityHandle(handle), STABLE_ATTRIBUTE_NAME)
934
fi
935
936
// What a pack-marked declared return type asks of a caller
937
// in another assembly - the same convention the formal
938
// markers use, argumentless at depth zero.
939
if method.return_pack_depth == 0 then
940
_mark(cast EntityHandle(handle), RETURN_PACK_ATTRIBUTE_NAME)
941
elif method.return_pack_depth > 0 then
942
_attach(
943
cast EntityHandle(handle),
944
"ghul-runtime",
945
RETURN_PACK_ATTRIBUTE_NAME,
946
_int_constructor_types(),
947
_int_argument_attribute_value(method.return_pack_depth))
948
fi
949
950
if method.is_internal then
951
_mark_compiler_generated(cast EntityHandle(handle))
952
fi
953
954
// An override or interface implementation carries the IL
955
// name its base or interface fixes (`ToString`, `MoveNext`,
956
// …) rather than ghūl's own name for it, so a reflection-
957
// side reader cannot recover the ghūl name from the IL name
958
// the way it can for an ordinary member. Carry it directly.
959
if !method.is_constructor /\ method.il_name !~ method.name then
960
_attach(
961
cast EntityHandle(handle),
962
"ghul-runtime",
963
GHUL_NAME_ATTRIBUTE_NAME,
964
_string_constructor_types(),
965
SRM_ATTRIBUTE_BLOB_ENCODER.encode_string_argument(method.name))
966
fi
967
968
if let attributes = method.custom_attributes then
969
_write_attributes(cast EntityHandle(handle), attributes)
970
fi
971
972
// `@IL.output` ranges captured while this body was emitted, if
973
// any. The attribute is synthetic - referenced by name only, and
974
// never resolved - so it need not exist in any referenced
975
// assembly; the test runner reads the raw blob without resolving
976
// the constructor.
977
if let outputs = _handles.il_outputs(method) then
978
_attach(
979
cast EntityHandle(handle),
980
"ghul-runtime",
981
IL_OUTPUT_ATTRIBUTE_NAME,
982
_il_output_ranges_constructor_types(),
983
SRM_ATTRIBUTE_BLOB_ENCODER.encode_il_output_ranges(outputs))
984
fi
985
986
if let entry_point = _assembly.entry_point_function then
987
if entry_point == method then
988
_assembly.set_entry_point(handle)
989
fi
990
fi
991
si
992
993
PURE_ATTRIBUTE_NAME: string static => "Ghul.Internal.PURE_ATTRIBUTE"
994
995
ARGUMENT_PACK_ATTRIBUTE_NAME: string static =>
996
"Ghul.Internal.ARGUMENT_PACK_ATTRIBUTE"
997
998
RETURN_PACK_ATTRIBUTE_NAME: string static =>
999
"Ghul.Internal.RETURN_PACK_ATTRIBUTE"
1000
1001
ARGUMENT_SPREAD_ATTRIBUTE_NAME: string static =>
1002
"Ghul.Internal.ARGUMENT_SPREAD_ATTRIBUTE"
1003
1004
STABLE_ATTRIBUTE_NAME: string static => "Ghul.Internal.STABLE_ATTRIBUTE"
1005
1006
GHUL_NAME_ATTRIBUTE_NAME: string static => "Ghul.Internal.GHUL_NAME_ATTRIBUTE"
1007
1008
NULLABLE_ATTRIBUTE_NAME: string static =>
1009
"System.Runtime.CompilerServices.NullableAttribute"
1010
1011
// The BCL's own marker for a synthesised member or type — the
1012
// same one C# emits for a backing field, a closure, an iterator
1013
// or async state machine, and its public members. Emitting it
1014
// lets an importer recognise a synthesised symbol without
1015
// reading its name, whether the importer is this compiler or a
1016
// different tool entirely (a debugger, a decompiler, a
1017
// serializer skipping a property's shadow field).
1018
COMPILER_GENERATED_ATTRIBUTE_NAME: string static =>
1019
"System.Runtime.CompilerServices.CompilerGeneratedAttribute"
1020
1021
PRESERVE_BASE_OVERRIDES_ATTRIBUTE_NAME: string static =>
1022
"System.Runtime.CompilerServices.PreserveBaseOverridesAttribute"
1023
1024
TUPLE_ELEMENT_NAMES_ATTRIBUTE_NAME: string static =>
1025
"System.Runtime.CompilerServices.TupleElementNamesAttribute"
1026
1027
IL_OUTPUT_ATTRIBUTE_NAME: string static =>
1028
"Ghul.Internal.IL_OUTPUT_ATTRIBUTE"
1029
1030
// The `NullableAttribute` entry for `type`'s reference-`?`
1031
// positions, or empty when none of them are `?` — the one piece
1032
// of `_slot_attributes` that also applies to an `InterfaceImpl`
1033
// row, which has no return-slot or tuple-element-name or purity
1034
// concept of its own.
1035
_nullable_slot_attributes(type: Semantic.Types.Type?) -> Collections.LIST[SRM_SLOT_ATTRIBUTE] is
1036
let result = Collections.LIST[SRM_SLOT_ATTRIBUTE]()
1037
1038
if !type? then
1039
return result
1040
fi
1041
1042
let nullable = Semantic.DotNet.NULLABILITY.compute_bytes(type)
1043
1044
if Semantic.DotNet.NULLABILITY.needs_attribute_for_bytes(nullable) then
1045
if nullable.count == 1 then
1046
result.add(
1047
SRM_SLOT_ATTRIBUTE(
1048
"System.Runtime",
1049
NULLABLE_ATTRIBUTE_NAME,
1050
_byte_constructor_types(),
1051
SRM_ATTRIBUTE_BLOB_ENCODER.encode_byte_argument(nullable[0])))
1052
else
1053
result.add(
1054
SRM_SLOT_ATTRIBUTE(
1055
"System.Runtime",
1056
NULLABLE_ATTRIBUTE_NAME,
1057
_byte_array_constructor_types(),
1058
SRM_ATTRIBUTE_BLOB_ENCODER.encode_byte_array_argument(nullable)))
1059
fi
1060
fi
1061
1062
return result
1063
si
1064
1065
// What a return or parameter slot carries beyond its type: the
1066
// reference nullability the CLR has no way to express, the
1067
// element names a value tuple loses on the way into metadata,
1068
// and whether the slot's function type was declared pure.
1069
//
1070
// Returned rather than written so the caller can decide whether
1071
// the slot needs a Param row at all — the return slot has none
1072
// unless something hangs off it.
1073
_slot_attributes(type: Semantic.Types.Type?) -> Collections.LIST[SRM_SLOT_ATTRIBUTE] is
1074
let result = Collections.LIST[SRM_SLOT_ATTRIBUTE]()
1075
1076
if !type? then
1077
return result
1078
fi
1079
1080
result.add_range(_nullable_slot_attributes(type))
1081
1082
if let names = Semantic.DotNet.TUPLE_ELEMENT_NAMES.attribute_names_for_type(type) then
1083
result.add(
1084
SRM_SLOT_ATTRIBUTE(
1085
"System.Runtime",
1086
TUPLE_ELEMENT_NAMES_ATTRIBUTE_NAME,
1087
_string_array_constructor_types(),
1088
SRM_ATTRIBUTE_BLOB_ENCODER.encode_string_array_argument(names)))
1089
fi
1090
1091
if type.is_pure_function then
1092
result.add(
1093
SRM_SLOT_ATTRIBUTE(
1094
"ghul-runtime",
1095
PURE_ATTRIBUTE_NAME,
1096
Collections.LIST[Semantic.Types.Type](),
1097
SRM_ASSEMBLY_EMITTER.NO_ARGUMENT_ATTRIBUTE_VALUE))
1098
fi
1099
1100
return result
1101
si
1102
1103
// What a formal declared against an argument pack asks of a
1104
// caller in another assembly. Neither claim is recoverable from
1105
// the slot's type - the pack binds to a tuple either way - so
1106
// each is written as a marker of its own.
1107
_pack_attributes(method: Function, index: int) -> Collections.LIST[SRM_SLOT_ATTRIBUTE] is
1108
let result = Collections.LIST[SRM_SLOT_ATTRIBUTE]()
1109
1110
if method.get_argument_is_pack(index) then
1111
let depth = method.get_argument_pack_depth(index)
1112
1113
// The argumentless form is what every marker written on
1114
// a formal's own function type has always meant, so a
1115
// depth of zero keeps writing it - an assembly built
1116
// against a runtime that predates the depth still reads
1117
// those.
1118
if depth == 0 then
1119
result.add(_pack_marker(ARGUMENT_PACK_ATTRIBUTE_NAME))
1120
else
1121
result.add(
1122
SRM_SLOT_ATTRIBUTE(
1123
"ghul-runtime",
1124
ARGUMENT_PACK_ATTRIBUTE_NAME,
1125
_int_constructor_types(),
1126
_int_argument_attribute_value(depth)))
1127
fi
1128
fi
1129
1130
if method.spread_argument_index == index then
1131
result.add(_pack_marker(ARGUMENT_SPREAD_ATTRIBUTE_NAME))
1132
fi
1133
1134
return result
1135
si
1136
1137
_pack_marker(qualified_name: string) -> SRM_SLOT_ATTRIBUTE =>
1138
SRM_SLOT_ATTRIBUTE(
1139
"ghul-runtime",
1140
qualified_name,
1141
Collections.LIST[Semantic.Types.Type](),
1142
SRM_ASSEMBLY_EMITTER.NO_ARGUMENT_ATTRIBUTE_VALUE)
1143
1144
_write_slot(parent: EntityHandle, attributes: Collections.List[SRM_SLOT_ATTRIBUTE]) is
1145
for attribute in attributes do
1146
_attach(
1147
parent,
1148
attribute.assembly_name,
1149
attribute.qualified_name,
1150
attribute.argument_types,
1151
attribute.value)
1152
od
1153
si
1154
1155
_int_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1156
let types = Collections.LIST[Semantic.Types.Type]()
1157
1158
types.add(IoC.CONTAINER.instance.innate_symbol_lookup.get_int_type())
1159
1160
return types
1161
si
1162
1163
// The value blob of an attribute applied to one int argument:
1164
// the prolog, the argument little-endian, then a named-argument
1165
// count of zero.
1166
_int_argument_attribute_value(value: int) -> ubyte[] is
1167
let unsigned = cast uint(value)
1168
1169
return [
1170
1ub,
1171
0ub,
1172
cast ubyte(unsigned & 0xFFu),
1173
cast ubyte((unsigned >> 8) & 0xFFu),
1174
cast ubyte((unsigned >> 16) & 0xFFu),
1175
cast ubyte((unsigned >> 24) & 0xFFu),
1176
0ub,
1177
0ub
1178
]
1179
si
1180
1181
_byte_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1182
let types = Collections.LIST[Semantic.Types.Type]()
1183
1184
types.add(IoC.CONTAINER.instance.innate_symbol_lookup.get_ubyte_type())
1185
1186
return types
1187
si
1188
1189
_string_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1190
let types = Collections.LIST[Semantic.Types.Type]()
1191
1192
types.add(IoC.CONTAINER.instance.innate_symbol_lookup.get_string_type())
1193
1194
return types
1195
si
1196
1197
_byte_array_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1198
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
1199
let types = Collections.LIST[Semantic.Types.Type]()
1200
1201
types.add(lookup.get_array_type(lookup.get_ubyte_type()))
1202
1203
return types
1204
si
1205
1206
_string_array_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1207
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
1208
let types = Collections.LIST[Semantic.Types.Type]()
1209
1210
types.add(lookup.get_array_type(lookup.get_string_type()))
1211
1212
return types
1213
si
1214
1215
// `IL_OUTPUT_ATTRIBUTE(string[], int32[], int32[], int32[])`:
1216
// paths, starts, ends, sequences.
1217
_il_output_ranges_constructor_types() -> Collections.LIST[Semantic.Types.Type] is
1218
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup
1219
let types = Collections.LIST[Semantic.Types.Type]()
1220
1221
let string_array = lookup.get_array_type(lookup.get_string_type())
1222
let int_array = lookup.get_array_type(lookup.get_int_type())
1223
1224
types.add(string_array)
1225
types.add(int_array)
1226
types.add(int_array)
1227
types.add(int_array)
1228
1229
return types
1230
si
1231
1232
// Every attribute a pragma resolved onto a symbol. An argument
1233
// the encoder cannot express is left off rather than emitted
1234
// wrong: the resolver has already reported anything the source
1235
// got wrong, so reaching here means the two disagree about what
1236
// is expressible, and a truncated blob would fault the reader
1237
// rather than say so.
1238
_write_attributes(
1239
parent: EntityHandle,
1240
attributes: Collections.List[Semantic.CUSTOM_ATTRIBUTE]
1241
) is
1242
for attribute in attributes do
1243
let value = _blobs.encode(attribute)
1244
1245
if !value? then
1246
throw System.NotImplementedException(
1247
"the binary back end cannot yet encode the arguments of "
1248
"'{attribute.constructor.owner}'")
1249
fi
1250
1251
_assembly.add_custom_attribute(
1252
parent,
1253
_constructor_handle(attribute.constructor),
1254
value)
1255
od
1256
si
1257
1258
// A constructor this assembly defines is named by its own row;
1259
// an imported one by a reference through its type.
1260
_constructor_handle(constructor: Function) -> EntityHandle is
1261
if let definition = _handles.method_definition(constructor) then
1262
return cast EntityHandle(definition)
1263
fi
1264
1265
let owner = cast Classy?(constructor.owner)
1266
1267
if !owner? then
1268
throw System.NotImplementedException(
1269
"the binary back end cannot reference an attribute constructor "
1270
"with no owning type")
1271
fi
1272
1273
return cast EntityHandle(
1274
_assembly.add_constructor_reference(
1275
cast EntityHandle(_signatures.type_reference_for(owner)),
1276
"{owner.qualified_name}::.ctor",
1277
constructor.arguments))
1278
si
1279
1280
// A globals carrier is abstract and sealed: never constructed,
1281
// never extended, only a home for static members.
1282
_type_attributes(type: SRM_EMITTED_TYPE) -> System.Reflection.TypeAttributes is
1283
if let declared = type.declared then
1284
return SRM_FLAGS.type_attributes(declared)
1285
fi
1286
1287
return SRM_FLAGS.globals_carrier_type_attributes()
1288
si
1289
1290
// A type's metadata namespace is its owning namespace's
1291
// qualified name. The symbol table's root namespace has an empty
1292
// name and qualifies its children with a leading separator, so
1293
// that is stripped rather than emitted as part of the name.
1294
_namespace_name(type: SRM_EMITTED_TYPE) -> string is
1295
let owner = type.owning_namespace
1296
1297
if !owner? then
1298
return ""
1299
fi
1300
1301
// A union's variants are owned by the union rather than by a
1302
// namespace. They are emitted flat, under a name that carries
1303
// the union's, so what stands in front of a variant is the
1304
// union's own namespace followed by the union's name — built
1305
// the same way the union's own row builds it, rather than
1306
// read off `qualified_name`, so the two cannot disagree.
1307
if !owner.is_namespace then
1308
if let owning_type: Classy = owner then
1309
let outer = owning_type.owner
1310
1311
let prefix = if outer? then _strip_root(outer.qualified_name) else "" fi
1312
1313
return
1314
if prefix.length == 0 then
1315
owning_type.il_metadata_name
1316
else
1317
"{prefix}.{owning_type.il_metadata_name}"
1318
fi
1319
fi
1320
1321
return ""
1322
fi
1323
1324
return _strip_root(owner.qualified_name)
1325
si
1326
1327
_strip_root(qualified: string) -> string static =>
1328
if qualified.starts_with('.') then
1329
qualified.substring(1)
1330
else
1331
qualified
1332
fi
1333
1334
// The first non-trait ancestor, which is what the type extends;
1335
// traits extend nothing, and a class with no declared superclass
1336
// extends System.Object.
1337
_base_type(emitted: SRM_EMITTED_TYPE) -> EntityHandle is
1338
let type = emitted.declared
1339
1340
if !type? then
1341
return cast EntityHandle(
1342
_assembly.add_type_reference_by_name("System.Runtime", "System", "Object"))
1343
fi
1344
1345
if type.is_trait then
1346
return _[EntityHandle]
1347
fi
1348
1349
// An enum is a struct in the symbol table, but the runtime
1350
// only treats it as an enum — reading its value through
1351
// `value__`, converting, comparing — when it descends from
1352
// System.Enum rather than from System.ValueType directly.
1353
if isa Semantic.Symbols.ENUM_STRUCT(type) then
1354
return cast EntityHandle(
1355
_assembly.add_type_reference_by_name("System.Runtime", "System", "Enum"))
1356
fi
1357
1358
for ancestor in type.ancestors do
1359
if ancestor.is_trait then
1360
continue
1361
fi
1362
1363
// Through the token rather than the symbol: a generic
1364
// union's variant extends the union constructed over
1365
// the variant's own parameters, and the open type it
1366
// was declared from is not a type anything can extend.
1367
//
1368
// A constructed ancestor's symbol is a `Symbols.GENERIC`
1369
// wrapping the definition rather than being one, so a
1370
// test for `Classy` alone answers false for exactly the
1371
// ancestors that need constructing — and the walk falls
1372
// through to Object, which loads and is wrong.
1373
if
1374
isa Classy(ancestor.symbol) \/
1375
isa Semantic.Symbols.GENERIC(ancestor.symbol)
1376
then
1377
return _type_token(ancestor)
1378
fi
1379
od
1380
1381
if type.is_value_type then
1382
return cast EntityHandle(
1383
_assembly.add_type_reference_by_name("System.Runtime", "System", "ValueType"))
1384
fi
1385
1386
return cast EntityHandle(
1387
_assembly.add_type_reference_by_name("System.Runtime", "System", "Object"))
1388
si
1389
1390
// `System.Collections.IEnumerable` and `System.Collections.
1391
// IEnumerator` are the non-generic interfaces the generic ones
1392
// derive from, and a type implementing the generic form has to
1393
// satisfy them too. ghūl has no declaration for either member,
1394
// so each is emitted here: an explicit implementation, named for
1395
// the interface, returning the untyped form and answering null.
1396
//
1397
// The body is never called — every consumer reaches the generic
1398
// member — so answering null costs nothing and saves the walk
1399
// from having to reach the type's own iterator.
1400
_write_boilerplate(type: SRM_EMITTED_TYPE) -> Collections.List[SRM_BOUND_METHOD] is
1401
let result = Collections.LIST[SRM_BOUND_METHOD]()
1402
1403
for member in _boilerplate_members(type) do
1404
case member
1405
when BoilerplateMember.ENUMERABLE_GET_ENUMERATOR then
1406
let `interface =
1407
_assembly.add_type_reference_by_name(
1408
"System.Runtime", "System.Collections", "IEnumerator")
1409
1410
let signature =
1411
_signatures.nullary_instance_signature(cast EntityHandle(`interface))
1412
1413
result.add(
1414
_write_explicit_implementation(
1415
"System.Collections.IEnumerable.GetEnumerator",
1416
signature,
1417
false,
1418
"System.Collections",
1419
"IEnumerable",
1420
"GetEnumerator",
1421
signature,
1422
_forward_to_generic(type, "iterator", false)))
1423
1424
when BoilerplateMember.ENUMERATOR_GET_CURRENT then
1425
let signature = _signatures.nullary_instance_signature_returning_object()
1426
1427
result.add(
1428
_write_explicit_implementation(
1429
"System.Collections.IEnumerator.get_Current",
1430
signature,
1431
true,
1432
"System.Collections",
1433
"IEnumerator",
1434
"get_Current",
1435
signature,
1436
_forward_to_generic(type, "current", true)))
1437
esac
1438
od
1439
1440
return result
1441
si
1442
1443
// The class members a method overrides with a narrower return
1444
// type. Its emitted signature differs from theirs, so it cannot
1445
// take their slot by name and signature and binds to it
1446
// explicitly instead.
1447
_class_covariant_overridees(method: Function) -> Collections.List[Function] static is
1448
let result = Collections.LIST[Function]()
1449
1450
if let overridees = method.overridees then
1451
for overridee in overridees do
1452
if let function: Function = overridee /\ !_is_trait_member(function) then
1453
let seen = _as_seen_from(method, function)
1454
1455
if method.has_covariant_return_over(seen) then
1456
result.add(seen)
1457
fi
1458
fi
1459
od
1460
fi
1461
1462
return result
1463
si
1464
1465
// Whether `method` is a trait's own default: a body on an
1466
// interface, which is the only thing that can need a slot
1467
// binding of its own.
1468
_declares_trait_default(type: SRM_EMITTED_TYPE, method: Function) -> bool static is
1469
if let declared = type.declared then
1470
return declared.is_trait /\ !method.is_abstract
1471
fi
1472
1473
return false
1474
si
1475
1476
// The trait members a type's methods answer through a bridge
1477
// of the member's own signature rather than directly. A class
1478
// needs one where its return type narrows, since the runtime
1479
// does not let a method answer an interface member of another
1480
// signature; a trait needs one for every default it supplies,
1481
// narrowing or not, because one interface's method never
1482
// implicitly implements another's.
1483
//
1484
// One list, read by both passes, in one order: the bridges are
1485
// rows of the type's method run.
1486
_trait_bridges(type: SRM_EMITTED_TYPE) -> Collections.List[(method: Function, overridee: Function)] static is
1487
let result = Collections.LIST[(method: Function, overridee: Function)]()
1488
1489
for method in SRM_MEMBER_ORDER.methods(type) do
1490
if let overridees = method.overridees then
1491
for overridee in overridees do
1492
if let function: Function = overridee /\ _is_trait_member(function) then
1493
let seen = _as_seen_from(method, function)
1494
1495
// One interface's method never implicitly
1496
// implements another's, so a trait's own
1497
// default needs a bridge saying which slot
1498
// it fills whether or not the return type
1499
// narrows. A class needs one only when it
1500
// does, since the CLR matches a class's
1501
// methods to interface slots by name and
1502
// signature.
1503
if
1504
method.has_covariant_return_over(seen) \/
1505
(_declares_trait_default(type, method))
1506
then
1507
result.add((method = method, overridee = seen))
1508
fi
1509
fi
1510
od
1511
fi
1512
od
1513
1514
return result
1515
si
1516
1517
// An overridden member as the overriding type sees it: through
1518
// that type's own instantiation of the ancestor declaring it,
1519
// which is what both its return type and a reference to it name.
1520
_as_seen_from(method: Function, overridee: Function) -> Function static is
1521
if
1522
let owner: Classy = method.owner,
1523
overridee_owner: Classy = overridee.owner,
1524
overridee_type = overridee_owner.type,
1525
ancestor_type = owner.find_ancestor(overridee_type),
1526
ancestor: Semantic.Symbols.GENERIC = ancestor_type.symbol
1527
then
1528
return overridee.specialize_function(ancestor.type_map, ancestor)
1529
fi
1530
1531
return overridee
1532
si
1533
1534
_is_trait_member(function: Function) -> bool static =>
1535
if let owner: Classy = function.owner then owner.is_trait else false fi
1536
1537
_write_trait_bridges(type: SRM_EMITTED_TYPE) -> Collections.List[SRM_BOUND_METHOD] is
1538
let result = Collections.LIST[SRM_BOUND_METHOD]()
1539
let context = IoC.CONTAINER.instance.ir_context
1540
1541
for (method, overridee) in _trait_bridges(type) do
1542
let body = SRM_METHOD_BODY_EMITTER()
1543
1544
for i in 0::method.arguments.count do
1545
body.ldarg(i)
1546
od
1547
1548
let target = context.resolve_call_target(method)
1549
1550
if isa Semantic.Symbols.STRUCT_METHOD(method) then
1551
body.call(target)
1552
else
1553
body.call_virtual(target)
1554
fi
1555
1556
body.ret()
1557
1558
let definition =
1559
_assembly.add_method_definition(
1560
SRM_FLAGS.explicit_implementation_attributes(false),
1561
cast System.Reflection.MethodImplAttributes(0), // IL, managed
1562
_assembly.get_or_add_string("{overridee.owner?.qualified_name}.{SRM_FLAGS.method_name(overridee)}"),
1563
_assembly.get_or_add_blob(_signatures.instantiated_method_signature(overridee)),
1564
body.flush(_assembly),
1565
MetadataTokens.parameter_handle(_assembly.next_parameter_row))
1566
1567
_mark_compiler_generated(cast EntityHandle(definition))
1568
1569
result.add(
1570
SRM_BOUND_METHOD(
1571
cast EntityHandle(definition),
1572
context.resolve_call_target(overridee)))
1573
od
1574
1575
return result
1576
si
1577
1578
// The body of a legacy bridge: read the generic member the
1579
// trait declares and hand back what it returns. The call is
1580
// virtual on a class, so a subclass overriding the generic
1581
// member is reached through the bridge its base declares, and
1582
// direct on a struct, which has no slot to dispatch through.
1583
// A value the interface types as object is boxed, which a type
1584
// parameter needs as much as a struct does.
1585
_forward_to_generic(
1586
type: SRM_EMITTED_TYPE,
1587
member_name: string,
1588
wants_object: bool
1589
) -> SRM_METHOD_BODY_EMITTER is
1590
let body = SRM_METHOD_BODY_EMITTER()
1591
1592
let frame_member =
1593
if wants_object then FrameMember.GET_CURRENT else FrameMember.GET_ENUMERATOR fi
1594
1595
if _frame_enumerator_members.contains_key(frame_member) then
1596
body.ldarg(0)
1597
body.call_virtual(_frame_enumerator_members[frame_member])
1598
1599
if wants_object then
1600
if let element = _frame_element_type /\ (element.is_value_type \/ element.is_type_variable) then
1601
body.box(IoC.CONTAINER.instance.ir_context.resolve_type_token(element))
1602
fi
1603
fi
1604
1605
body.ret()
1606
1607
return body
1608
fi
1609
1610
let read = _generic_reader(type, member_name)
1611
1612
if !read? then
1613
body.ldnull()
1614
body.ret()
1615
1616
return body
1617
fi
1618
1619
body.ldarg(0)
1620
1621
let target = IoC.CONTAINER.instance.ir_context.resolve_call_target(read)
1622
1623
if isa Semantic.Symbols.STRUCT_METHOD(read) then
1624
body.call(target)
1625
else
1626
body.call_virtual(target)
1627
fi
1628
1629
if wants_object then
1630
if let returns = read.return_type /\ (returns.is_value_type \/ returns.is_type_variable) then
1631
body.box(IoC.CONTAINER.instance.ir_context.resolve_type_token(returns))
1632
fi
1633
fi
1634
1635
body.ret()
1636
1637
return body
1638
si
1639
1640
_generic_reader(type: SRM_EMITTED_TYPE, member_name: string)
1641
-> Semantic.Symbols.Function?
1642
is
1643
if let declared = type.declared then
1644
if let property: Semantic.Symbols.Property =
1645
declared.find_member(member_name)
1646
then
1647
return property.read_function
1648
fi
1649
fi
1650
1651
return null
1652
si
1653
1654
// Whether a type's own interface list reaches `trait`. A type
1655
// that only inherits the implementation from its base is
1656
// excluded: the base's own bridge already fills the slot and
1657
// dispatches back through the generic member, and a MethodImpl
1658
// here would name an interface this type does not declare,
1659
// which a trimmer rejects.
1660
_declares_trait(type: Classy, sought: Semantic.Types.Type) -> bool static is
1661
for ancestor in type.ancestors do
1662
if !ancestor.is_trait then
1663
continue
1664
fi
1665
1666
if ancestor.find_ancestor(sought)? then
1667
return true
1668
fi
1669
od
1670
1671
return false
1672
si
1673
1674
// One explicit-implementation member: the row, its body, and
1675
// the interface member it answers for, which the MethodImpl row
1676
// binds it to once the type has a handle.
1677
_write_explicit_implementation(
1678
name: string,
1679
signature: ubyte[],
1680
is_special_name: bool,
1681
interface_namespace: string,
1682
interface_name: string,
1683
member_name: string,
1684
member_signature: ubyte[],
1685
body: SRM_METHOD_BODY_EMITTER
1686
) -> SRM_BOUND_METHOD is
1687
1688
let definition =
1689
_assembly.add_method_definition(
1690
SRM_FLAGS.explicit_implementation_attributes(is_special_name),
1691
cast System.Reflection.MethodImplAttributes(0), // IL, managed
1692
_assembly.get_or_add_string(name),
1693
_assembly.get_or_add_blob(signature),
1694
body.flush(_assembly),
1695
MetadataTokens.parameter_handle(_assembly.next_parameter_row))
1696
1697
_mark_compiler_generated(cast EntityHandle(definition))
1698
1699
let `interface =
1700
_assembly.add_type_reference_by_name(
1701
"System.Runtime", interface_namespace, interface_name)
1702
1703
let declaration =
1704
_assembly.add_named_member_reference(
1705
cast EntityHandle(`interface),
1706
member_name,
1707
"{interface_namespace}.{interface_name}::{member_name}",
1708
member_signature)
1709
1710
return SRM_BOUND_METHOD(
1711
cast EntityHandle(definition),
1712
cast EntityHandle(declaration))
1713
si
1714
1715
// The traits a type declares, in declaration order, each named
1716
// by a handle the InterfaceImpl row can carry, paired with the
1717
// ancestor type itself so the caller can compute the row's
1718
// nullability attribute.
1719
//
1720
// `ancestors` mixes the superclass in with the traits, so the
1721
// superclass is filtered back out here.
1722
_interfaces(type: Classy) -> Collections.List[SRM_INTERFACE_ANCESTOR] is
1723
let result = Collections.LIST[SRM_INTERFACE_ANCESTOR]()
1724
1725
for ancestor in type.ancestors do
1726
if !ancestor.is_trait then
1727
continue
1728
fi
1729
1730
result.add(SRM_INTERFACE_ANCESTOR(_type_token(ancestor), ancestor))
1731
od
1732
1733
return result
1734
si
1735
1736
// A type named in a row rather than in a signature. A
1737
// constructed generic has no row of its own and is named by a
1738
// specification carrying its shape; anything else resolves to
1739
// its own TypeDef row, or to an imported reference.
1740
//
1741
// The same choice as IR.CONTEXT.resolve_type_token, which the
1742
// structure walk cannot reach: it runs without an IR context.
1743
_type_token(type: Semantic.Types.Type) -> EntityHandle is
1744
// A type variable has no row of its own either: it is named
1745
// by position, which only a signature can express. Reached
1746
// by a bound that is itself a type parameter
1747
// (`[TBase: BOX, TDerived: TBase]`).
1748
if type.arguments.count > 0 \/ type.is_type_variable then
1749
return cast EntityHandle(_assembly.add_type_specification(type))
1750
fi
1751
1752
let symbol =
1753
if let generic: Semantic.Symbols.GENERIC = type.symbol then
1754
generic.symbol
1755
else
1756
cast Classy?(type.symbol)
1757
fi
1758
1759
assert symbol? else "cannot name the type '{type}' in a metadata row"
1760
1761
return _type_handle(symbol)
1762
si
1763
1764
// A same-assembly ancestor resolves to its own TypeDef row;
1765
// anything else is an ordinary imported reference.
1766
_type_handle(symbol: Classy) -> EntityHandle is
1767
if let definition = _handles.type_definition(symbol) then
1768
return cast EntityHandle(definition)
1769
fi
1770
1771
return cast EntityHandle(_signatures.type_reference_for(symbol))
1772
si
1773
si
1774
si