bool SetDenseElement(JSContext *cx, HandleObject 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->isNative()); MOZ_ASSERT(!obj->isIndexed()); JSObject::EnsureDenseResult result = JSObject::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 != JSObject::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 == JSObject::ED_FAILED) return false; MOZ_ASSERT(result == JSObject::ED_SPARSE); RootedValue indexVal(cx, Int32Value(index)); return SetObjectElement(cx, obj, indexVal, value, strict); }
/* ES5 15.12.3 JA. */ static bool JA(JSContext* cx, HandleObject obj, StringifyContext* scx) { /* * This method implements the JA algorithm in ES5 15.12.3, but: * * * The algorithm is somewhat reformulated to allow the final string to * be streamed into a single buffer, rather than be created and copied * into place incrementally as the ES5 algorithm specifies it. This * requires moving portions of the Str call in 8a into this algorithm * (and in JO as well). */ /* Steps 1-2, 11. */ CycleDetector detect(scx, obj); if (!detect.foundCycle(cx)) return false; if (!scx->sb.append('[')) return false; /* Step 6. */ uint32_t length; if (!GetLengthProperty(cx, obj, &length)) return false; /* Steps 7-10. */ if (length != 0) { /* Steps 4, 10b(i). */ if (!WriteIndent(cx, scx, scx->depth)) return false; /* Steps 7-10. */ RootedValue outputValue(cx); for (uint32_t i = 0; i < length; i++) { if (!CheckForInterrupt(cx)) return false; /* * Steps 8a-8c. Again note how the call to the spec's Str method * is broken up into getting the property, running it past toJSON * and the replacer and maybe unboxing, and interpreting some * values as |null| in separate steps. */ #ifdef DEBUG if (scx->maybeSafely) { /* * Trying to do a JS_AlreadyHasOwnElement runs the risk of * hitting OOM on jsid creation. Let's just assert sanity for * small enough indices. */ MOZ_ASSERT(obj->is<ArrayObject>()); MOZ_ASSERT(obj->is<NativeObject>()); RootedNativeObject nativeObj(cx, &obj->as<NativeObject>()); if (i <= JSID_INT_MAX) { MOZ_ASSERT(nativeObj->containsDenseElement(i) != nativeObj->isIndexed(), "the array must either be small enough to remain " "fully dense (and otherwise un-indexed), *or* " "all its initially-dense elements were sparsified " "and the object is indexed"); } else { MOZ_ASSERT(obj->isIndexed()); } } #endif if (!GetElement(cx, obj, obj, i, &outputValue)) return false; if (!PreprocessValue(cx, obj, i, &outputValue, scx)) return false; if (IsFilteredValue(outputValue)) { if (!scx->sb.append("null")) return false; } else { if (!Str(cx, outputValue, scx)) return false; } /* Steps 3, 4, 10b(i). */ if (i < length - 1) { if (!scx->sb.append(',')) return false; if (!WriteIndent(cx, scx, scx->depth)) return false; } } /* Step 10(b)(iii). */ if (!WriteIndent(cx, scx, scx->depth - 1)) return false; } return scx->sb.append(']'); }