Incomplete analysis for the states of global integer variables that does not eliminate excessive equality checks

Aperta
#9,086 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
48/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
kotlin, wasm

Direzione di ricerca

Inizia da kotlin-wasm-benchmarks/src/commonMain/kotlin/microBenchmarks/ParameterNotNullAssertionBenchmark.kt e riproduci il getter generato e la funzione di inizializzazione mostrata nell’issue. Segui l’ottimizzazione che rimuove il blocco try/catch, quindi verifica che il controllo ridondante state == 2 possa essere eliminato senza modificare il comportamento in caso di errore di inizializzazione e che il getter possa ancora essere inlineato nei suoi callsite.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

In kotlin-wasm-benchmarks ParameterNotNullAssertionBenchmark we pass global property
val OBJ = Any()
as several arguments into methods, like
methodWithEightNotnullParameters(OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ).

With the current schema of the initialization in K/Wasm, OBJ getter first calls the function responsible for the initialization of static properties for the whole file - here $"microBenchmarks.<init properties ParameterNotNullAssertionBenchmark.kt>"

  (func $microBenchmarks.<get-OBJ> (;5386;) (type $"#type1038 ") (result (ref null $kotlin.Any))
    call $"microBenchmarks.<init properties ParameterNotNullAssertionBenchmark.kt>"
    global.get $microBenchmarks.OBJ
    return
  )

Initialization function first checks, by the global state
(global $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt" (;5674;) (mut i32) i32.const 1)

  • if the properties were already successfully initialized (value 0) - fast path, just return
  • if previous initialization attempt failed (value 2) - call staticInitializationFailureWithClassName that will throw corresponding error
  • if not initialized (value 1) - call initializers inside try {} catch {} block, so that when the error occur we will be able to catch it and throw corresponding staticInitialization error.
  (func $"microBenchmarks.<init properties ParameterNotNullAssertionBenchmark.kt>" (;5400;) (type $"#type3092 ")
    (local $~state i32) (local $reason (ref null $kotlin.Throwable))
    global.get $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt"
    local.tee $~state
    i32.eqz
    if ;; label = @1  // already successfully initialized, state == 0
      return
    end
    local.get $~state
    i32.const 2
    i32.eq
    if ;; label = @1 // previous initialization attempt failed, state == 2 - throw corresponding error
      ref.null none
      call $kotlin.wasm.internal.staticInitializationFailureWithClassName
      unreachable
    end
    i32.const 0
    global.set $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt" // state = 0
    try ;; label = @1 // try to initialize, catch an error if thrown during initialization
      global.get $"#global6460 <classVTable>"
      ref.null none
      global.get $kotlin.Any_rtti
      i32.const 0
      struct.new $kotlin.Any
      global.set $microBenchmarks.OBJ
    catch 0
      call $kotlin.wasm.internal.getKotlinException
      local.set $reason
      i32.const 2 // state = 2
      global.set $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt"
      local.get $reason
      ref.null none
      call $kotlin.internal.staticInitializationFailure
      unreachable
    end
    nop
  )

Here, initializer for OBJ property is primitive and Binaryen seems to be able to prove that it does not throw an error. So, it removes try/catch block and inlines $"microBenchmarks.<init properties ParameterNotNullAssertionBenchmark.kt>" function into <get-OBJ>.

  (func $microBenchmarks.<get-OBJ> (;2109;) (type 128) (result (ref null $kotlin.Any_125))
    (local i32)
    global.get $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt"
    local.tee 0
    if ;; label = @1 // state != 0
      local.get 0
      i32.const 2
      i32.eq
      if ;; label = @2 // state == 2 - excessive check
        ref.null none
        call $kotlin.wasm.internal.staticInitializationFailureWithClassName
        unreachable
      end
      i32.const 0
      global.set $"microBenchmarks.properties initialized ParameterNotNullAssertionBenchmark.kt"
      global.get $<classVTable>_1501
      ref.null none
      global.get $kotlin.Any_rtti
      i32.const 0
      struct.new $kotlin.Any_125
      global.set $microBenchmarks.OBJf
    end
    global.get $microBenchmarks.OBJ
  )

Since, try/catch block is gone, there is no more assignment state = 2, but there is a check for it. Without this check Binaryen (as we observed) could inline $microBenchmarks.<get-OBJ> into its callsites and speed up the benchmark. Is it feasible to eliminate such kind of checks?

Lingua principale
WebAssembly
Stelle
8.6k
Fork
885
Merge medio
2g 1h
PR unite (30g)
70

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di WebAssembly/binaryen

Tutte le issue di WebAssembly/binaryen

Issue simili

Altre issue su Compilers

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.