bool SetDenseElement(JSContext *cx, HandleNativeObject obj, int32_t index, HandleValue value, bool strict) { // This function is called from Ion code for StoreElementHole's OOL path. // In this case we know the object is native, has no indexed properties // and we can use setDenseElement instead of setDenseElementWithType. MOZ_ASSERT(!obj->isIndexed()); NativeObject::EnsureDenseResult result = NativeObject::ED_SPARSE; do { if (index < 0) break; bool isArray = obj->is<ArrayObject>(); if (isArray && !obj->as<ArrayObject>().lengthIsWritable()) break; uint32_t idx = uint32_t(index); result = obj->ensureDenseElements(cx, idx, 1); if (result != NativeObject::ED_OK) break; if (isArray) { ArrayObject &arr = obj->as<ArrayObject>(); if (idx >= arr.length()) arr.setLengthInt32(idx + 1); } obj->setDenseElement(idx, value); return true; } while (false); if (result == NativeObject::ED_FAILED) return false; MOZ_ASSERT(result == NativeObject::ED_SPARSE); RootedValue indexVal(cx, Int32Value(index)); return SetObjectElement(cx, obj, indexVal, value, strict); }
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; }