gecko-dev/js/public/RefCounted.h
Ryan Hunt 2c98aaaa09 Bug 1774827 - wasm: Add RecGroup and implement canonicalization of all types. r=yury
This commit adds explicit recursion groups and implements type equality using
canonicalization as specified in the GC proposal.

For the following example:
  0: (struct)
  (rec
  1:  (struct (ref 0))
  2:  (struct (ref 1))
  )
  (rec
  3:  (struct (ref 0))
  4:  (struct (ref 3))
  )

Type equality is done primarily on a recursion group basis.
The first and second explicit rec's are equal, causing the types within them
to be pairwise equal.

Equality is given by the following transformation of the recs to have 'back edges'
to their local recursion group made explicit. The rest of the equality can be
done in a bottom up (inductive) manner.

  (rec
  1:  (struct (ref nonrecursive 0))
  2:  (struct (ref recursive 0))
  )
  (rec
  3:  (struct (ref nonrecursive 0))
  4:  (struct (ref recursive 0))
  )

With this example, you can see that transforming the 'local' edges to a normalized
format allows equality to done by simple comparison.

The biggest change in this commit is to how we store and create type definitions:
  1. TypeDef is now stored inline in a containing RecGroup class
  2. TypeContext now has a 'startRecGroup' and 'endRecGroup' method for building
     rec groups.

There are several other changes required too:
  1. Serialization/deserialization now operates on recursion groups, not type defs
  2. (oom handling fix) Serialization/deserialization initializes refptr's at the correct type
  3. Canonicalization of function types (which existed already for MVP) is now generalized to
     to support canonicalization of all types.

Differential Revision: https://phabricator.services.mozilla.com/D159057
2022-11-04 13:26:40 +00:00

97 lines
2.5 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_RefCounted_h
#define js_RefCounted_h
#include "mozilla/Atomics.h"
#include "mozilla/RefCountType.h"
#include "js/Utility.h"
// These types implement the same interface as mozilla::(Atomic)RefCounted and
// must be used instead of mozilla::(Atomic)RefCounted for everything in
// SpiderMonkey. There are two reasons:
// - Release() needs to call js_delete, not delete
// - SpiderMonkey does not have MOZILLA_INTERNAL_API defined which can lead
// to ODR violations that show up as spurious leak reports when ref-counted
// types are allocated by SpiderMonkey and released by Gecko (or vice versa).
namespace js {
template <typename T>
class RefCounted {
static const MozRefCountType DEAD = 0xffffdead;
protected:
RefCounted() : mRefCnt(0) {}
~RefCounted() { MOZ_ASSERT(mRefCnt == DEAD); }
public:
void AddRef() const {
MOZ_ASSERT(int32_t(mRefCnt) >= 0);
++mRefCnt;
}
void Release() const {
MOZ_ASSERT(int32_t(mRefCnt) > 0);
MozRefCountType cnt = --mRefCnt;
if (0 == cnt) {
#ifdef DEBUG
mRefCnt = DEAD;
#endif
js_delete(const_cast<T*>(static_cast<const T*>(this)));
}
}
private:
mutable MozRefCountType mRefCnt;
};
template <typename T>
class AtomicRefCounted {
// On 64-bit systems, if the refcount type is small (say, 32 bits), there's
// a risk that it could overflow. So require it to be large enough.
static_assert(sizeof(MozRefCountType) == sizeof(uintptr_t),
"You're at risk for ref count overflow.");
static const MozRefCountType DEAD = ~MozRefCountType(0xffff) | 0xdead;
protected:
AtomicRefCounted() = default;
~AtomicRefCounted() { MOZ_ASSERT(mRefCnt == DEAD); }
public:
void AddRef() const {
++mRefCnt;
MOZ_ASSERT(mRefCnt != DEAD);
}
void Release() const {
MOZ_ASSERT(mRefCnt != 0);
MozRefCountType cnt = --mRefCnt;
if (0 == cnt) {
#ifdef DEBUG
mRefCnt = DEAD;
#endif
js_delete(const_cast<T*>(static_cast<const T*>(this)));
}
}
bool hasOneRef() const {
MOZ_ASSERT(mRefCnt > 0);
return mRefCnt == 1;
}
private:
mutable mozilla::Atomic<MozRefCountType> mRefCnt{0};
};
} // namespace js
#endif /* js_RefCounted_h */