Appearance
| 1 | namespace IR.Emitter is | |
| 2 | use System.Reflection.Metadata.BlobBuilder | |
| 3 | use System.Reflection.Metadata.EntityHandle | |
| 4 | use System.Reflection.Metadata.SignatureCallingConvention | |
| 5 | use System.Reflection.Metadata.Ecma335.BlobEncoder | |
| 6 | use System.Reflection.Metadata.Ecma335.MethodSignatureEncoder | |
| 7 | use System.Reflection.Metadata.Ecma335.ReturnTypeEncoder | |
| 8 | use System.Reflection.Metadata.Ecma335.ParametersEncoder | |
| 9 | use System.Reflection.Metadata.Ecma335.SignatureTypeEncoder | |
| 10 | ||
| 11 | // Encodes a function's argument and return types as an ECMA-335 | |
| 12 | // signature blob. | |
| 13 | // | |
| 14 | // The shape mirrors Symbols.Classy.gen_type's decision tree — the | |
| 15 | // il_is_primitive_type short-circuit, then a class-versus-valuetype | |
| 16 | // split, then generic instantiation — with metadata handles in place | |
| 17 | // of the text that path appends. Keeping the two in step matters: | |
| 18 | // a methodref whose signature disagrees with the target's own | |
| 19 | // declaration resolves to nothing at run time. | |
| 20 | class SRM_SIGNATURE_ENCODER(_assembly: SRM_ASSEMBLY_EMITTER) is | |
| 21 | // The innate string and object symbols, resolved once: every | |
| 22 | // signature the assembly emits passes through encode_type. | |
| 23 | _string_symbol: Semantic.Symbols.Symbol? | |
| 24 | _object_symbol: Semantic.Symbols.Symbol? | |
| 25 | ||
| 26 | string_symbol: Semantic.Symbols.Symbol is | |
| 27 | if !_string_symbol? then | |
| 28 | _string_symbol = (cast Semantic.Types.NAMED(IoC.CONTAINER.instance.innate_symbol_lookup.get_string_type())).symbol | |
| 29 | fi | |
| 30 | ||
| 31 | return _string_symbol | |
| 32 | si | |
| 33 | ||
| 34 | object_symbol: Semantic.Symbols.Symbol is | |
| 35 | if !_object_symbol? then | |
| 36 | _object_symbol = (cast Semantic.Types.NAMED(IoC.CONTAINER.instance.innate_symbol_lookup.get_object_type())).symbol | |
| 37 | fi | |
| 38 | ||
| 39 | return _object_symbol | |
| 40 | si | |
| 41 | ||
| 42 | // The closure to install a mapping from while a member of its | |
| 43 | // frame is encoded, or null for a member that needs none. | |
| 44 | // | |
| 45 | // A member's signature is written in its owner's terms, and for | |
| 46 | // a closure frame that does not happen on its own: the frame's | |
| 47 | // type parameters are the enclosing function's symbols, which | |
| 48 | // carry their own method-level position until the closure | |
| 49 | // installs the frame's class-level one. A body is emitted inside | |
| 50 | // that window, so its local signature comes out right unaided. | |
| 51 | // These blobs are not: the structure walk builds them long after | |
| 52 | // the window has closed, and a call site builds them from | |
| 53 | // wherever it happens to be. Without reopening it, a field of | |
| 54 | // `T` encodes as `!!0` on a type whose one parameter is `!0`. | |
| 55 | // | |
| 56 | // The reference the member hangs off is deliberately outside | |
| 57 | // this: it names the frame at the arguments the *caller* passes, | |
| 58 | // which are the caller's own parameters and are spelled where | |
| 59 | // the caller stands. | |
| 60 | // As frame_mapping, but for the member a body is being emitted | |
| 61 | // into rather than a member whose own signature is being written, | |
| 62 | // so a null member (outside any) answers null rather than faulting. | |
| 63 | frame_mapping_for_emission(member: Semantic.Symbols.Symbol?) -> Semantic.Symbols.Closure? static is | |
| 64 | if member? then | |
| 65 | return frame_mapping(member) | |
| 66 | fi | |
| 67 | ||
| 68 | return null | |
| 69 | si | |
| 70 | ||
| 71 | frame_mapping(member: Semantic.Symbols.Symbol) -> Semantic.Symbols.Closure? static is | |
| 72 | // The closure's own method is emitted as a member of its | |
| 73 | // frame, but it is declared into the function the literal | |
| 74 | // was written in, so its owner does not name the frame. A | |
| 75 | // frameless closure needs the mapping too when it captures | |
| 76 | // type arguments: its method-level type parameters are | |
| 77 | // numbered in capture order, so its signature must be | |
| 78 | // written in that space rather than the enclosing | |
| 79 | // function's declaration order. | |
| 80 | if let closure: Semantic.Symbols.Closure = member then | |
| 81 | if closure.frame? \/ closure.captured_type_arguments? then | |
| 82 | return closure | |
| 83 | fi | |
| 84 | fi | |
| 85 | ||
| 86 | if let frame: Semantic.Symbols.FRAME = member.owner then | |
| 87 | return frame.closure | |
| 88 | fi | |
| 89 | ||
| 90 | // The frame's own rows need it too: its type parameters are | |
| 91 | // the enclosing function's symbols, so a bound naming one | |
| 92 | // encodes at that symbol's method-level position unless the | |
| 93 | // frame's class-level one is installed. | |
| 94 | if let frame: Semantic.Symbols.FRAME = member then | |
| 95 | return frame.closure | |
| 96 | fi | |
| 97 | ||
| 98 | return null | |
| 99 | si | |
| 100 | ||
| 101 | // A property's signature is its accessors' shape rather than its | |
| 102 | // own: the calling convention says PROPERTY, and an instance | |
| 103 | // property sets HASTHIS to match the getter it is read through. | |
| 104 | // ghūl declares no indexed properties, so the parameter list is | |
| 105 | // always empty and the signature carries only the type. | |
| 106 | property_signature(property: Semantic.Symbols.Property) -> ubyte[] is | |
| 107 | let builder = BlobBuilder(16) | |
| 108 | ||
| 109 | let return_type: ReturnTypeEncoder mut | |
| 110 | let parameters: ParametersEncoder mut | |
| 111 | ||
| 112 | BlobEncoder(builder) | |
| 113 | .property_signature(_is_instance_property(property)) | |
| 114 | .parameters(0, return_type ref, parameters ref) | |
| 115 | ||
| 116 | encode_type(return_type.`type(false), property.type!) | |
| 117 | ||
| 118 | return builder.to_array() | |
| 119 | si | |
| 120 | ||
| 121 | _is_instance_property(property: Semantic.Symbols.Property) -> bool static => | |
| 122 | isa Semantic.Symbols.INSTANCE_PROPERTY(property) | |
| 123 | ||
| 124 | field_signature(`field: Semantic.Symbols.Field) -> ubyte[] is | |
| 125 | let closure = frame_mapping(`field) | |
| 126 | ||
| 127 | if closure? then | |
| 128 | closure.map_type_arguments() | |
| 129 | fi | |
| 130 | ||
| 131 | try | |
| 132 | let builder = BlobBuilder(16) | |
| 133 | ||
| 134 | // Same recovery as for a method signature: a field | |
| 135 | // inherited from a constructed-generic base in another | |
| 136 | // assembly surfaces via reflection with its type | |
| 137 | // parameter substituted, and the open form is carried as | |
| 138 | // unspecialized_type. Prefer it when present. | |
| 139 | encode_type( | |
| 140 | BlobEncoder(builder).field_signature(), | |
| 141 | `field.unspecialized_type ?? `field.type!) | |
| 142 | ||
| 143 | return builder.to_array() | |
| 144 | finally | |
| 145 | if closure? then | |
| 146 | closure.unmap_type_arguments() | |
| 147 | fi | |
| 148 | yrt | |
| 149 | si | |
| 150 | ||
| 151 | // The same, for a field the back end synthesises and so has no | |
| 152 | // symbol to read a type off. | |
| 153 | field_signature(type: Semantic.Types.Type) -> ubyte[] is | |
| 154 | let builder = BlobBuilder(16) | |
| 155 | ||
| 156 | encode_type(BlobEncoder(builder).field_signature(), type) | |
| 157 | ||
| 158 | return builder.to_array() | |
| 159 | si | |
| 160 | ||
| 161 | // A static constructor's signature: static, void, no arguments. | |
| 162 | static_initializer_signature() -> ubyte[] is | |
| 163 | let builder = BlobBuilder(8) | |
| 164 | ||
| 165 | let return_type: ReturnTypeEncoder mut | |
| 166 | let parameters: ParametersEncoder mut | |
| 167 | ||
| 168 | BlobEncoder(builder) | |
| 169 | .method_signature(SignatureCallingConvention.DEFAULT, 0, false) | |
| 170 | .parameters(0, return_type ref, parameters ref) | |
| 171 | ||
| 172 | return_type.void() | |
| 173 | ||
| 174 | return builder.to_array() | |
| 175 | si | |
| 176 | ||
| 177 | // An instance method taking nothing and returning the given | |
| 178 | // reference type, named by handle rather than by symbol: the | |
| 179 | // members that need this satisfy a framework interface no ghūl | |
| 180 | // declaration mentions. | |
| 181 | nullary_instance_signature(return_type: EntityHandle) -> ubyte[] is | |
| 182 | let builder = BlobBuilder(16) | |
| 183 | ||
| 184 | let return_encoder: ReturnTypeEncoder mut | |
| 185 | let parameters: ParametersEncoder mut | |
| 186 | ||
| 187 | BlobEncoder(builder) | |
| 188 | .method_signature(SignatureCallingConvention.DEFAULT, 0, true) | |
| 189 | .parameters(0, return_encoder ref, parameters ref) | |
| 190 | ||
| 191 | return_encoder.`type(false).`type(return_type, false) | |
| 192 | ||
| 193 | return builder.to_array() | |
| 194 | si | |
| 195 | ||
| 196 | // The same, returning `object`, which has its own element-type | |
| 197 | // code rather than a reference. | |
| 198 | nullary_instance_signature_returning_object() -> ubyte[] is | |
| 199 | let builder = BlobBuilder(16) | |
| 200 | ||
| 201 | let return_encoder: ReturnTypeEncoder mut | |
| 202 | let parameters: ParametersEncoder mut | |
| 203 | ||
| 204 | BlobEncoder(builder) | |
| 205 | .method_signature(SignatureCallingConvention.DEFAULT, 0, true) | |
| 206 | .parameters(0, return_encoder ref, parameters ref) | |
| 207 | ||
| 208 | return_encoder.`type(false).object() | |
| 209 | ||
| 210 | return builder.to_array() | |
| 211 | si | |
| 212 | ||
| 213 | // A constructor's signature: an instance method returning void, | |
| 214 | // taking the given argument types. Built from types rather than | |
| 215 | // from a Function because the constructors that need this are | |
| 216 | // the ones with no symbol to read a signature off. | |
| 217 | constructor_signature(argument_types: Collections.List[Semantic.Types.Type]) -> ubyte[] is | |
| 218 | let builder = BlobBuilder(16) | |
| 219 | ||
| 220 | let return_type: ReturnTypeEncoder mut | |
| 221 | let parameters: ParametersEncoder mut | |
| 222 | ||
| 223 | BlobEncoder(builder) | |
| 224 | .method_signature(SignatureCallingConvention.DEFAULT, 0, true) | |
| 225 | .parameters(argument_types.count, return_type ref, parameters ref) | |
| 226 | ||
| 227 | return_type.void() | |
| 228 | ||
| 229 | for argument in argument_types do | |
| 230 | let referenced = pointee(argument) | |
| 231 | ||
| 232 | encode_type(parameters.add_parameter().`type(referenced?), referenced ?? argument) | |
| 233 | od | |
| 234 | ||
| 235 | return builder.to_array() | |
| 236 | si | |
| 237 | ||
| 238 | // A static method's signature, built from types rather than read | |
| 239 | // off a Function, for the framework members the back end reaches | |
| 240 | // for by name. | |
| 241 | static_signature( | |
| 242 | return_type_of: Semantic.Types.Type, | |
| 243 | argument_types: Collections.List[Semantic.Types.Type] | |
| 244 | ) -> ubyte[] => | |
| 245 | call_signature(return_type_of, argument_types, false) | |
| 246 | ||
| 247 | // The same, for a method reached through a receiver. Built from | |
| 248 | // types rather than from a Function because the members that | |
| 249 | // need it are ones no symbol in the compilation declares. | |
| 250 | call_signature( | |
| 251 | return_type_of: Semantic.Types.Type, | |
| 252 | argument_types: Collections.List[Semantic.Types.Type], | |
| 253 | is_instance: bool | |
| 254 | ) -> ubyte[] is | |
| 255 | let builder = BlobBuilder(16) | |
| 256 | ||
| 257 | let return_type: ReturnTypeEncoder mut | |
| 258 | let parameters: ParametersEncoder mut | |
| 259 | ||
| 260 | BlobEncoder(builder) | |
| 261 | .method_signature(SignatureCallingConvention.DEFAULT, 0, is_instance) | |
| 262 | .parameters(argument_types.count, return_type ref, parameters ref) | |
| 263 | ||
| 264 | encode_return(return_type, return_type_of) | |
| 265 | ||
| 266 | for argument in argument_types do | |
| 267 | let referenced = pointee(argument) | |
| 268 | ||
| 269 | encode_type(parameters.add_parameter().`type(referenced?), referenced ?? argument) | |
| 270 | od | |
| 271 | ||
| 272 | return builder.to_array() | |
| 273 | si | |
| 274 | ||
| 275 | // A constructor on a constructed generic, taking one argument | |
| 276 | // per type parameter. The arguments are written as indexes for | |
| 277 | // the same reason Invoke's are: the reference is to the open | |
| 278 | // type's constructor, and the instantiation lives in the owning | |
| 279 | // TypeSpec. | |
| 280 | generic_constructor_signature(argument_count: int) -> ubyte[] is | |
| 281 | let builder = BlobBuilder(16) | |
| 282 | ||
| 283 | let return_type: ReturnTypeEncoder mut | |
| 284 | let parameters: ParametersEncoder mut | |
| 285 | ||
| 286 | BlobEncoder(builder) | |
| 287 | .method_signature(SignatureCallingConvention.DEFAULT, 0, true) | |
| 288 | .parameters(argument_count, return_type ref, parameters ref) | |
| 289 | ||
| 290 | return_type.void() | |
| 291 | ||
| 292 | for i in 0..argument_count do | |
| 293 | parameters.add_parameter().`type(false).generic_type_parameter(i) | |
| 294 | od | |
| 295 | ||
| 296 | return builder.to_array() | |
| 297 | si | |
| 298 | ||
| 299 | // A delegate's Invoke, whose parameters and return are the | |
| 300 | // delegate type's own type parameters. They are written as | |
| 301 | // indexes rather than as the arguments the delegate was | |
| 302 | // instantiated with: the reference is to Func`N's Invoke, and | |
| 303 | // the instantiation lives in the owning TypeSpec. | |
| 304 | delegate_invoke_signature(argument_count: int, is_action: bool) -> ubyte[] is | |
| 305 | let builder = BlobBuilder(16) | |
| 306 | ||
| 307 | let return_type: ReturnTypeEncoder mut | |
| 308 | let parameters: ParametersEncoder mut | |
| 309 | ||
| 310 | BlobEncoder(builder) | |
| 311 | .method_signature(SignatureCallingConvention.DEFAULT, 0, true) | |
| 312 | .parameters(argument_count, return_type ref, parameters ref) | |
| 313 | ||
| 314 | if is_action then | |
| 315 | return_type.void() | |
| 316 | else | |
| 317 | return_type.`type(false).generic_type_parameter(argument_count) | |
| 318 | fi | |
| 319 | ||
| 320 | for i in 0..argument_count do | |
| 321 | parameters.add_parameter().`type(false).generic_type_parameter(i) | |
| 322 | od | |
| 323 | ||
| 324 | return builder.to_array() | |
| 325 | si | |
| 326 | ||
| 327 | // The blob a TypeSpec row holds: the constructed type encoded | |
| 328 | // structurally, exactly as it would appear inside any other | |
| 329 | // signature. | |
| 330 | type_specification_signature(type: Semantic.Types.Type) -> ubyte[] is | |
| 331 | let builder = BlobBuilder(16) | |
| 332 | ||
| 333 | encode_type(BlobEncoder(builder).type_specification_signature(), type) | |
| 334 | ||
| 335 | return builder.to_array() | |
| 336 | si | |
| 337 | ||
| 338 | method_signature(function: Semantic.Symbols.Function) -> ubyte[] is | |
| 339 | let closure = frame_mapping(function) | |
| 340 | ||
| 341 | if closure? then | |
| 342 | closure.map_type_arguments() | |
| 343 | fi | |
| 344 | ||
| 345 | try | |
| 346 | return _method_signature(function) | |
| 347 | finally | |
| 348 | if closure? then | |
| 349 | closure.unmap_type_arguments() | |
| 350 | fi | |
| 351 | yrt | |
| 352 | si | |
| 353 | ||
| 354 | // A signature in the member's own specialised types, for a | |
| 355 | // definition this assembly writes over a member it takes from an | |
| 356 | // instantiated ancestor. A reference prefers the open form; a | |
| 357 | // definition has no instantiation to resolve the indexes against. | |
| 358 | instantiated_method_signature(function: Semantic.Symbols.Function) -> ubyte[] => | |
| 359 | _method_signature(function, false) | |
| 360 | ||
| 361 | _method_signature(function: Semantic.Symbols.Function) -> ubyte[] => | |
| 362 | _method_signature(function, true) | |
| 363 | ||
| 364 | _method_signature(function: Semantic.Symbols.Function, prefer_open: bool) -> ubyte[] is | |
| 365 | let builder = BlobBuilder(32) | |
| 366 | ||
| 367 | // A method inherited from a constructed-generic base in | |
| 368 | // another assembly surfaces via reflection with its type- | |
| 369 | // parameter references substituted to concrete types, which | |
| 370 | // the CLR will not match at the call site. The open-generic | |
| 371 | // form is recovered at import time (symbol_factory) and | |
| 372 | // carried as unspecialized_*; prefer it when present. | |
| 373 | let arguments = | |
| 374 | if prefer_open then function.unspecialized_arguments ?? function.arguments else function.arguments fi | |
| 375 | ||
| 376 | let return_type: ReturnTypeEncoder mut | |
| 377 | let parameters: ParametersEncoder mut | |
| 378 | ||
| 379 | // A generic method's signature declares its arity, and its | |
| 380 | // own type parameters appear in it as indexes rather than | |
| 381 | // as the arguments some instantiation supplied. | |
| 382 | BlobEncoder(builder) | |
| 383 | .method_signature( | |
| 384 | SignatureCallingConvention.DEFAULT, | |
| 385 | function.generic_arguments.count, | |
| 386 | function.is_emitted_with_receiver) | |
| 387 | .parameters(arguments.count, return_type ref, parameters ref) | |
| 388 | ||
| 389 | encode_return( | |
| 390 | return_type, | |
| 391 | if prefer_open then function.unspecialized_return_type ?? function.return_type else function.return_type fi) | |
| 392 | ||
| 393 | for argument in arguments do | |
| 394 | let referenced = pointee(argument) | |
| 395 | ||
| 396 | encode_type(parameters.add_parameter().`type(referenced?), referenced ?? argument) | |
| 397 | od | |
| 398 | ||
| 399 | return builder.to_array() | |
| 400 | si | |
| 401 | ||
| 402 | // What a `T ref` points at, or null when the type is not a | |
| 403 | // reference. | |
| 404 | // | |
| 405 | // The format carries byref as a flag on the slot rather than as | |
| 406 | // part of the type, so a `T ref` marks its parameter, return or | |
| 407 | // local and encodes the pointee in its own place. Encoding the | |
| 408 | // reference type itself instead names a value type the runtime | |
| 409 | // will not accept where a managed pointer belongs. | |
| 410 | pointee(type: Semantic.Types.Type?) -> Semantic.Types.Type? static => | |
| 411 | if let reference: Semantic.Types.REFERENCE = type then | |
| 412 | reference.arguments[0] | |
| 413 | else | |
| 414 | null | |
| 415 | fi | |
| 416 | ||
| 417 | encode_return(encoder: ReturnTypeEncoder, type: Semantic.Types.Type?) is | |
| 418 | if !type? \/ is_void(type) then | |
| 419 | encoder.void() | |
| 420 | ||
| 421 | return | |
| 422 | fi | |
| 423 | ||
| 424 | let referenced = pointee(type) | |
| 425 | ||
| 426 | encode_type(encoder.`type(referenced?), referenced ?? type) | |
| 427 | si | |
| 428 | ||
| 429 | is_void(type: Semantic.Types.Type) -> bool static => | |
| 430 | type.symbol.il_name_override =~ "void" | |
| 431 | ||
| 432 | encode_type(encoder: SignatureTypeEncoder, type: Semantic.Types.Type) is | |
| 433 | if let array: Semantic.Types.ARRAY = type then | |
| 434 | encode_type(encoder.szarray(), array.arguments[0]) | |
| 435 | ||
| 436 | return | |
| 437 | fi | |
| 438 | ||
| 439 | // A pointer is its own element type in the format, not a | |
| 440 | // generic named `POINTER` over one. Encoding it as the | |
| 441 | // latter names a class the runtime has never heard of, and | |
| 442 | // the slot then holds an object reference where the code | |
| 443 | // reading it expects a native integer. | |
| 444 | if let pointer: Semantic.Types.POINTER = type then | |
| 445 | encode_type(encoder.pointer(), pointer.arguments[0]) | |
| 446 | ||
| 447 | return | |
| 448 | fi | |
| 449 | ||
| 450 | let symbol = type.symbol | |
| 451 | ||
| 452 | if let generic_argument: Semantic.Symbols.GenericArgument = symbol then | |
| 453 | // A body emitted somewhere other than where its type | |
| 454 | // parameters were declared — a state machine's MoveNext, | |
| 455 | // a closure's frame — reaches them at a position the | |
| 456 | // lowering assigns, rather than at their own index. | |
| 457 | if let position = generic_argument.emitted_position then | |
| 458 | if position.is_class_level then | |
| 459 | encoder.generic_type_parameter(position.index) | |
| 460 | else | |
| 461 | encoder.generic_method_type_parameter(position.index) | |
| 462 | fi | |
| 463 | elif isa Semantic.Symbols.FUNCTION_GENERIC_ARGUMENT(generic_argument) then | |
| 464 | encoder.generic_method_type_parameter(generic_argument.index) | |
| 465 | else | |
| 466 | encoder.generic_type_parameter(generic_argument.index) | |
| 467 | fi | |
| 468 | ||
| 469 | return | |
| 470 | fi | |
| 471 | ||
| 472 | if symbol.il_is_primitive_type then | |
| 473 | encode_primitive(encoder, symbol.il_name_override ?? "") | |
| 474 | ||
| 475 | return | |
| 476 | fi | |
| 477 | ||
| 478 | // A constructed generic's symbol is a Symbols.GENERIC, which | |
| 479 | // holds the open definition rather than being one. The | |
| 480 | // format wants that definition as the TypeDefOrRef, with | |
| 481 | // the arguments encoded after it, so the specialization is | |
| 482 | // unwrapped here rather than referenced in its own right. | |
| 483 | let classy = | |
| 484 | if let generic: Semantic.Symbols.GENERIC = symbol then | |
| 485 | generic.symbol | |
| 486 | else | |
| 487 | cast Semantic.Symbols.Classy?(symbol) | |
| 488 | fi | |
| 489 | ||
| 490 | if !classy? then | |
| 491 | throw System.NotImplementedException( | |
| 492 | "the binary back end cannot encode the type '{type}' yet") | |
| 493 | fi | |
| 494 | ||
| 495 | // string and object have dedicated element-type codes rather | |
| 496 | // than a typeref, and il_is_primitive_type does not cover | |
| 497 | // them — neither is a CLR primitive. A signature spelling | |
| 498 | // them as a class reference is well-formed, but no other | |
| 499 | // assembly declares them that way, so a methodref built from | |
| 500 | // one binds to nothing. | |
| 501 | if classy == string_symbol then | |
| 502 | encoder.string() | |
| 503 | ||
| 504 | return | |
| 505 | elif classy == object_symbol then | |
| 506 | encoder.object() | |
| 507 | ||
| 508 | return | |
| 509 | fi | |
| 510 | ||
| 511 | let handle = _type_handle_for(classy) | |
| 512 | ||
| 513 | let arguments = type.arguments | |
| 514 | ||
| 515 | if arguments.count > 0 then | |
| 516 | let generic_arguments = | |
| 517 | encoder.generic_instantiation(handle, arguments.count, classy.is_value_type) | |
| 518 | ||
| 519 | for argument in arguments do | |
| 520 | encode_type(generic_arguments.add_argument(), argument) | |
| 521 | od | |
| 522 | ||
| 523 | return | |
| 524 | fi | |
| 525 | ||
| 526 | encoder.`type(handle, classy.is_value_type) | |
| 527 | si | |
| 528 | ||
| 529 | encode_primitive(encoder: SignatureTypeEncoder, il_name: string) static is | |
| 530 | if il_name =~ "bool" then | |
| 531 | encoder.boolean() | |
| 532 | elif il_name =~ "char" then | |
| 533 | encoder.char() | |
| 534 | elif il_name =~ "int8" then | |
| 535 | encoder.sbyte() | |
| 536 | elif il_name =~ "unsigned int8" then | |
| 537 | encoder.byte() | |
| 538 | elif il_name =~ "int16" then | |
| 539 | encoder.int16() | |
| 540 | elif il_name =~ "unsigned int16" then | |
| 541 | encoder.uint16() | |
| 542 | elif il_name =~ "int32" then | |
| 543 | encoder.int32() | |
| 544 | elif il_name =~ "unsigned int32" then | |
| 545 | encoder.uint32() | |
| 546 | elif il_name =~ "int64" then | |
| 547 | encoder.int64() | |
| 548 | elif il_name =~ "unsigned int64" then | |
| 549 | encoder.uint64() | |
| 550 | elif il_name =~ "native int" then | |
| 551 | encoder.int_ptr() | |
| 552 | elif il_name =~ "native unsigned int" then | |
| 553 | encoder.uint_ptr() | |
| 554 | elif il_name =~ "float32" then | |
| 555 | encoder.single() | |
| 556 | elif il_name =~ "float64" then | |
| 557 | encoder.double() | |
| 558 | else | |
| 559 | throw System.NotImplementedException( | |
| 560 | "the binary back end cannot encode the primitive type '{il_name}' yet") | |
| 561 | fi | |
| 562 | si | |
| 563 | ||
| 564 | // A primitive's il_name_override is the assembler keyword, which | |
| 565 | // is what a signature needs and what a reference must never | |
| 566 | // carry: there is no type called `int32`. Named here so that a | |
| 567 | // member reached through a primitive owner - `to_string` on an | |
| 568 | // `int` - names the type the runtime knows. | |
| 569 | // | |
| 570 | // Written as a chain rather than a `case` because `case` over a | |
| 571 | // string compares by reference, so only interned literals match | |
| 572 | // and a computed name silently falls through. | |
| 573 | clr_name_for_primitive(il_name: string) -> string? static => | |
| 574 | if il_name =~ "bool" then "System.Boolean" | |
| 575 | elif il_name =~ "char" then "System.Char" | |
| 576 | elif il_name =~ "int8" then "System.SByte" | |
| 577 | elif il_name =~ "unsigned int8" then "System.Byte" | |
| 578 | elif il_name =~ "int16" then "System.Int16" | |
| 579 | elif il_name =~ "unsigned int16" then "System.UInt16" | |
| 580 | elif il_name =~ "int32" then "System.Int32" | |
| 581 | elif il_name =~ "unsigned int32" then "System.UInt32" | |
| 582 | elif il_name =~ "int64" then "System.Int64" | |
| 583 | elif il_name =~ "unsigned int64" then "System.UInt64" | |
| 584 | elif il_name =~ "native int" then "System.IntPtr" | |
| 585 | elif il_name =~ "native unsigned int" then "System.UIntPtr" | |
| 586 | elif il_name =~ "float32" then "System.Single" | |
| 587 | elif il_name =~ "float64" then "System.Double" | |
| 588 | elif il_name =~ "void" then "System.Void" | |
| 589 | else null | |
| 590 | fi | |
| 591 | ||
| 592 | // A type this assembly defines is named by its own TypeDef row, | |
| 593 | // not by a reference; every other type resolves to a TypeRef. | |
| 594 | // The TypeDef row need not exist yet — the numbering pass has | |
| 595 | // already fixed which row it will be. | |
| 596 | _type_handle_for(symbol: Semantic.Symbols.Classy) -> EntityHandle is | |
| 597 | if let definition = _assembly.handles.type_definition(symbol) then | |
| 598 | return cast EntityHandle(definition) | |
| 599 | fi | |
| 600 | ||
| 601 | return cast EntityHandle(type_reference_for(symbol)) | |
| 602 | si | |
| 603 | ||
| 604 | type_reference_for(symbol: Semantic.Symbols.Classy) -> System.Reflection.Metadata.TypeReferenceHandle is | |
| 605 | let assembly_name = symbol.il_assembly_name | |
| 606 | ||
| 607 | // An empty name is as absent as a null one, and worse to | |
| 608 | // act on: it yields a reference row the runtime resolves to | |
| 609 | // the assembly being built, so the type appears to be one | |
| 610 | // this assembly defines and fails to load. | |
| 611 | if !assembly_name? \/ assembly_name.length == 0 then | |
| 612 | throw System.NotImplementedException( | |
| 613 | "the binary back end cannot yet reference '{symbol.qualified_name}', " | |
| 614 | "a type defined in the assembly being built") | |
| 615 | fi | |
| 616 | ||
| 617 | _assembly.add_assembly_reference(assembly_name) | |
| 618 | ||
| 619 | return reference_for_clr_name( | |
| 620 | symbol, | |
| 621 | assembly_name, | |
| 622 | symbol.il_name_override ?? symbol.qualified_name) | |
| 623 | si | |
| 624 | ||
| 625 | // One CLR type name to one reference row, for both places that | |
| 626 | // need it: a type named in a signature, and the owner a member | |
| 627 | // reference hangs off. Each used to split the name itself, and | |
| 628 | // only one of the two would ever have learned about nesting. | |
| 629 | // | |
| 630 | // A nested type is written `Outer/Inner`, and each step is a | |
| 631 | // reference of its own scoped to the one before it, with only | |
| 632 | // the outermost carrying a namespace. Flattened into a single | |
| 633 | // row the name resolves to nothing, and the failure surfaces at | |
| 634 | // load rather than at emission. | |
| 635 | reference_for_clr_name( | |
| 636 | symbol: Semantic.Symbols.Symbol, | |
| 637 | assembly_name: string, | |
| 638 | clr_type_name: string | |
| 639 | ) -> System.Reflection.Metadata.TypeReferenceHandle is | |
| 640 | let nested = clr_type_name.index_of('/') | |
| 641 | ||
| 642 | if nested >= 0 then | |
| 643 | let outer_name = clr_type_name.substring(0, nested) | |
| 644 | let outer_dot = outer_name.last_index_of('.') | |
| 645 | ||
| 646 | let enclosing mut = | |
| 647 | _assembly.add_type_reference_by_name( | |
| 648 | assembly_name, | |
| 649 | if outer_dot >= 0 then outer_name.substring(0, outer_dot) else "" fi, | |
| 650 | if outer_dot >= 0 then outer_name.substring(outer_dot + 1) else outer_name fi) | |
| 651 | ||
| 652 | for step in clr_type_name.substring(nested + 1).split(['/']) do | |
| 653 | enclosing = | |
| 654 | _assembly.add_nested_type_reference(assembly_name, enclosing, step) | |
| 655 | od | |
| 656 | ||
| 657 | return enclosing | |
| 658 | fi | |
| 659 | ||
| 660 | let dot = clr_type_name.last_index_of('.') | |
| 661 | ||
| 662 | return _assembly.add_type_reference( | |
| 663 | symbol, | |
| 664 | assembly_name, | |
| 665 | if dot >= 0 then clr_type_name.substring(0, dot) else "" fi, | |
| 666 | if dot >= 0 then clr_type_name.substring(dot + 1) else clr_type_name fi) | |
| 667 | si | |
| 668 | si | |
| 669 | si |