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