diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index f97bb1503c8..e1da8826c31 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -67,6 +67,7 @@ MarkExactStackRoot(JSTracer *trc, Rooted *rooter, ThingRootKind kind) case THING_ROOT_ID: MarkIdRoot(trc, (jsid *)addr, "exact-id"); break; case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break; case THING_ROOT_BINDINGS: ((Bindings *)addr)->trace(trc); break; + case THING_ROOT_PROPERTY_DESCRIPTOR: ((JSPropertyDescriptor *)addr)->trace(trc); break; default: JS_NOT_REACHED("Invalid THING_ROOT kind"); break; } } @@ -415,19 +416,7 @@ AutoGCRooter::trace(JSTracer *trc) case DESCRIPTOR : { PropertyDescriptor &desc = *static_cast(this); - if (desc.obj) - MarkObjectRoot(trc, &desc.obj, "Descriptor::obj"); - MarkValueRoot(trc, &desc.value, "Descriptor::value"); - if ((desc.attrs & JSPROP_GETTER) && desc.getter) { - JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter); - MarkObjectRoot(trc, &tmp, "Descriptor::get"); - desc.getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, tmp); - } - if (desc.attrs & JSPROP_SETTER && desc.setter) { - JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, desc.setter); - MarkObjectRoot(trc, &tmp, "Descriptor::set"); - desc.setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, tmp); - } + desc.trace(trc); return; } @@ -648,6 +637,24 @@ StackShape::AutoRooter::trace(JSTracer *trc) MarkIdRoot(trc, (jsid*) &shape->propid, "StackShape::AutoRooter id"); } +void +JSPropertyDescriptor::trace(JSTracer *trc) +{ + if (obj) + MarkObjectRoot(trc, &obj, "Descriptor::obj"); + MarkValueRoot(trc, &value, "Descriptor::value"); + if ((attrs & JSPROP_GETTER) && getter) { + JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, getter); + MarkObjectRoot(trc, &tmp, "Descriptor::get"); + getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, tmp); + } + if ((attrs & JSPROP_SETTER) && setter) { + JSObject *tmp = JS_FUNC_TO_DATA_PTR(JSObject *, setter); + MarkObjectRoot(trc, &tmp, "Descriptor::set"); + setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, tmp); + } +} + void js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) { diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index d7f714e9679..9cdebbd5afe 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -29,14 +29,23 @@ using namespace mozilla; #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) +template +bool +CheckNonAddressThing(uintptr_t *w, T *t) +{ + return w >= (uintptr_t*)t && w < (uintptr_t*)(t + 1); +} + JS_ALWAYS_INLINE bool CheckStackRootThing(uintptr_t *w, void *address, ThingRootKind kind) { - if (kind != THING_ROOT_BINDINGS) - return address == static_cast(w); + if (kind == THING_ROOT_BINDINGS) + return CheckNonAddressThing(w, static_cast(address)); - Bindings *bp = static_cast(address); - return w >= (uintptr_t*)bp && w < (uintptr_t*)(bp + 1); + if (kind == THING_ROOT_PROPERTY_DESCRIPTOR) + return CheckNonAddressThing(w, static_cast(address)); + + return address == static_cast(w); } struct Rooter { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 9bcb80d2f42..8bc2630a35d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3326,13 +3326,115 @@ struct JSPropertyDescriptor { unsigned shortid; JSPropertyOp getter; JSStrictPropertyOp setter; - jsval value; + JS::Value value; JSPropertyDescriptor() : obj(NULL), attrs(0), shortid(0), getter(NULL), setter(NULL), value(JSVAL_VOID) {} + + void trace(JSTracer *trc); }; +namespace JS { + +template +class PropertyDescriptorOperations +{ + const JSPropertyDescriptor * desc() const { return static_cast(this)->extract(); } + JSPropertyDescriptor * desc() { return static_cast(this)->extract(); } + + public: + bool isEnumerable() const { return desc()->attrs & JSPROP_ENUMERATE; } + bool isReadonly() const { return desc()->attrs & JSPROP_READONLY; } + bool isPermanent() const { return desc()->attrs & JSPROP_PERMANENT; } + bool hasNativeAccessors() const { return desc()->attrs & JSPROP_NATIVE_ACCESSORS; } + bool hasGetterObject() const { return desc()->attrs & JSPROP_GETTER; } + bool hasSetterObject() const { return desc()->attrs & JSPROP_SETTER; } + bool isShared() const { return desc()->attrs & JSPROP_SHARED; } + bool isIndex() const { return desc()->attrs & JSPROP_INDEX; } + bool hasShortId() const { return desc()->attrs & JSPROP_SHORTID; } + bool hasAttributes(unsigned attrs) const { return desc()->attrs & attrs; } + + JS::MutableHandleObject object() { return JS::MutableHandleObject::fromMarkedLocation(&desc()->obj); } + unsigned attributes() const { return desc()->attrs; } + unsigned shortid() const { + MOZ_ASSERT(hasShortId()); + return desc()->shortid; + } + JSPropertyOp getter() const { MOZ_ASSERT(!hasGetterObject()); return desc()->getter; } + JSStrictPropertyOp setter() const { MOZ_ASSERT(!hasSetterObject()); return desc()->setter; } + JS::HandleObject getterObject() const { + MOZ_ASSERT(hasGetterObject()); + return JS::HandleObject::fromMarkedLocation(reinterpret_cast(&desc()->getter)); + } + JS::HandleObject setterObject() const { + MOZ_ASSERT(hasSetterObject()); + return JS::HandleObject::fromMarkedLocation(reinterpret_cast(&desc()->setter)); + } + JS::MutableHandleValue value() { return JS::MutableHandleValue::fromMarkedLocation(&desc()->value); } + + void setAttributes(unsigned attrs) { desc()->attrs = attrs; } + void setShortId(unsigned id) { desc()->shortid = id; } + void setGetter(JSPropertyOp op) { desc()->getter = op; } + void setSetter(JSStrictPropertyOp op) { desc()->setter = op; } + void setGetterObject(JSObject *obj) { desc()->getter = reinterpret_cast(obj); } + void setSetterObject(JSObject *obj) { desc()->setter = reinterpret_cast(obj); } +}; + +} /* namespace JS */ + +namespace js { + +template <> +struct RootMethods { + static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); } + static ThingRootKind kind() { return THING_ROOT_PROPERTY_DESCRIPTOR; } + static bool poisoned(const JSPropertyDescriptor &desc) { + return (desc.obj && JS::IsPoisonedPtr(desc.obj)) || + (desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) || + (desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) || + (desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing())); + } +}; + +template <> +class RootedBase + : public JS::PropertyDescriptorOperations > +{ + friend class JS::PropertyDescriptorOperations >; + const JSPropertyDescriptor *extract() const { + return static_cast*>(this)->address(); + } + JSPropertyDescriptor *extract() { + return static_cast*>(this)->address(); + } +}; + +template <> +class HandleBase + : public JS::PropertyDescriptorOperations > +{ + friend class JS::PropertyDescriptorOperations >; + const JSPropertyDescriptor *extract() const { + return static_cast*>(this)->address(); + } +}; + +template <> +class MutableHandleBase + : public JS::PropertyDescriptorOperations > +{ + friend class JS::PropertyDescriptorOperations >; + const JSPropertyDescriptor *extract() const { + return static_cast*>(this)->address(); + } + JSPropertyDescriptor *extract() { + return static_cast*>(this)->address(); + } +}; + +} /* namespace js */ + /* * Like JS_GetPropertyAttrsGetterAndSetterById but will return a property on * an object on the prototype chain (returned in objp). If data->obj is null, diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index ab124ee5710..c9e4eacad75 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -244,6 +244,7 @@ enum ThingRootKind THING_ROOT_VALUE, THING_ROOT_TYPE, THING_ROOT_BINDINGS, + THING_ROOT_PROPERTY_DESCRIPTOR, THING_ROOT_LIMIT };