static bool CloneProperties(JSContext *cx, HandleNativeObject selfHostedObject, HandleObject clone) { AutoIdVector ids(cx); for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) { if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) { if (!ids.append(INT_TO_JSID(i))) return false; } } for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) { Shape &shape = range.front(); if (shape.enumerable() && !ids.append(shape.propid())) return false; } RootedId id(cx); RootedValue val(cx); RootedValue selfHostedValue(cx); for (uint32_t i = 0; i < ids.length(); i++) { id = ids[i]; if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue)) return false; if (!CloneValue(cx, selfHostedValue, &val) || !JS_DefinePropertyById(cx, clone, id, val, 0)) { return false; } } return true; }
static bool EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe<IdSet>& ht, AutoIdVector* props) { bool enumerateSymbols; if (flags & JSITER_SYMBOLSONLY) { enumerateSymbols = true; } else { /* Collect any dense elements from this object. */ size_t initlen = pobj->getDenseInitializedLength(); const Value* vp = pobj->getDenseElements(); for (size_t i = 0; i < initlen; ++i, ++vp) { if (!vp->isMagic(JS_ELEMENTS_HOLE)) { /* Dense arrays never get so large that i would not fit into an integer id. */ if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props)) return false; } } /* Collect any typed array or shared typed array elements from this object. */ if (IsAnyTypedArray(pobj)) { size_t len = AnyTypedArrayLength(pobj); for (size_t i = 0; i < len; i++) { if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props)) return false; } } size_t initialLength = props->length(); /* Collect all unique property names from this object's shape. */ bool symbolsFound = false; Shape::Range<NoGC> r(pobj->lastProperty()); for (; !r.empty(); r.popFront()) { Shape& shape = r.front(); jsid id = shape.propid(); if (JSID_IS_SYMBOL(id)) { symbolsFound = true; continue; } if (!Enumerate(cx, pobj, id, shape.enumerable(), flags, ht, props)) return false; } ::Reverse(props->begin() + initialLength, props->end()); enumerateSymbols = symbolsFound && (flags & JSITER_SYMBOLS); } if (enumerateSymbols) { // Do a second pass to collect symbols. ES6 draft rev 25 (2014 May 22) // 9.1.12 requires that all symbols appear after all strings in the // result. size_t initialLength = props->length(); for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty(); r.popFront()) { Shape& shape = r.front(); jsid id = shape.propid(); if (JSID_IS_SYMBOL(id)) { if (!Enumerate(cx, pobj, id, shape.enumerable(), flags, ht, props)) return false; } } ::Reverse(props->begin() + initialLength, props->end()); } return true; }
static bool EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe<IdSet>& ht, AutoIdVector* props, Handle<UnboxedPlainObject*> unboxed = nullptr) { bool enumerateSymbols; if (flags & JSITER_SYMBOLSONLY) { enumerateSymbols = true; } else { /* Collect any dense elements from this object. */ size_t firstElemIndex = props->length(); size_t initlen = pobj->getDenseInitializedLength(); const Value* vp = pobj->getDenseElements(); bool hasHoles = false; for (size_t i = 0; i < initlen; ++i, ++vp) { if (vp->isMagic(JS_ELEMENTS_HOLE)) { hasHoles = true; } else { /* Dense arrays never get so large that i would not fit into an integer id. */ if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props)) return false; } } /* Collect any typed array or shared typed array elements from this object. */ if (pobj->is<TypedArrayObject>()) { size_t len = pobj->as<TypedArrayObject>().length(); for (size_t i = 0; i < len; i++) { if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props)) return false; } } // Collect any sparse elements from this object. bool isIndexed = pobj->isIndexed(); if (isIndexed) { // If the dense elements didn't have holes, we don't need to include // them in the sort. if (!hasHoles) firstElemIndex = props->length(); for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty(); r.popFront()) { Shape& shape = r.front(); jsid id = shape.propid(); uint32_t dummy; if (IdIsIndex(id, &dummy)) { if (!Enumerate(cx, pobj, id, shape.enumerable(), flags, ht, props)) return false; } } MOZ_ASSERT(firstElemIndex <= props->length()); jsid* ids = props->begin() + firstElemIndex; size_t n = props->length() - firstElemIndex; AutoIdVector tmp(cx); if (!tmp.resize(n)) return false; PodCopy(tmp.begin(), ids, n); if (!MergeSort(ids, n, tmp.begin(), SortComparatorIntegerIds)) return false; } if (unboxed) { // If |unboxed| is set then |pobj| is the expando for an unboxed // plain object we are enumerating. Add the unboxed properties // themselves here since they are all property names that were // given to the object before any of the expando's properties. MOZ_ASSERT(pobj->is<UnboxedExpandoObject>()); if (!EnumerateExtraProperties(cx, unboxed, flags, ht, props)) return false; } size_t initialLength = props->length(); /* Collect all unique property names from this object's shape. */ bool symbolsFound = false; Shape::Range<NoGC> r(pobj->lastProperty()); for (; !r.empty(); r.popFront()) { Shape& shape = r.front(); jsid id = shape.propid(); if (JSID_IS_SYMBOL(id)) { symbolsFound = true; continue; } uint32_t dummy; if (isIndexed && IdIsIndex(id, &dummy)) continue; if (!Enumerate(cx, pobj, id, shape.enumerable(), flags, ht, props)) return false; } ::Reverse(props->begin() + initialLength, props->end()); enumerateSymbols = symbolsFound && (flags & JSITER_SYMBOLS); } if (enumerateSymbols) { // Do a second pass to collect symbols. ES6 draft rev 25 (2014 May 22) // 9.1.12 requires that all symbols appear after all strings in the // result. size_t initialLength = props->length(); for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty(); r.popFront()) { Shape& shape = r.front(); jsid id = shape.propid(); if (JSID_IS_SYMBOL(id)) { if (!Enumerate(cx, pobj, id, shape.enumerable(), flags, ht, props)) return false; } } ::Reverse(props->begin() + initialLength, props->end()); } return true; }