Bug 1128110 - Share common operators on pointer-like GC classes; r=sfink

This commit is contained in:
Terrence Cole 2015-02-04 15:27:00 -08:00
Родитель a15d9e4060
Коммит 77089204b6
10 изменённых файлов: 120 добавлений и 201 удалений

Просмотреть файл

@ -138,11 +138,11 @@ public:
JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); }
void SetUncompiled(UncompiledT* source) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(source));
wrapper() = nsXBLMaybeCompiled<UncompiledT>(source);
}
void SetJSFunction(JSObject* function) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(function));
wrapper() = nsXBLMaybeCompiled<UncompiledT>(function);
}
JS::Heap<JSObject*>& AsHeapObject()

Просмотреть файл

@ -145,6 +145,41 @@ template<typename T>
struct PersistentRootedMarker;
} /* namespace gc */
#define DECLARE_POINTER_COMPARISON_OPS(T) \
bool operator==(const T &other) const { return get() == other; } \
bool operator!=(const T &other) const { return get() != other; }
// Important: Return a reference so passing a Rooted<T>, etc. to
// something that takes a |const T&| is not a GC hazard.
#define DECLARE_POINTER_CONSTREF_OPS(T) \
operator const T &() const { return get(); } \
const T &operator->() const { return get(); }
// Assignment operators on a base class are hidden by the implicitly defined
// operator= on the derived class. Thus, define the operator= directly on the
// class as we would need to manually pass it through anyway.
#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
Wrapper<T> &operator=(const T &p) { \
set(p); \
return *this; \
} \
Wrapper<T> &operator=(const Wrapper<T> &other) { \
set(other.get()); \
return *this; \
} \
#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \
template <typename S> Wrapper<T> &operator=(S) = delete; \
Wrapper<T> &operator=(const Wrapper<T> &) = delete;
#define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \
const T *address() const { return &(ptr); } \
const T &get() const { return (ptr); } \
#define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \
T *address() { return &(ptr); } \
T &get() { return (ptr); } \
} /* namespace js */
namespace JS {
@ -227,42 +262,12 @@ class Heap : public js::HeapBase<T>
relocate();
}
bool operator==(const Heap<T> &other) { return ptr == other.ptr; }
bool operator!=(const Heap<T> &other) { return ptr != other.ptr; }
bool operator==(const T &other) const { return ptr == other; }
bool operator!=(const T &other) const { return ptr != other; }
operator T() const { return ptr; }
T operator->() const { return ptr; }
const T *address() const { return &ptr; }
const T &get() const { return ptr; }
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(Heap, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
T *unsafeGet() { return &ptr; }
Heap<T> &operator=(T p) {
set(p);
return *this;
}
Heap<T> &operator=(const Heap<T>& other) {
set(other.get());
return *this;
}
void set(T newPtr) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
if (js::GCMethods<T>::needsPostBarrier(newPtr)) {
ptr = newPtr;
post();
} else if (js::GCMethods<T>::needsPostBarrier(ptr)) {
relocate(); /* Called before overwriting ptr. */
ptr = newPtr;
} else {
ptr = newPtr;
}
}
/*
* Set the pointer to a value which will cause a crash if it is
* dereferenced.
@ -283,6 +288,19 @@ class Heap : public js::HeapBase<T>
post();
}
void set(T newPtr) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
if (js::GCMethods<T>::needsPostBarrier(newPtr)) {
ptr = newPtr;
post();
} else if (js::GCMethods<T>::needsPostBarrier(ptr)) {
relocate(); /* Called before overwriting ptr. */
ptr = newPtr;
} else {
ptr = newPtr;
}
}
void post() {
MOZ_ASSERT(js::GCMethods<T>::needsPostBarrier(ptr));
js::GCMethods<T>::postBarrier(&ptr);
@ -472,30 +490,19 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
Handle(MutableHandle<S> &root,
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
const T *address() const { return ptr; }
const T& get() const { return *ptr; }
/*
* Return a reference so passing a Handle<T> to something that
* takes a |const T&| is not a GC hazard.
*/
operator const T&() const { return get(); }
T operator->() const { return get(); }
bool operator!=(const T &other) const { return *ptr != other; }
bool operator==(const T &other) const { return *ptr == other; }
DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
private:
Handle() {}
DELETE_ASSIGNMENT_OPS(Handle, T);
enum Disambiguator { DeliberatelyChoosingThisOverload = 42 };
enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 };
MOZ_CONSTEXPR Handle(const T *p, Disambiguator, CallerIdentity) : ptr(p) {}
const T *ptr;
template <typename S> void operator=(S) = delete;
void operator=(Handle) = delete;
};
/*
@ -536,23 +543,15 @@ class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
return h;
}
T *address() const { return ptr; }
const T& get() const { return *ptr; }
/*
* Return a reference so passing a MutableHandle<T> to something that takes
* a |const T&| is not a GC hazard.
*/
operator const T&() const { return get(); }
T operator->() const { return get(); }
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
private:
MutableHandle() {}
DELETE_ASSIGNMENT_OPS(MutableHandle, T);
T *ptr;
template <typename S> void operator=(S v) = delete;
void operator=(MutableHandle other) = delete;
};
} /* namespace JS */
@ -786,34 +785,19 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
Rooted<T> *previous() { return reinterpret_cast<Rooted<T>*>(prev); }
/*
* Important: Return a reference here so passing a Rooted<T> to
* something that takes a |const T&| is not a GC hazard.
* This method is public for Rooted so that Codegen.py can use a Rooted
* interchangeably with a MutableHandleValue.
*/
operator const T&() const { return ptr; }
T operator->() const { return ptr; }
T *address() { return &ptr; }
const T *address() const { return &ptr; }
T &get() { return ptr; }
const T &get() const { return ptr; }
T &operator=(T value) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
ptr = value;
return ptr;
}
T &operator=(const Rooted &value) {
ptr = value;
return ptr;
}
void set(T value) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
ptr = value;
}
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr);
private:
/*
@ -895,31 +879,20 @@ class FakeRooted : public RootedBase<T>
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
operator T() const { return ptr; }
T operator->() const { return ptr; }
T *address() { return &ptr; }
const T *address() const { return &ptr; }
T &get() { return ptr; }
const T &get() const { return ptr; }
FakeRooted<T> &operator=(T value) {
MOZ_ASSERT(!GCMethods<T>::poisoned(value));
ptr = value;
return *this;
}
FakeRooted<T> &operator=(const FakeRooted<T> &other) {
MOZ_ASSERT(!GCMethods<T>::poisoned(other.ptr));
ptr = other.ptr;
return *this;
}
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr);
private:
T ptr;
void set(const T &value) {
MOZ_ASSERT(!GCMethods<T>::poisoned(value));
ptr = value;
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
FakeRooted(const FakeRooted &) = delete;
@ -943,21 +916,15 @@ class FakeMutableHandle : public js::MutableHandleBase<T>
*ptr = v;
}
T *address() const { return ptr; }
T get() const { return *ptr; }
operator T() const { return get(); }
T operator->() const { return get(); }
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
private:
FakeMutableHandle() {}
DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T);
T *ptr;
template <typename S>
void operator=(S v) = delete;
void operator=(const FakeMutableHandle<T>& other) = delete;
};
/*
@ -1161,8 +1128,7 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
init(cx, js::GCMethods<T>::initial());
}
void init(JSContext *cx, T initial)
{
void init(JSContext *cx, T initial) {
ptr = initial;
registerWithRuntime(js::GetRuntime(cx));
}
@ -1171,8 +1137,7 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
init(rt, js::GCMethods<T>::initial());
}
void init(JSRuntime *rt, T initial)
{
void init(JSRuntime *rt, T initial) {
ptr = initial;
registerWithRuntime(rt);
}
@ -1184,37 +1149,19 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
}
}
/*
* Important: Return a reference here so passing a Rooted<T> to
* something that takes a |const T&| is not a GC hazard.
*/
operator const T&() const { return ptr; }
T operator->() const { return ptr; }
T *address() { return &ptr; }
const T *address() const { return &ptr; }
T &get() { return ptr; }
const T &get() const { return ptr; }
T &operator=(T value) {
set(value);
return ptr;
}
T &operator=(const PersistentRooted &other) {
set(other.ptr);
return ptr;
}
DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr);
private:
void set(T value) {
MOZ_ASSERT(initialized());
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
ptr = value;
}
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
private:
T ptr;
};
@ -1278,7 +1225,10 @@ CallTraceCallbackOnNonHeap(T *v, const TraceCallbacks &aCallbacks, const char *a
}
} /* namespace gc */
} /* namespace js */
#undef DELETE_ASSIGNMENT_OPS
#undef DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS
#undef DECLARE_NONPOINTER_ACCESSOR_METHODS
#endif /* js_RootingAPI_h */

Просмотреть файл

@ -1757,7 +1757,7 @@ class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); }
void setBarriered(const JS::Value &v) {
static_cast<JS::Heap<JS::Value> *>(this)->set(v);
*static_cast<JS::Heap<JS::Value> *>(this) = v;
}
public:

Просмотреть файл

@ -2092,7 +2092,7 @@ TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &proper
return false;
for (int32_t index = 0; index < typedObj->length(); index++) {
id.set(INT_TO_JSID(index));
id = INT_TO_JSID(index);
properties.infallibleAppend(id);
}
break;
@ -2104,7 +2104,7 @@ TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &proper
return false;
for (size_t index = 0; index < fieldCount; index++) {
id.set(AtomToId(&descr->as<StructTypeDescr>().fieldName(index)));
id = AtomToId(&descr->as<StructTypeDescr>().fieldName(index));
properties.infallibleAppend(id);
}
break;

Просмотреть файл

@ -423,8 +423,8 @@ class BarrieredBase : public BarrieredBaseMixins<T>
this->value = v;
}
bool operator==(const T &other) const { return value == other; }
bool operator!=(const T &other) const { return value != other; }
DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
/* Use this if the automatic coercion to T isn't working. */
const T &get() const { return value; }
@ -437,10 +437,6 @@ class BarrieredBase : public BarrieredBaseMixins<T>
const T *unsafeGet() const { return &value; }
void unsafeSet(T v) { value = v; }
T operator->() const { return value; }
operator const T &() const { return value; }
/* For users who need to manually barrier the raw types. */
static void writeBarrierPre(const T &v) { InternalGCMethods<T>::preBarrier(v); }
static void writeBarrierPost(const T &v, T *vp) { InternalGCMethods<T>::postBarrier(vp); }
@ -483,18 +479,13 @@ class PreBarriered : public BarrieredBase<T>
this->value = nullptr;
}
PreBarriered<T> &operator=(T v) {
DECLARE_POINTER_ASSIGN_OPS(PreBarriered, T);
private:
void set(const T &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
return *this;
}
PreBarriered<T> &operator=(const PreBarriered<T> &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v.value));
this->value = v.value;
return *this;
}
};
@ -524,21 +515,7 @@ class HeapPtr : public BarrieredBase<T>
post();
}
HeapPtr<T> &operator=(T v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
post();
return *this;
}
HeapPtr<T> &operator=(const HeapPtr<T> &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v.value));
this->value = v.value;
post();
return *this;
}
DECLARE_POINTER_ASSIGN_OPS(HeapPtr, T);
protected:
void post() { InternalGCMethods<T>::postBarrier(&this->value); }
@ -551,6 +528,13 @@ class HeapPtr : public BarrieredBase<T>
HeapPtr<T2*> &v2, T2 *val2);
private:
void set(const T &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
post();
}
/*
* Unlike RelocatablePtr<T>, HeapPtr<T> must be managed with GC lifetimes.
* Specifically, the memory used by the pointer itself must be live until
@ -628,7 +612,10 @@ class RelocatablePtr : public BarrieredBase<T>
relocate();
}
RelocatablePtr<T> &operator=(T v) {
DECLARE_POINTER_ASSIGN_OPS(RelocatablePtr, T);
protected:
void set(const T &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
if (GCMethods<T>::needsPostBarrier(v)) {
@ -640,26 +627,8 @@ class RelocatablePtr : public BarrieredBase<T>
} else {
this->value = v;
}
return *this;
}
RelocatablePtr<T> &operator=(const RelocatablePtr<T> &v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v.value));
if (GCMethods<T>::needsPostBarrier(v.value)) {
this->value = v.value;
post();
} else if (GCMethods<T>::needsPostBarrier(this->value)) {
relocate();
this->value = v;
} else {
this->value = v;
}
return *this;
}
protected:
void post() {
MOZ_ASSERT(GCMethods<T>::needsPostBarrier(this->value));
InternalGCMethods<T>::postBarrierRelocate(&this->value);

Просмотреть файл

@ -47,7 +47,7 @@ TestHeapPostBarriers(T initialObj)
JS::Heap<T> *heapData = new JS::Heap<T>();
CHECK(heapData);
CHECK(Passthrough(heapData->get() == nullptr));
heapData->set(initialObj);
*heapData = initialObj;
/* Store the pointer as an integer so that the hazard analysis will miss it. */
uintptr_t initialObjAsInt = uintptr_t(initialObj);

Просмотреть файл

@ -2303,7 +2303,7 @@ DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue va
RootedId id(cx);
if (attrs & JSPROP_INDEX) {
id.set(INT_TO_JSID(intptr_t(name)));
id = INT_TO_JSID(intptr_t(name));
attrs &= ~JSPROP_INDEX;
} else {
JSAtom *atom = Atomize(cx, name, strlen(name));

Просмотреть файл

@ -1389,7 +1389,7 @@ FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class
if (shape->hasSlot()) {
RootedValue v(cx, pobj->as<NativeObject>().getSlot(shape->slot()));
if (v.isObject())
ctor.set(&v.toObject());
ctor = &v.toObject();
}
}

Просмотреть файл

@ -561,7 +561,7 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
stackState[i-1].name,
parentFrame,
stackState[i-1].principals);
parentFrame.set(getOrCreateSavedFrame(cx, lookup));
parentFrame = getOrCreateSavedFrame(cx, lookup);
if (!parentFrame)
return false;
}

Просмотреть файл

@ -431,7 +431,7 @@ js::intrinsic_DefineDataProperty(JSContext *cx, unsigned argc, Value *vp)
PropDesc::Writability writable =
PropDesc::Writability(bool(attributes & ATTR_WRITABLE));
desc.set(PropDesc(value, writable, enumerable, configurable));
desc = PropDesc(value, writable, enumerable, configurable);
bool result;
return StandardDefineProperty(cx, obj, id, desc, true, &result);