Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't generate type IDs for formal generic instances #11167

Conversation

HertzDevil
Copy link
Contributor

@HertzDevil HertzDevil commented Sep 4, 2021

The compiler traverses through every instantiation of a generic class type when it generates unique IDs for every type's metaclass for the Object#class primitive. This includes formal types:

class A(T)
end

class B(T) < A(T) # second `T` is an unbound type parameter referring to the first `T`
  @x : A(T) # unbound type parameter referring to the `T` of `B(T)`
end

# the generated `~metaclass` function references `A(T)` and `A(T).class` where
# `T` refers to the type parameter of the generic `B(T)`, see below

This PR skips those types because they can never be encountered in any real program. This reduces the number of unique types in a blank source file by about 21%; see here for a comparison.

@HertzDevil HertzDevil changed the title Don't generate type IDs for unbound metaclasses Don't generate type IDs for unbound generic instances Sep 4, 2021
@HertzDevil HertzDevil changed the title Don't generate type IDs for unbound generic instances Don't generate type IDs for formal generic instances Sep 4, 2021
@HertzDevil
Copy link
Contributor Author

HertzDevil commented Sep 4, 2021

The ~metaclass LLVM function, which corresponds to Object#class, is implemented by a jump table. Compiled to x86-64 assembly, it looks like this:

.LBB1430_589:
        movl    $822, %eax
        retq

.LBB1430_590:
        movl    $590, %eax
        retq

.LBB1430_591:
        movl    $595, %eax
        retq

.LBB1430_592:
        movl    $598, %eax
        retq

.LBB1430_750:
        movl    $1498, %eax
        retq

.LBB1430_751:
; no code follows

.LJTI1430_0:
        .long   .LBB1430_1-.LJTI1430_0
        .long   .LBB1430_2-.LJTI1430_0
        .long   .LBB1430_3-.LJTI1430_0
; ...
        .long   .LBB1430_589-.LJTI1430_0 ; Value -> Value.class
        .long   .LBB1430_590-.LJTI1430_0 ; Object -> Object.class
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_591-.LJTI1430_0 ; Array(T) -> Array(T).class, T is some type parameter
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_592-.LJTI1430_0 ; Array(T) -> Array(T).class, T is a different type parameter
; ...
        .long   .LBB1430_751-.LJTI1430_0 ; unreachable!
        .long   .LBB1430_750-.LJTI1430_0 ; Proc(Hash(T, Nil), T, Nil) -> Proc(Hash(T, Nil), T, Nil).class
; the table does not actually end with `.LBB1430_751` because it is used only to
; fill in the gaps between the `crystal_instance_type_id`s of various unbound types

"~metaclass":
        movl    %edi, %eax
        movl    %eax, %ecx
        movq    %rcx, -8(%rsp)
        leaq    .LJTI1430_0(%rip), %rax
        movq    -8(%rsp), %rcx
        movslq  (%rax,%rcx,4), %rdx
        addq    %rax, %rdx
        jmpq    *%rdx

A blank source file emits 908 of extra lines in this table (everything after .LBB1430_590), plus code for 160 branch targets. They are all gone, so a fully filtered blank source on Compiler Explorer now contains only ~3.2k lines after this PR.

@straight-shoota straight-shoota added this to the 1.2.0 milestone Sep 6, 2021
@straight-shoota straight-shoota merged commit a0eb3ab into crystal-lang:master Sep 7, 2021
@HertzDevil HertzDevil deleted the refactor/unbound-metaclass-id branch September 8, 2021 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants