-
Notifications
You must be signed in to change notification settings - Fork 814
[Custom Descriptors] Use placeholder describees in GTO #7888
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
Conversation
GTO tries to optimize out unused descriptor types, but sometimes cannot because the descriptor type must remain a descriptor to be a valid supertype of a subtype that will remain a descriptor. To optimize the original described type to not have a descriptor while simultaneously keeping the descriptor a valid supertype, insert a new, trivial placeholder type for the descriptor to describe. Since this new type is not otherwise used in the module, it should be able to be optimized out after subsequent rounds of unsubtyping and other optimizations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
HeapType placeholder = Struct{}; | ||
types.insert( | ||
types.begin(), parent.descriptorsOfPlaceholders.size(), placeholder); | ||
return types; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we need a new hook for this, but I guess using getSortedTypes
works... it has to run before the rebuilding stage.
Co-authored-by: Alon Zakai <azakai@google.com>
Fuzzer found a bug: (module
(rec
(type $0 (sub (func)))
(type $1 (sub (descriptor $2 (struct (field f64) (field i32) (field (ref null $2)) (field (mut i8))))))
(type $2 (sub (describes $1 (struct (field (mut f32)) (field (ref null $0)) (field (mut f64))))))
(type $3 (sub (struct (field eqref))))
(type $4 (sub (array (mut f32))))
)
(type $5 (sub (struct (field f64))))
(rec
(type $6 (sub (array (mut (ref $11)))))
(type $7 (sub (func (param i32 i64 (ref $9) v128) (result (ref null $9)))))
(type $8 (sub final $7 (func (param i32 i64 arrayref v128) (result (ref null $9)))))
(type $9 (array (mut i31ref)))
(type $10 (sub $3 (struct (field (ref null $2)) (field (mut nullref)) (field f32) (field (mut f64)) (field (mut (ref null $12))) (field i64))))
(type $11 (sub final $5 (struct (field f64) (field (mut f32)) (field i32) (field i64) (field (mut i64)) (field i16))))
(type $12 (sub (func (param (ref null $6) v128) (result (ref $0)))))
)
(rec
(type $13 (sub $1 (descriptor $15 (struct (field f64) (field i32) (field (ref $15)) (field (mut i8)) (field (ref null $18))))))
(type $14 (sub final $13 (descriptor $16 (struct (field f64) (field i32) (field (ref $16)) (field (mut i8)) (field nullfuncref) (field (mut (ref eq)))))))
(type $15 (sub $2 (describes $13 (struct (field (mut f32)) (field nullfuncref) (field (mut f64))))))
(type $16 (sub $15 (describes $14 (descriptor $17 (struct (field (mut f32)) (field nullfuncref) (field (mut f64)) (field (mut f64)))))))
(type $17 (sub final $2 (describes $16 (descriptor $19 (struct (field (mut f32)) (field (ref null $20)) (field (mut f64)))))))
(type $18 (sub (func (param (ref $11)) (result anyref))))
(type $19 (sub (describes $17 (struct (field (mut i32)) (field (mut (ref null $0))) (field (mut i64)) (field (mut f32)) (field (mut i16))))))
(type $20 (sub final $0 (func)))
)
(type $21 (func (result f32 (ref null $12) i32 i64 exnref arrayref)))
(global $global$0 (ref (exact $16)) (struct.new_default $16
(struct.new_default $17
(ref.null none)
)
))
(export "func_24" (func $0))
(func $0 (result f32 (ref null $12) i32 i64 exnref arrayref)
(unreachable)
)
)
|
Fuzzer failure I bisected to here, that still fails on
|
Thanks, taking a look now. |
Another that fails on current (module
(type $7 (struct))
(type $8 (sub (array (mut (ref $7)))))
(rec
(type $1 (sub (descriptor $2 (struct))))
(type $5 (sub $1 (descriptor $6 (struct))))
(type $2 (sub (describes $1 (struct))))
(type $6 (sub $2 (describes $5 (struct))))
(type $63 (func (result structref)))
)
(rec
(type $10 (func (param (ref $8)) (result (ref null $14))))
(type $11 (func (result f32)))
(type $12 (sub (func (param (ref $8) v128) (result i64))))
(type $13 (func (param (ref null $11)) (result f64)))
(type $14 (struct (field (mut i8)) (field (mut i32)) (field (ref $11)) (field (ref i31))))
)
(type $69 (func (param externref externref) (result (ref $11))))
(elem declare func $8)
(export "func_20" (func $71))
(func $8 (type $11) (result f32)
(unreachable)
)
(func $58 (type $63) (result structref)
(block $block (result (ref (exact $5)))
(unreachable)
(drop
(struct.new $14
(i32.const 0)
(block (result i32)
(br $block
(struct.new_default $5
(ref.null none)
)
)
(i32.const 0)
)
(ref.func $8)
(ref.i31
(i32.const 0)
)
)
)
(return
(struct.new_default $7)
)
)
)
(func $71 (type $69) (param $0 externref) (param $1 externref) (result (ref $11))
(unreachable)
)
)
|
Wow, what a bug farm. Taking a look. |
GTO tries to optimize out unused descriptor types, but sometimes cannot
because the descriptor type must remain a descriptor to be a valid
supertype of a subtype that will remain a descriptor. To optimize the
original described type to not have a descriptor while simultaneously
keeping the descriptor a valid supertype, insert a new, trivial
placeholder type for the descriptor to describe. Since this new type is
not otherwise used in the module, it should be able to be optimized out
after subsequent rounds of unsubtyping and other optimizations.