From 7ffeb822e442245031c6027a09ac0aa0dbbaad30 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 7 Feb 2011 12:06:32 -0800 Subject: [PATCH] Bug 629817 - Add an AutoShapeVector to root shape vectors on the stack (r=luke) --- js/src/jsarray.cpp | 4 +- js/src/jscntxt.h | 115 ++++++++++++++++------------------------ js/src/jscntxtinlines.h | 2 +- js/src/jsgc.cpp | 6 +++ js/src/jsgcinlines.h | 15 ++++++ js/src/jsobj.cpp | 6 +-- js/src/jsvalue.h | 22 ++++++-- 7 files changed, 91 insertions(+), 79 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 868d17a0317d..bf0ae26477e8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1867,7 +1867,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * the root set covered by tvr.count. */ Value *mergesort_tmp = vec + newlen; - MakeValueRangeGCSafe(mergesort_tmp, newlen); + MakeRangeGCSafe(mergesort_tmp, newlen); tvr.changeLength(newlen * 2); /* Here len == 2 * (newlen + undefs + number_of_holes). */ @@ -1932,7 +1932,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) return false; } mergesort_tmp = vec + 2 * newlen; - MakeValueRangeGCSafe(mergesort_tmp, 2 * newlen); + MakeRangeGCSafe(mergesort_tmp, 2 * newlen); tvr.changeArray(vec, newlen * 4); elemsize = 2 * sizeof(Value); } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1ff1b8b6a1c1..9ac643015834 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -2241,7 +2241,8 @@ class AutoGCRooter { DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */ STRING = -14, /* js::AutoStringRooter */ IDVECTOR = -15, /* js::AutoIdVector */ - BINDINGS = -16 /* js::Bindings */ + BINDINGS = -16, /* js::Bindings */ + SHAPEVECTOR = -17 /* js::AutoShapeVector */ }; private: @@ -3227,28 +3228,28 @@ ContextAllocPolicy::reportAllocOverflow() const js_ReportAllocationOverflow(cx); } -class AutoValueVector : private AutoGCRooter +template +class AutoVectorRooter : protected AutoGCRooter { public: - explicit AutoValueVector(JSContext *cx - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VALVECTOR), vector(cx) + explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), vector(cx) { JS_GUARD_OBJECT_NOTIFIER_INIT; } size_t length() const { return vector.length(); } - bool append(const Value &v) { return vector.append(v); } + bool append(const T &v) { return vector.append(v); } void popBack() { vector.popBack(); } bool growBy(size_t inc) { - /* N.B. Value's default ctor leaves the Value undefined */ size_t oldLength = vector.length(); if (!vector.growByUninitialized(inc)) return false; - MakeValueRangeGCSafe(vector.begin() + oldLength, vector.end()); + MakeRangeGCSafe(vector.begin() + oldLength, vector.end()); return true; } @@ -3258,10 +3259,9 @@ class AutoValueVector : private AutoGCRooter vector.shrinkBy(oldLength - newLength); return true; } - /* N.B. Value's default ctor leaves the Value undefined */ if (!vector.growByUninitialized(newLength - oldLength)) return false; - MakeValueRangeGCSafe(vector.begin() + oldLength, vector.end()); + MakeRangeGCSafe(vector.begin() + oldLength, vector.end()); return true; } @@ -3269,14 +3269,33 @@ class AutoValueVector : private AutoGCRooter return vector.reserve(newLength); } - Value &operator[](size_t i) { return vector[i]; } - const Value &operator[](size_t i) const { return vector[i]; } + T &operator[](size_t i) { return vector[i]; } + const T &operator[](size_t i) const { return vector[i]; } - const Value *begin() const { return vector.begin(); } - Value *begin() { return vector.begin(); } + const T *begin() const { return vector.begin(); } + T *begin() { return vector.begin(); } - const Value *end() const { return vector.end(); } - Value *end() { return vector.end(); } + const T *end() const { return vector.end(); } + T *end() { return vector.end(); } + + const T &back() const { return vector.back(); } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Vector vector; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoValueVector : public AutoVectorRooter +{ + public: + explicit AutoValueVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, VALVECTOR) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } const jsval *jsval_begin() const { return Jsvalify(begin()); } jsval *jsval_begin() { return Jsvalify(begin()); } @@ -3284,72 +3303,32 @@ class AutoValueVector : private AutoGCRooter const jsval *jsval_end() const { return Jsvalify(end()); } jsval *jsval_end() { return Jsvalify(end()); } - const Value &back() const { return vector.back(); } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - Vector vector; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -class AutoIdVector : private AutoGCRooter +class AutoIdVector : public AutoVectorRooter { public: explicit AutoIdVector(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, IDVECTOR), vector(cx) + : AutoVectorRooter(cx, IDVECTOR) { JS_GUARD_OBJECT_NOTIFIER_INIT; } - size_t length() const { return vector.length(); } + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; - bool append(jsid id) { return vector.append(id); } - - void popBack() { vector.popBack(); } - - bool growBy(size_t inc) { - /* N.B. jsid's default ctor leaves the jsid undefined */ - size_t oldLength = vector.length(); - if (!vector.growByUninitialized(inc)) - return false; - MakeIdRangeGCSafe(vector.begin() + oldLength, vector.end()); - return true; +class AutoShapeVector : public AutoVectorRooter +{ + public: + explicit AutoShapeVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, SHAPEVECTOR) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; } - bool resize(size_t newLength) { - size_t oldLength = vector.length(); - if (newLength <= oldLength) { - vector.shrinkBy(oldLength - newLength); - return true; - } - /* N.B. jsid's default ctor leaves the jsid undefined */ - if (!vector.growByUninitialized(newLength - oldLength)) - return false; - MakeIdRangeGCSafe(vector.begin() + oldLength, vector.end()); - return true; - } - - bool reserve(size_t newLength) { - return vector.reserve(newLength); - } - - jsid &operator[](size_t i) { return vector[i]; } - const jsid &operator[](size_t i) const { return vector[i]; } - - const jsid *begin() const { return vector.begin(); } - jsid *begin() { return vector.begin(); } - - const jsid *end() const { return vector.end(); } - jsid *end() { return vector.end(); } - - const jsid &back() const { return vector.back(); } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - Vector vector; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index de652746bb20..cc3d4831fb93 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -248,7 +248,7 @@ StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag) Value *vp = start; Value *vpend = vp + nvals; - /* Don't need to MakeValueRangeGCSafe: the VM stack is conservatively marked. */ + /* Don't need to MakeRangeGCSafe: the VM stack is conservatively marked. */ /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */ ag->prevInvokeArgEnd = invokeArgEnd; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index ef9983d26c64..4d63eb029738 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1601,6 +1601,12 @@ AutoGCRooter::trace(JSTracer *trc) return; } + case SHAPEVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkShapeRange(trc, vector.length(), vector.begin(), "js::AutoShapeVector.vector"); + return; + } + case BINDINGS: { static_cast(this)->bindings.trace(trc); return; diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index e75ade169e57..e200ee8e8828 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -623,6 +623,21 @@ MarkValueRange(JSTracer *trc, size_t len, Value *vec, const char *name) MarkValueRange(trc, vec, vec + len, name); } +static inline void +MarkShapeRange(JSTracer *trc, const Shape **beg, const Shape **end, const char *name) +{ + for (const Shape **sp = beg; sp < end; ++sp) { + JS_SET_TRACING_INDEX(trc, name, sp - beg); + (*sp)->trace(trc); + } +} + +static inline void +MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name) +{ + MarkShapeRange(trc, vec, vec + len, name); +} + /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ static inline void MarkGCThing(JSTracer *trc, void *thing, uint32 kind) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index fe79e2b78da7..fa31b0f713ac 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3426,7 +3426,7 @@ JSObject::copyPropertiesFrom(JSContext *cx, JSObject *obj) if (!isNative()) return true; - Vector shapes(cx); + AutoShapeVector shapes(cx); for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { if (!shapes.append(&r.front())) return false; @@ -3725,8 +3725,8 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) return false; } } else { - Vector shapes(cx); - shapes.growByUninitialized(count); + AutoShapeVector shapes(cx); + shapes.growBy(count); for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { shape = &r.front(); diff --git a/js/src/jsvalue.h b/js/src/jsvalue.h index 2933b07304d8..a296f0b4775c 100644 --- a/js/src/jsvalue.h +++ b/js/src/jsvalue.h @@ -1145,28 +1145,40 @@ ValueArgToConstRef(const Value &v) /******************************************************************************/ static JS_ALWAYS_INLINE void -MakeValueRangeGCSafe(Value *vec, size_t len) +MakeRangeGCSafe(Value *vec, size_t len) { PodZero(vec, len); } static JS_ALWAYS_INLINE void -MakeValueRangeGCSafe(Value *beg, Value *end) +MakeRangeGCSafe(Value *beg, Value *end) { PodZero(beg, end - beg); } static JS_ALWAYS_INLINE void -MakeIdRangeGCSafe(jsid *beg, jsid *end) +MakeRangeGCSafe(jsid *beg, jsid *end) { for (jsid *id = beg; id != end; ++id) *id = INT_TO_JSID(0); } static JS_ALWAYS_INLINE void -MakeIdRangeGCSafe(jsid *vec, size_t len) +MakeRangeGCSafe(jsid *vec, size_t len) { - MakeIdRangeGCSafe(vec, vec + len); + MakeRangeGCSafe(vec, vec + len); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(const Shape **beg, const Shape **end) +{ + PodZero(beg, end - beg); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(const Shape **vec, size_t len) +{ + PodZero(vec, len); } static JS_ALWAYS_INLINE void