Differential D3143 Diff 14286 ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCPolicyAPI.h
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCPolicyAPI.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=2 et sw=2 tw=80: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * 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 | * 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/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
// GC Policy Mechanism | // GC Policy Mechanism | ||||
// A GCPolicy controls how the GC interacts with both direct pointers to GC | // A GCPolicy controls how the GC interacts with both direct pointers to GC | ||||
// things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC | // things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC | ||||
// things (e.g. Value or jsid), and C++ container types (e.g. | // things (e.g. Value or jsid), and C++ container types (e.g. | ||||
// JSPropertyDescriptor or GCHashMap). | // JSPropertyDescriptor or GCHashMap). | ||||
// | // | ||||
// The GCPolicy provides at a minimum: | // The GCPolicy provides at a minimum: | ||||
// | // | ||||
// static T initial() | |||||
// - Construct and return an empty T. | |||||
// | |||||
// static void trace(JSTracer, T* tp, const char* name) | // static void trace(JSTracer, T* tp, const char* name) | ||||
// - Trace the edge |*tp|, calling the edge |name|. Containers like | // - Trace the edge |*tp|, calling the edge |name|. Containers like | ||||
// GCHashMap and GCHashSet use this method to trace their children. | // GCHashMap and GCHashSet use this method to trace their children. | ||||
// | // | ||||
// static bool needsSweep(T* tp) | // static bool needsSweep(T* tp) | ||||
// - Return true if |*tp| is about to be finalized. Otherwise, update the | // - Return true if |*tp| is about to be finalized. Otherwise, update the | ||||
// edge for moving GC, and return false. Containers like GCHashMap and | // edge for moving GC, and return false. Containers like GCHashMap and | ||||
// GCHashSet use this method to decide when to remove an entry: if this | // GCHashSet use this method to decide when to remove an entry: if this | ||||
// function returns true on a key/value/member/etc, its entry is dropped | // function returns true on a key/value/member/etc, its entry is dropped | ||||
// from the container. Specializing this method is the standard way to | // from the container. Specializing this method is the standard way to | ||||
// get custom weak behavior from a container type. | // get custom weak behavior from a container type. | ||||
// | // | ||||
// static bool isValid(const T& t) | |||||
// - Return false only if |t| is corrupt in some way. The built-in GC | |||||
// types do some memory layout checks. For debugging only; it is ok | |||||
// to always return true or even to omit this member entirely. | |||||
// | |||||
// The default GCPolicy<T> assumes that T has a default constructor and |trace| | // The default GCPolicy<T> assumes that T has a default constructor and |trace| | ||||
// and |needsSweep| methods, and forwards to them. GCPolicy has appropriate | // and |needsSweep| methods, and forwards to them. GCPolicy has appropriate | ||||
// specializations for pointers to GC things and pointer-like types like | // specializations for pointers to GC things and pointer-like types like | ||||
// JS::Heap<T> and mozilla::UniquePtr<T>. | // JS::Heap<T> and mozilla::UniquePtr<T>. | ||||
// | // | ||||
// There are some stock structs your specializations can inherit from. | // There are some stock structs your specializations can inherit from. | ||||
// IgnoreGCPolicy<T> does nothing. StructGCPolicy<T> forwards the methods to the | // IgnoreGCPolicy<T> does nothing. StructGCPolicy<T> forwards the methods to the | ||||
// referent type T. | // referent type T. | ||||
#ifndef GCPolicyAPI_h | #ifndef GCPolicyAPI_h | ||||
#define GCPolicyAPI_h | #define GCPolicyAPI_h | ||||
#include "mozilla/Maybe.h" | #include "mozilla/Maybe.h" | ||||
#include "mozilla/UniquePtr.h" | #include "mozilla/UniquePtr.h" | ||||
#include "js/TraceKind.h" | #include "js/TraceKind.h" | ||||
#include "js/TracingAPI.h" | #include "js/TracingAPI.h" | ||||
#include "js/TypeDecls.h" | #include "js/TypeDecls.h" | ||||
// Expand the given macro D for each public GC pointer. | // Expand the given macro D for each public GC pointer. | ||||
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ | #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ | ||||
D(JS::Symbol*) \ | D(JS::Symbol*) \ | ||||
D(JS::BigInt*) \ | |||||
D(JSAtom*) \ | D(JSAtom*) \ | ||||
D(JSFunction*) \ | D(JSFunction*) \ | ||||
D(JSObject*) \ | D(JSObject*) \ | ||||
D(JSScript*) \ | D(JSScript*) \ | ||||
D(JSString*) | D(JSString*) | ||||
// Expand the given macro D for each public tagged GC pointer type. | // Expand the given macro D for each public tagged GC pointer type. | ||||
#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \ | #define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \ | ||||
D(JS::Value) \ | D(JS::Value) \ | ||||
D(jsid) | D(jsid) | ||||
#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) D(JSPropertyDescriptor) | #define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) D(JSPropertyDescriptor) | ||||
namespace JS { | namespace JS { | ||||
// Defines a policy for container types with non-GC, i.e. C storage. This | // Defines a policy for container types with non-GC, i.e. C storage. This | ||||
// policy dispatches to the underlying struct for GC interactions. | // policy dispatches to the underlying struct for GC interactions. | ||||
template <typename T> | template <typename T> | ||||
struct StructGCPolicy { | struct StructGCPolicy { | ||||
static T initial() { return T(); } | static_assert(!mozilla::IsPointer<T>::value, | ||||
"Pointer type not allowed for StructGCPolicy"); | |||||
static void trace(JSTracer* trc, T* tp, const char* name) { tp->trace(trc); } | static void trace(JSTracer* trc, T* tp, const char* name) { tp->trace(trc); } | ||||
static void sweep(T* tp) { return tp->sweep(); } | static void sweep(T* tp) { return tp->sweep(); } | ||||
static bool needsSweep(T* tp) { return tp->needsSweep(); } | static bool needsSweep(T* tp) { return tp->needsSweep(); } | ||||
static bool isValid(const T& tp) { return true; } | static bool isValid(const T& tp) { return true; } | ||||
}; | }; | ||||
// The default GC policy attempts to defer to methods on the underlying type. | // The default GC policy attempts to defer to methods on the underlying type. | ||||
// Most C++ structures that contain a default constructor, a trace function and | // Most C++ structures that contain a default constructor, a trace function and | ||||
// a sweep function will work out of the box with Rooted, Handle, GCVector, | // a sweep function will work out of the box with Rooted, Handle, GCVector, | ||||
// and GCHash{Set,Map}. | // and GCHash{Set,Map}. | ||||
template <typename T> | template <typename T> | ||||
struct GCPolicy : public StructGCPolicy<T> {}; | struct GCPolicy : public StructGCPolicy<T> {}; | ||||
// This policy ignores any GC interaction, e.g. for non-GC types. | // This policy ignores any GC interaction, e.g. for non-GC types. | ||||
template <typename T> | template <typename T> | ||||
struct IgnoreGCPolicy { | struct IgnoreGCPolicy { | ||||
static T initial() { return T(); } | |||||
static void trace(JSTracer* trc, T* t, const char* name) {} | static void trace(JSTracer* trc, T* t, const char* name) {} | ||||
static bool needsSweep(T* v) { return false; } | static bool needsSweep(T* v) { return false; } | ||||
static bool isValid(const T& v) { return true; } | static bool isValid(const T& v) { return true; } | ||||
}; | }; | ||||
template <> | template <> | ||||
struct GCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {}; | struct GCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {}; | ||||
template <> | template <> | ||||
struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {}; | struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {}; | ||||
template <typename T> | template <typename T> | ||||
struct GCPointerPolicy { | struct GCPointerPolicy { | ||||
static T initial() { return nullptr; } | static_assert(mozilla::IsPointer<T>::value, | ||||
"Non-pointer type not allowed for GCPointerPolicy"); | |||||
static void trace(JSTracer* trc, T* vp, const char* name) { | static void trace(JSTracer* trc, T* vp, const char* name) { | ||||
if (*vp) js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); | if (*vp) { | ||||
js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); | |||||
} | |||||
} | } | ||||
static bool needsSweep(T* vp) { | static bool needsSweep(T* vp) { | ||||
if (*vp) return js::gc::IsAboutToBeFinalizedUnbarriered(vp); | if (*vp) { | ||||
return js::gc::IsAboutToBeFinalizedUnbarriered(vp); | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } | static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } | ||||
}; | }; | ||||
template <> | #define EXPAND_SPECIALIZE_GCPOLICY(Type) \ | ||||
struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {}; | template <> \ | ||||
template <> | struct GCPolicy<Type> : public GCPointerPolicy<Type> {}; \ | ||||
struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {}; | template <> \ | ||||
template <> | struct GCPolicy<Type const> : public GCPointerPolicy<Type const> {}; | ||||
struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {}; | FOR_EACH_PUBLIC_GC_POINTER_TYPE(EXPAND_SPECIALIZE_GCPOLICY) | ||||
template <> | #undef EXPAND_SPECIALIZE_GCPOLICY | ||||
struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {}; | |||||
template <> | |||||
struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {}; | |||||
template <> | |||||
struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {}; | |||||
template <typename T> | template <typename T> | ||||
struct NonGCPointerPolicy { | struct NonGCPointerPolicy { | ||||
static T initial() { return nullptr; } | |||||
static void trace(JSTracer* trc, T* vp, const char* name) { | static void trace(JSTracer* trc, T* vp, const char* name) { | ||||
if (*vp) (*vp)->trace(trc); | if (*vp) { | ||||
(*vp)->trace(trc); | |||||
} | |||||
} | } | ||||
static bool needsSweep(T* vp) { | static bool needsSweep(T* vp) { | ||||
if (*vp) return (*vp)->needsSweep(); | if (*vp) { | ||||
return (*vp)->needsSweep(); | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
static bool isValid(T v) { return true; } | static bool isValid(T v) { return true; } | ||||
}; | }; | ||||
template <typename T> | template <typename T> | ||||
struct GCPolicy<JS::Heap<T>> { | struct GCPolicy<JS::Heap<T>> { | ||||
static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) { | static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) { | ||||
TraceEdge(trc, thingp, name); | TraceEdge(trc, thingp, name); | ||||
} | } | ||||
static bool needsSweep(JS::Heap<T>* thingp) { | static bool needsSweep(JS::Heap<T>* thingp) { | ||||
return *thingp && js::gc::EdgeNeedsSweep(thingp); | return *thingp && js::gc::EdgeNeedsSweep(thingp); | ||||
} | } | ||||
}; | }; | ||||
// GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>. | // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>. | ||||
template <typename T, typename D> | template <typename T, typename D> | ||||
struct GCPolicy<mozilla::UniquePtr<T, D>> { | struct GCPolicy<mozilla::UniquePtr<T, D>> { | ||||
static mozilla::UniquePtr<T, D> initial() { | |||||
return mozilla::UniquePtr<T, D>(); | |||||
} | |||||
static void trace(JSTracer* trc, mozilla::UniquePtr<T, D>* tp, | static void trace(JSTracer* trc, mozilla::UniquePtr<T, D>* tp, | ||||
const char* name) { | const char* name) { | ||||
if (tp->get()) GCPolicy<T>::trace(trc, tp->get(), name); | if (tp->get()) { | ||||
GCPolicy<T>::trace(trc, tp->get(), name); | |||||
} | |||||
} | } | ||||
static bool needsSweep(mozilla::UniquePtr<T, D>* tp) { | static bool needsSweep(mozilla::UniquePtr<T, D>* tp) { | ||||
if (tp->get()) return GCPolicy<T>::needsSweep(tp->get()); | if (tp->get()) { | ||||
return GCPolicy<T>::needsSweep(tp->get()); | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
static bool isValid(const mozilla::UniquePtr<T, D>& t) { | static bool isValid(const mozilla::UniquePtr<T, D>& t) { | ||||
if (t.get()) return GCPolicy<T>::isValid(*t.get()); | if (t.get()) { | ||||
return GCPolicy<T>::isValid(*t.get()); | |||||
} | |||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
// GCPolicy<Maybe<T>> forwards tracing/sweeping to GCPolicy<T*> if | // GCPolicy<Maybe<T>> forwards tracing/sweeping to GCPolicy<T*> if | ||||
// when the Maybe<T> is full. | // when the Maybe<T> is full. | ||||
template <typename T> | template <typename T> | ||||
struct GCPolicy<mozilla::Maybe<T>> { | struct GCPolicy<mozilla::Maybe<T>> { | ||||
static mozilla::Maybe<T> initial() { return mozilla::Maybe<T>(); } | |||||
static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) { | static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) { | ||||
if (tp->isSome()) GCPolicy<T>::trace(trc, tp->ptr(), name); | if (tp->isSome()) { | ||||
GCPolicy<T>::trace(trc, tp->ptr(), name); | |||||
} | |||||
} | } | ||||
static bool needsSweep(mozilla::Maybe<T>* tp) { | static bool needsSweep(mozilla::Maybe<T>* tp) { | ||||
if (tp->isSome()) return GCPolicy<T>::needsSweep(tp->ptr()); | if (tp->isSome()) { | ||||
return GCPolicy<T>::needsSweep(tp->ptr()); | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
static bool isValid(const mozilla::Maybe<T>& t) { | static bool isValid(const mozilla::Maybe<T>& t) { | ||||
if (t.isSome()) return GCPolicy<T>::isValid(t.ref()); | if (t.isSome()) { | ||||
return GCPolicy<T>::isValid(t.ref()); | |||||
} | |||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
template <> | template <> | ||||
struct GCPolicy<JS::Realm*>; // see Realm.h | struct GCPolicy<JS::Realm*>; // see Realm.h | ||||
} // namespace JS | } // namespace JS | ||||
#endif // GCPolicyAPI_h | #endif // GCPolicyAPI_h |
Wildfire Games · Phabricator