Bug 773049 - Implement the Value interface in MutableHandle<Value> and Rooted<Value> (in addition to Handle<Value> and EncapsulatedValue which already manually implemented it), consolidating the Value interface bits in ValueOperations and MutableValueOperations classes using CRTP. r=bhackett

--HG--
extra : rebase_source : 436385599a7f071792c2d14037e1a1c639427c4f
This commit is contained in:
Jeff Walden 2012-07-12 03:01:59 -07:00
Родитель 3d9aec9dc1
Коммит d63f0497f0
3 изменённых файлов: 149 добавлений и 105 удалений

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

@ -303,7 +303,7 @@ struct HeapPtrHasher
template <class T> template <class T>
struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { }; struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
class EncapsulatedValue class EncapsulatedValue : public ValueOperations<EncapsulatedValue>
{ {
protected: protected:
Value value; Value value;
@ -328,44 +328,20 @@ class EncapsulatedValue
Value *unsafeGet() { return &value; } Value *unsafeGet() { return &value; }
operator const Value &() const { return value; } operator const Value &() const { return value; }
bool isUndefined() const { return value.isUndefined(); }
bool isNull() const { return value.isNull(); }
bool isBoolean() const { return value.isBoolean(); }
bool isTrue() const { return value.isTrue(); }
bool isFalse() const { return value.isFalse(); }
bool isNumber() const { return value.isNumber(); }
bool isInt32() const { return value.isInt32(); }
bool isDouble() const { return value.isDouble(); }
bool isString() const { return value.isString(); }
bool isObject() const { return value.isObject(); }
bool isMagic() const { return value.isMagic(); }
bool isMagic(JSWhyMagic why) const { return value.isMagic(why); }
bool isGCThing() const { return value.isGCThing(); }
bool isMarkable() const { return value.isMarkable(); }
bool toBoolean() const { return value.toBoolean(); }
double toNumber() const { return value.toNumber(); }
int32_t toInt32() const { return value.toInt32(); }
double toDouble() const { return value.toDouble(); }
JSString *toString() const { return value.toString(); }
JSObject &toObject() const { return value.toObject(); }
JSObject *toObjectOrNull() const { return value.toObjectOrNull(); }
void *toGCThing() const { return value.toGCThing(); }
JSGCTraceKind gcKind() const { return value.gcKind(); } JSGCTraceKind gcKind() const { return value.gcKind(); }
uint64_t asRawBits() const { return value.asRawBits(); } uint64_t asRawBits() const { return value.asRawBits(); }
#ifdef DEBUG
JSWhyMagic whyMagic() const { return value.whyMagic(); }
#endif
static inline void writeBarrierPre(const Value &v); static inline void writeBarrierPre(const Value &v);
static inline void writeBarrierPre(JSCompartment *comp, const Value &v); static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
protected: protected:
inline void pre(); inline void pre();
inline void pre(JSCompartment *comp); inline void pre(JSCompartment *comp);
private:
friend class ValueOperations<EncapsulatedValue>;
const Value * extract() const { return &value; }
}; };
class HeapValue : public EncapsulatedValue class HeapValue : public EncapsulatedValue

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

@ -79,13 +79,19 @@ struct NullPtr
static void * const constNullValue; static void * const constNullValue;
}; };
template <typename T>
class HandleBase {};
/* /*
* Reference to a T that has been rooted elsewhere. This is most useful * Reference to a T that has been rooted elsewhere. This is most useful
* as a parameter type, which guarantees that the T lvalue is properly * as a parameter type, which guarantees that the T lvalue is properly
* rooted. See "Move GC Stack Rooting" above. * rooted. See "Move GC Stack Rooting" above.
*
* If you want to add additional methods to Handle for a specific
* specialization, define a HandleBase<T> specialization containing them.
*/ */
template <typename T> template <typename T>
class Handle class Handle : public HandleBase<T>
{ {
public: public:
/* Creates a handle from a handle of a type convertible to T. */ /* Creates a handle from a handle of a type convertible to T. */
@ -139,10 +145,6 @@ class Handle
void operator =(S v) MOZ_DELETE; void operator =(S v) MOZ_DELETE;
}; };
/* Defined in jsapi.h under Value definition */
template <>
class Handle<Value>;
typedef Handle<JSObject*> HandleObject; typedef Handle<JSObject*> HandleObject;
typedef Handle<JSFunction*> HandleFunction; typedef Handle<JSFunction*> HandleFunction;
typedef Handle<JSScript*> HandleScript; typedef Handle<JSScript*> HandleScript;
@ -150,12 +152,19 @@ typedef Handle<JSString*> HandleString;
typedef Handle<jsid> HandleId; typedef Handle<jsid> HandleId;
typedef Handle<Value> HandleValue; typedef Handle<Value> HandleValue;
template <typename T>
class MutableHandleBase {};
/* /*
* Similar to a handle, but the underlying storage can be changed. This is * Similar to a handle, but the underlying storage can be changed. This is
* useful for outparams. * useful for outparams.
*
* If you want to add additional methods to MutableHandle for a specific
* specialization, define a MutableHandleBase<T> specialization containing
* them.
*/ */
template <typename T> template <typename T>
class MutableHandle class MutableHandle : public MutableHandleBase<T>
{ {
public: public:
template <typename S> template <typename S>
@ -199,13 +208,20 @@ struct RootMethods<T *>
static bool poisoned(T *v) { return IsPoisonedPtr(v); } static bool poisoned(T *v) { return IsPoisonedPtr(v); }
}; };
template <typename T>
class RootedBase {};
/* /*
* Local variable of type T whose value is always rooted. This is typically * Local variable of type T whose value is always rooted. This is typically
* used for local variables, or for non-rooted values being passed to a * used for local variables, or for non-rooted values being passed to a
* function that requires a handle, e.g. Foo(Root<T>(cx, x)). * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
*
* If you want to add additional methods to MutableHandle for a specific
* specialization, define a MutableHandleBase<T> specialization containing
* them.
*/ */
template <typename T> template <typename T>
class Rooted class Rooted : public RootedBase<T>
{ {
void init(JSContext *cx_) void init(JSContext *cx_)
{ {

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

@ -614,75 +614,6 @@ IsPoisonedValue(const Value &v)
/************************************************************************/ /************************************************************************/
/* This is a specialization of the general Handle template in gc/Root.h */
template <>
class Handle<Value>
{
public:
/*
* Construct a handle from an explicitly rooted location. This is the
* normal way to create a handle, and normally happens implicitly.
*/
inline Handle(Rooted<Value> &root) {
ptr = root.address();
}
/*
* This may be called only if the location of the T is guaranteed
* to be marked (for some reason other than being a Rooted),
* e.g., if it is guaranteed to be reachable from an implicit root.
*
* Create a Handle from a raw location of a T.
*/
static Handle fromMarkedLocation(const Value *p) {
Handle h;
h.ptr = p;
return h;
}
const Value *address() const { return ptr; }
const Value &get() const { return *ptr; }
operator const Value &() const { return *ptr; }
bool operator==(const Handle &h) const { return *ptr == *h.ptr; }
bool operator!=(const Handle &h) const { return *ptr != *h.ptr; }
bool isUndefined() const { return ptr->isUndefined(); }
bool isNull() const { return ptr->isNull(); }
bool isBoolean() const { return ptr->isBoolean(); }
bool isTrue() const { return ptr->isTrue(); }
bool isFalse() const { return ptr->isFalse(); }
bool isNumber() const { return ptr->isNumber(); }
bool isInt32() const { return ptr->isInt32(); }
bool isDouble() const { return ptr->isDouble(); }
bool isString() const { return ptr->isString(); }
bool isObject() const { return ptr->isObject(); }
bool isMagic() const { return ptr->isMagic(); }
bool isMagic(JSWhyMagic why) const { return ptr->isMagic(why); }
bool isGCThing() const { return ptr->isGCThing(); }
bool isMarkable() const { return ptr->isMarkable(); }
bool toBoolean() const { return ptr->toBoolean(); }
double toNumber() const { return ptr->toNumber(); }
int32_t toInt32() const { return ptr->toInt32(); }
double toDouble() const { return ptr->toDouble(); }
JSString *toString() const { return ptr->toString(); }
JSObject &toObject() const { return ptr->toObject(); }
JSObject *toObjectOrNull() const { return ptr->toObjectOrNull(); }
void *toGCThing() const { return ptr->toGCThing(); }
#ifdef DEBUG
JSWhyMagic whyMagic() const { return ptr->whyMagic(); }
#endif
private:
Handle() {}
const Value *ptr;
};
/************************************************************************/
static JS_ALWAYS_INLINE Value static JS_ALWAYS_INLINE Value
NullValue() NullValue()
{ {
@ -883,6 +814,8 @@ SameType(const Value &lhs, const Value &rhs)
return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
} }
/************************************************************************/
template <> struct RootMethods<const Value> template <> struct RootMethods<const Value>
{ {
static Value initial() { return UndefinedValue(); } static Value initial() { return UndefinedValue(); }
@ -897,6 +830,125 @@ template <> struct RootMethods<Value>
static bool poisoned(const Value &v) { return IsPoisonedValue(v); } static bool poisoned(const Value &v) { return IsPoisonedValue(v); }
}; };
template <class Outer> class MutableValueOperations;
/*
* A class designed for CRTP use in implementing the non-mutating parts of the
* Value interface in Value-like classes. Outer must be a class inheriting
* ValueOperations<Outer> with a visible extract() method returning the
* const Value* abstracted by Outer.
*/
template <class Outer>
class ValueOperations
{
friend class MutableValueOperations<Outer>;
const Value * value() const { return static_cast<const Outer*>(this)->extract(); }
public:
bool isUndefined() const { return value()->isUndefined(); }
bool isNull() const { return value()->isNull(); }
bool isBoolean() const { return value()->isBoolean(); }
bool isTrue() const { return value()->isTrue(); }
bool isFalse() const { return value()->isFalse(); }
bool isNumber() const { return value()->isNumber(); }
bool isInt32() const { return value()->isInt32(); }
bool isDouble() const { return value()->isDouble(); }
bool isString() const { return value()->isString(); }
bool isObject() const { return value()->isObject(); }
bool isMagic() const { return value()->isMagic(); }
bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); }
bool isMarkable() const { return value()->isMarkable(); }
bool isPrimitive() const { return value()->isPrimitive(); }
bool toBoolean() const { return value()->toBoolean(); }
double toNumber() const { return value()->toNumber(); }
int32_t toInt32() const { return value()->toInt32(); }
double toDouble() const { return value()->toDouble(); }
JSString *toString() const { return value()->toString(); }
JSObject &toObject() const { return value()->toObject(); }
JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
void *toGCThing() const { return value()->toGCThing(); }
#ifdef DEBUG
JSWhyMagic whyMagic() const { return value()->whyMagic(); }
#endif
};
/*
* A class designed for CRTP use in implementing the mutating parts of the
* Value interface in Value-like classes. Outer must be a class inheriting
* MutableValueOperations<Outer> with visible extractMutable() and extract()
* methods returning the const Value* and Value* abstracted by Outer.
*/
template <class Outer>
class MutableValueOperations : public ValueOperations<Outer>
{
Value * value() { return static_cast<Outer*>(this)->extractMutable(); }
public:
void setNull() { value()->setNull(); }
void setUndefined() { value()->setUndefined(); }
void setInt32(int32_t i) { value()->setInt32(i); }
void setDouble(double d) { value()->setDouble(d); }
void setString(JSString *str) { value()->setString(str); }
void setString(const JS::Anchor<JSString *> &str) { value()->setString(str); }
void setObject(JSObject &obj) { value()->setObject(obj); }
void setBoolean(bool b) { value()->setBoolean(b); }
void setMagic(JSWhyMagic why) { value()->setMagic(why); }
bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
bool setNumber(double d) { return value()->setNumber(d); }
void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(); }
};
/*
* Augment the generic Handle<T> interface when T = Value with type-querying
* and value-extracting operations.
*/
template <>
class HandleBase<Value> : public ValueOperations<Handle<Value> >
{
friend class ValueOperations<Handle<Value> >;
const Value * extract() const {
return static_cast<const Handle<Value>*>(this)->address();
}
};
/*
* Augment the generic MutableHandle<T> interface when T = Value with
* type-querying, value-extracting, and mutating operations.
*/
template <>
class MutableHandleBase<Value> : public MutableValueOperations<MutableHandle<Value> >
{
friend class ValueOperations<Handle<Value> >;
const Value * extract() const {
return static_cast<const MutableHandle<Value>*>(this)->address();
}
friend class MutableValueOperations<Handle<Value> >;
Value * extractMutable() {
return static_cast<MutableHandle<Value>*>(this)->address();
}
};
/*
* Augment the generic Rooted<T> interface when T = Value with type-querying,
* value-extracting, and mutating operations.
*/
template <>
class RootedBase<Value> : public MutableValueOperations<Rooted<Value> >
{
friend class ValueOperations<Rooted<Value> >;
const Value * extract() const {
return static_cast<const Rooted<Value>*>(this)->address();
}
friend class MutableValueOperations<Handle<Value> >;
Value * extractMutable() {
return static_cast<Rooted<Value>*>(this)->address();
}
};
/************************************************************************/ /************************************************************************/
#ifndef __GNUC__ #ifndef __GNUC__