mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
2c98aaaa09
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
97 lines
2.5 KiB
C++
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 */
|