diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2021-03-05 14:26:06 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-05 14:26:06 -0800 |
commit | 57619b508d38677844cb482a4034dc985d2cecc6 (patch) | |
tree | 5ab8cd9fa807be2844161bf9db76c031e030297c /src | |
parent | d7cf703bf9c6c9e09a048b976cfb0c5db6a43270 (diff) | |
download | binaryen-57619b508d38677844cb482a4034dc985d2cecc6.tar.gz binaryen-57619b508d38677844cb482a4034dc985d2cecc6.tar.bz2 binaryen-57619b508d38677844cb482a4034dc985d2cecc6.zip |
[effects] Record reads and writes of the GC heap (#3657)
Just as reads and writes to memory can interfere with each other, reads and
writes of GC objects can interfere with each other. This PR adds new `readsHeap`
and `writesHeap` fields to EffectAnalyzer to account for this interference. Note
that memory accesses can never alias with GC heap accesses, so they are
considered separately. Similarly, it would be possible to prove that different
GC heap accesses never interfere with each other based on the accessed types,
but that's left to future work.
Fixes #3655.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/effects.h | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h index d52fcfb15..268a7b4e0 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -71,6 +71,10 @@ public: std::set<Name> globalsWritten; bool readsMemory = false; bool writesMemory = false; + // TODO: Type-based alias analysis. For example, writes to Arrays never + // interfere with reads from Structs. + bool readsHeap = false; + bool writesHeap = false; // A trap, either from an unreachable instruction, or from an implicit trap // that we do not ignore (see below). // Note that we ignore trap differences, so it is ok to reorder traps with @@ -105,6 +109,7 @@ public: return globalsRead.size() + globalsWritten.size() > 0; } bool accessesMemory() const { return calls || readsMemory || writesMemory; } + bool accessesHeap() const { return calls || readsHeap || writesHeap; } // Check whether this may transfer control flow to somewhere outside of this // expression (aside from just flowing out normally). That includes a break // or a throw (if the throw is not known to be caught inside this expression; @@ -143,6 +148,8 @@ public: (other.transfersControlFlow() && hasSideEffects()) || ((writesMemory || calls) && other.accessesMemory()) || ((other.writesMemory || other.calls) && accessesMemory()) || + ((writesHeap || calls) && other.accessesHeap()) || + ((other.writesHeap || other.calls) && accessesHeap()) || (danglingPop || other.danglingPop)) { return true; } @@ -202,6 +209,8 @@ public: calls = calls || other.calls; readsMemory = readsMemory || other.readsMemory; writesMemory = writesMemory || other.writesMemory; + readsHeap = readsHeap || other.readsHeap; + writesHeap = writesHeap || other.writesHeap; trap = trap || other.trap; implicitTrap = implicitTrap || other.implicitTrap; isAtomic = isAtomic || other.isAtomic; @@ -571,12 +580,14 @@ private: void visitRttSub(RttSub* curr) {} void visitStructNew(StructNew* curr) {} void visitStructGet(StructGet* curr) { + parent.readsHeap = true; // traps when the arg is null if (curr->ref->type.isNullable()) { parent.implicitTrap = true; } } void visitStructSet(StructSet* curr) { + parent.writesHeap = true; // traps when the arg is null if (curr->ref->type.isNullable()) { parent.implicitTrap = true; @@ -584,10 +595,12 @@ private: } void visitArrayNew(ArrayNew* curr) {} void visitArrayGet(ArrayGet* curr) { + parent.readsHeap = true; // traps when the arg is null or the index out of bounds parent.implicitTrap = true; } void visitArraySet(ArraySet* curr) { + parent.writesHeap = true; // traps when the arg is null or the index out of bounds parent.implicitTrap = true; } |