Skip to content

Missing simple store-to-load forward optimization for globals #8002

@mkustermann

Description

@mkustermann

It's very common that imported objects (e.g. foreign JS objects) get wrapped in a wrapper that integrates into the from-source language type hierarchy. For example a JS string that's imported will be wrapped in Dart via a JSStringImpl - which inherits from Dart's Object (top type) and therefore behaves like a Dart object.

It's very common that such wrapped imported objects are immediately unwrapped. That means the wrapper is unnecessary. It would be very nice if binaryen did remove such wrappers.

See example in global_opt_bad.tar.gz which contains the unoptimized and optimized wasm file. We optimize it via

% wasm-opt --enable-gc --enable-reference-types --enable-multivalue --enable-exception-handling --enable-nontrapping-float-to-int --enable-sign-ext --enable-bulk-memory --enable-threads '--no-inline=*<noInline>*' --closed-world --traps-never-happen --type-unfinalizing -Os --type-ssa --gufa -Os --type-merging -Os --type-finalizing --minimize-rec-groups -g bad.wasm -o bad.opt.wasm 
...
% wami --full-wat bad.opt.wasm -o bad.opt.wat

We can see the following code

  (type $#Top (;0;) (struct (field $field0 i32)))
  (type $JSStringImpl  (sub final $#Top (struct (field $field0 i32) (field $_ref externref))))
  ...
  (global $S.barbaz  (import "S" "barbaz") externref)
  ...
  (global $C329 "barbaz"  (ref $JSStringImpl) (i32.const 4) (global.get $S.barbaz) (struct.new $JSStringImpl))
  ...
  (func $_invokeMain (export "$invokeMain") (param $var0 (ref extern))
      ....
        global.get $C329 "barbaz"
        struct.get $JSStringImpl $_ref
        call $dart2wasm._274 (import)
      ...

Since we struct.get a non-mutable field from a global and the global has simple initializer that just puts an imported global into the field, it should be easy to fold this away into e.g.

  (type $#Top (;0;) (struct (field $field0 i32)))
  (type $JSStringImpl  (sub final $#Top (struct (field $field0 i32) (field $_ref externref))))
  ...
  (global $S.barbaz  (import "S" "barbaz") externref)
  ...
  (func $_invokeMain (export "$invokeMain") (param $var0 (ref extern))
      ....
        (global.get $S.barbaz)
        call $dart2wasm._274 (import)
      ...

This would make code size smaller as well as reduce number of globals.

This pattern occurs quite a lot for us, so it would make a difference if wasm-opt could do this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions