diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index bc551e9bde0e..08c8de8f0d73 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -303,7 +303,7 @@ struct HeapPtrHasher template struct DefaultHasher< HeapPtr > : HeapPtrHasher { }; -class EncapsulatedValue +class EncapsulatedValue : public ValueOperations { protected: Value value; @@ -328,44 +328,20 @@ class EncapsulatedValue Value *unsafeGet() { 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(); } 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(JSCompartment *comp, const Value &v); protected: inline void pre(); inline void pre(JSCompartment *comp); + + private: + friend class ValueOperations; + const Value * extract() const { return &value; } }; class HeapValue : public EncapsulatedValue diff --git a/js/src/gc/Root.h b/js/src/gc/Root.h index 6052dd301c12..722088694128 100644 --- a/js/src/gc/Root.h +++ b/js/src/gc/Root.h @@ -79,13 +79,19 @@ struct NullPtr static void * const constNullValue; }; +template +class HandleBase {}; + /* * 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 * rooted. See "Move GC Stack Rooting" above. + * + * If you want to add additional methods to Handle for a specific + * specialization, define a HandleBase specialization containing them. */ template -class Handle +class Handle : public HandleBase { public: /* Creates a handle from a handle of a type convertible to T. */ @@ -139,10 +145,6 @@ class Handle void operator =(S v) MOZ_DELETE; }; -/* Defined in jsapi.h under Value definition */ -template <> -class Handle; - typedef Handle HandleObject; typedef Handle HandleFunction; typedef Handle HandleScript; @@ -150,12 +152,19 @@ typedef Handle HandleString; typedef Handle HandleId; typedef Handle HandleValue; +template +class MutableHandleBase {}; + /* * Similar to a handle, but the underlying storage can be changed. This is * useful for outparams. + * + * If you want to add additional methods to MutableHandle for a specific + * specialization, define a MutableHandleBase specialization containing + * them. */ template -class MutableHandle +class MutableHandle : public MutableHandleBase { public: template @@ -199,13 +208,20 @@ struct RootMethods static bool poisoned(T *v) { return IsPoisonedPtr(v); } }; +template +class RootedBase {}; + /* * 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 * function that requires a handle, e.g. Foo(Root(cx, x)). + * + * If you want to add additional methods to MutableHandle for a specific + * specialization, define a MutableHandleBase specialization containing + * them. */ template -class Rooted +class Rooted : public RootedBase { void init(JSContext *cx_) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 8c65cc908238..23405e0fae20 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -614,75 +614,6 @@ IsPoisonedValue(const Value &v) /************************************************************************/ -/* This is a specialization of the general Handle template in gc/Root.h */ -template <> -class Handle -{ - 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 &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 NullValue() { @@ -883,6 +814,8 @@ SameType(const Value &lhs, const Value &rhs) return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); } +/************************************************************************/ + template <> struct RootMethods { static Value initial() { return UndefinedValue(); } @@ -897,6 +830,125 @@ template <> struct RootMethods static bool poisoned(const Value &v) { return IsPoisonedValue(v); } }; +template 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 with a visible extract() method returning the + * const Value* abstracted by Outer. + */ +template +class ValueOperations +{ + friend class MutableValueOperations; + const Value * value() const { return static_cast(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 with visible extractMutable() and extract() + * methods returning the const Value* and Value* abstracted by Outer. + */ +template +class MutableValueOperations : public ValueOperations +{ + Value * value() { return static_cast(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 &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 interface when T = Value with type-querying + * and value-extracting operations. + */ +template <> +class HandleBase : public ValueOperations > +{ + friend class ValueOperations >; + const Value * extract() const { + return static_cast*>(this)->address(); + } +}; + +/* + * Augment the generic MutableHandle interface when T = Value with + * type-querying, value-extracting, and mutating operations. + */ +template <> +class MutableHandleBase : public MutableValueOperations > +{ + friend class ValueOperations >; + const Value * extract() const { + return static_cast*>(this)->address(); + } + + friend class MutableValueOperations >; + Value * extractMutable() { + return static_cast*>(this)->address(); + } +}; + +/* + * Augment the generic Rooted interface when T = Value with type-querying, + * value-extracting, and mutating operations. + */ +template <> +class RootedBase : public MutableValueOperations > +{ + friend class ValueOperations >; + const Value * extract() const { + return static_cast*>(this)->address(); + } + + friend class MutableValueOperations >; + Value * extractMutable() { + return static_cast*>(this)->address(); + } +}; + /************************************************************************/ #ifndef __GNUC__