Skip to content
← Back

src/ir/emitter/srm_flags.ghul

1
namespace IR.Emitter is
2
use System.Reflection.TypeAttributes
3
use System.Reflection.MethodAttributes
4
use System.Reflection.FieldAttributes
5
6
use Semantic.Symbols.Classy
7
use Semantic.Symbols.Function
8
use Semantic.Symbols.Field
9
10
// The metadata flag words for a definition, derived from the
11
// symbol's own predicates. Kept together here, and out of the
12
// symbol classes, so what a symbol means and how it is encoded
13
// stay separable.
14
//
15
// Instance methods are emitted virtual without newslot, so a
16
// same-named member in a subclass overrides by name and signature,
17
// which is the dispatch behaviour ghūl source already relies on.
18
class SRM_FLAGS is
19
_PUBLIC_TYPE: int static => 1
20
_INTERFACE: int static => 32
21
_ABSTRACT_TYPE: int static => 128
22
_SEALED: int static => 256
23
_SEQUENTIAL_LAYOUT: int static => 8
24
_BEFORE_FIELD_INIT: int static => 1048576
25
26
type_attributes(type: Classy) -> TypeAttributes static is
27
let flags mut = _PUBLIC_TYPE
28
29
if !type.is_public_readable then
30
flags = 0
31
fi
32
33
if type.is_trait then
34
return cast TypeAttributes(flags | _INTERFACE | _ABSTRACT_TYPE)
35
fi
36
37
// An enum is sealed like any other value type, but takes
38
// auto layout: the runtime treats it as its underlying
39
// scalar, and a sequential-layout enum is rejected as
40
// malformed rather than merely laid out differently.
41
if isa Semantic.Symbols.ENUM_STRUCT(type) then
42
flags = flags | _SEALED
43
elif type.is_value_type then
44
flags = flags | _SEALED | _SEQUENTIAL_LAYOUT
45
elif type.is_abstract then
46
flags = flags | _ABSTRACT_TYPE
47
fi
48
49
// A type declaring its own static constructor must not
50
// carry beforefieldinit, which lets the CLR run the
51
// `.cctor` at an unspecified point before first use rather
52
// than precisely before it.
53
if type.has_static_constructor then
54
return cast TypeAttributes(flags)
55
fi
56
57
return cast TypeAttributes(flags | _BEFORE_FIELD_INIT)
58
si
59
60
globals_carrier_type_attributes() -> TypeAttributes static =>
61
cast TypeAttributes(_PUBLIC_TYPE | _ABSTRACT_TYPE | _SEALED)
62
63
_PRIVATE_METHOD: int static => 1
64
_ASSEMBLY_METHOD: int static => 3
65
_PUBLIC_METHOD: int static => 6
66
_STATIC: int static => 16
67
_FINAL: int static => 32
68
_VIRTUAL: int static => 64
69
_HIDE_BY_SIG: int static => 128
70
_NEW_SLOT: int static => 256
71
_ABSTRACT_METHOD: int static => 1024
72
_SPECIAL_NAME: int static => 2048
73
_RT_SPECIAL_NAME: int static => 4096
74
75
_PINVOKE_IMPL: int static => 0x2000
76
77
method_attributes(method: Function) -> MethodAttributes static is
78
// A `.cctor` is reached by the runtime rather than by any
79
// call site, and only the rtspecialname mark tells it so.
80
// Without it the row is an ordinary static method that
81
// happens to be named `.cctor`, and nothing ever runs it.
82
if method.is_static_constructor then
83
return static_initializer_attributes()
84
fi
85
86
let flags mut =
87
if method.is_public_readable then _PUBLIC_METHOD else _ASSEMBLY_METHOD fi
88
89
flags = flags | _HIDE_BY_SIG
90
91
// A constructor is never virtual: it is reached through the
92
// type it constructs, so there is no slot for a subclass to
93
// take over, and the runtime rejects the combination.
94
if !method.is_emitted_with_receiver then
95
flags = flags | _STATIC
96
elif method.is_virtual /\ !method.is_constructor then
97
flags = flags | _VIRTUAL
98
fi
99
100
// A constructor's IL name is reserved, which is what
101
// rtspecialname asserts; the runtime rejects a `.ctor`
102
// without it.
103
if method.is_constructor then
104
flags = flags | _SPECIAL_NAME | _RT_SPECIAL_NAME
105
elif method.is_internal then
106
flags = flags | _SPECIAL_NAME
107
fi
108
109
// A body-less declaration — an interface member, or an
110
// abstract method — has no body for the row to point at.
111
if method.is_abstract then
112
flags = flags | _ABSTRACT_METHOD | _VIRTUAL
113
fi
114
115
// A method that calls into a shared library: the row points
116
// at no body and the runtime builds the call from the
117
// ImplMap row that names the module and the entry point.
118
if method.pinvoke? then
119
flags = flags | _PINVOKE_IMPL
120
fi
121
122
return cast MethodAttributes(flags)
123
si
124
125
// A state-machine frame's synthesised members. Each satisfies an
126
// interface the frame implements, so each is a newslot virtual;
127
// ToString overrides Object's and takes the slot it already has.
128
frame_member_attributes(member: FrameMember) -> MethodAttributes static is
129
if member == FrameMember.TO_STRING then
130
return cast MethodAttributes(_PUBLIC_METHOD | _VIRTUAL | _HIDE_BY_SIG)
131
fi
132
133
let flags mut =
134
_PUBLIC_METHOD | _FINAL | _VIRTUAL | _HIDE_BY_SIG | _NEW_SLOT
135
136
if member == FrameMember.GET_CURRENT \/ member == FrameMember.GET_ENUMERATOR then
137
flags = flags | _SPECIAL_NAME
138
fi
139
140
return cast MethodAttributes(flags)
141
si
142
143
// An explicit interface implementation: private, because it is
144
// reached only through the interface, and newslot because it
145
// takes a slot of its own rather than overriding anything the
146
// base declares. Final, since a name carrying dots cannot be
147
// overridden by a subclass member anyway.
148
explicit_implementation_attributes(is_special_name: bool) -> MethodAttributes static is
149
let flags mut =
150
_PRIVATE_METHOD | _FINAL | _VIRTUAL | _HIDE_BY_SIG | _NEW_SLOT
151
152
if is_special_name then
153
flags = flags | _SPECIAL_NAME
154
fi
155
156
return cast MethodAttributes(flags)
157
si
158
159
// A method taking a slot of its own rather than the one its name
160
// and signature would find.
161
with_new_slot(attributes: MethodAttributes) -> MethodAttributes static =>
162
cast MethodAttributes(cast int(attributes) | _NEW_SLOT)
163
164
// A static constructor: private, static, and reserved-named.
165
// Shared by a declared `init() static` and by the one the back
166
// end synthesises to intern a unit variant.
167
static_initializer_attributes() -> MethodAttributes static =>
168
cast MethodAttributes(
169
_PRIVATE_METHOD | _HIDE_BY_SIG | _STATIC | _SPECIAL_NAME | _RT_SPECIAL_NAME)
170
171
method_name(method: Function) -> string static => method.il_name
172
173
property_name(property: Semantic.Symbols.Property) -> string static =>
174
property.il_name
175
176
_COVARIANT: int static => 1
177
_CONTRAVARIANT: int static => 2
178
_REFERENCE_TYPE_CONSTRAINT: int static => 4
179
_VALUE_TYPE_CONSTRAINT: int static => 8
180
_DEFAULT_CONSTRUCTOR_CONSTRAINT: int static => 16
181
182
// What a GenericParam row says about one type parameter beyond
183
// its name: which way it varies, which kind of type can
184
// instantiate it, and whether it must be constructible.
185
//
186
// All three are read back by an importing compiler and enforced
187
// by the CLR, so a row left at zero silently turns a covariant
188
// trait invariant and drops a `class`, `struct` or `init` bound.
189
// A bound naming a type is a GenericParamConstraint row instead,
190
// and cannot be expressed here.
191
type_parameter_attributes(
192
variance: Semantic.Types.TypeVariance,
193
constraint: Semantic.Symbols.TypeParameterConstraintKind,
194
has_constructor_constraint: bool
195
) -> System.Reflection.GenericParameterAttributes static is
196
let flags mut = 0
197
198
if has_constructor_constraint then
199
flags = flags | _DEFAULT_CONSTRUCTOR_CONSTRAINT
200
fi
201
202
if variance == Semantic.Types.TypeVariance.COVARIANT then
203
flags = flags | _COVARIANT
204
elif variance == Semantic.Types.TypeVariance.CONTRAVARIANT then
205
flags = flags | _CONTRAVARIANT
206
fi
207
208
// OPTIONAL constrains what the parameter can hold rather
209
// than which kind of type it is, and has no CLR counterpart.
210
if constraint == Semantic.Symbols.TypeParameterConstraintKind.REFERENCE then
211
flags = flags | _REFERENCE_TYPE_CONSTRAINT
212
elif constraint == Semantic.Symbols.TypeParameterConstraintKind.VALUE then
213
flags = flags | _VALUE_TYPE_CONSTRAINT
214
fi
215
216
return cast System.Reflection.GenericParameterAttributes(flags)
217
si
218
219
_PRIVATE_FIELD: int static => 1
220
_ASSEMBLY_FIELD: int static => 3
221
_PUBLIC_FIELD: int static => 6
222
_STATIC_FIELD: int static => 16
223
224
_LITERAL_FIELD: int static => 64
225
_HAS_DEFAULT_FIELD: int static => 32768
226
227
// FieldAttributes numbers these differently from
228
// MethodAttributes, which uses 0x0800 / 0x1000 for the same two
229
// marks.
230
_SPECIAL_NAME_FIELD: int static => 512
231
_RT_SPECIAL_NAME_FIELD: int static => 1024
232
233
unit_variant_instance_attributes() -> FieldAttributes static =>
234
cast FieldAttributes(_PUBLIC_FIELD | _STATIC_FIELD)
235
236
// An enum's members are compile-time constants: each is a static
237
// literal of the enum's own type, whose value lives in a Constant
238
// row rather than in any initializer.
239
enum_member_attributes() -> FieldAttributes static =>
240
cast FieldAttributes(
241
_PUBLIC_FIELD | _STATIC_FIELD | _LITERAL_FIELD | _HAS_DEFAULT_FIELD)
242
243
// The instance field an enum's value is actually stored in. Its
244
// name is fixed by ECMA-335 and the runtime finds it by the
245
// rtspecialname mark rather than by position.
246
enum_value_attributes() -> FieldAttributes static =>
247
cast FieldAttributes(_PUBLIC_FIELD | _SPECIAL_NAME_FIELD | _RT_SPECIAL_NAME_FIELD)
248
249
field_attributes(`field: Field) -> FieldAttributes static is
250
let flags mut =
251
if `field.is_public_readable then _PUBLIC_FIELD else _ASSEMBLY_FIELD fi
252
253
if isa Semantic.Symbols.STATIC_FIELD(`field) \/
254
isa Semantic.Symbols.GLOBAL_VARIABLE(`field)
255
then
256
flags = flags | _STATIC_FIELD
257
fi
258
259
return cast FieldAttributes(flags)
260
si
261
si
262
si