bool ArrayPushDense(JSContext *cx, HandleArrayObject obj, HandleValue v, uint32_t *length) { if (MOZ_LIKELY(obj->lengthIsWritable())) { uint32_t idx = obj->length(); NativeObject::EnsureDenseResult result = obj->ensureDenseElements(cx, idx, 1); if (result == NativeObject::ED_FAILED) return false; if (result == NativeObject::ED_OK) { obj->setDenseElement(idx, v); MOZ_ASSERT(idx < INT32_MAX); *length = idx + 1; obj->setLengthInt32(*length); return true; } } JS::AutoValueArray<3> argv(cx); argv[0].setUndefined(); argv[1].setObject(*obj); argv[2].set(v); if (!js::array_push(cx, 1, argv.begin())) return false; *length = argv[0].toInt32(); return true; }
bool MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator, HandleArrayObject resultPairObj) { MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2); ValueMap::Range* range = MapIteratorObjectRange(mapIterator); if (!range || range->empty()) { js_delete(range); mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr)); return true; } switch (mapIterator->kind()) { case MapObject::Keys: resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get()); break; case MapObject::Values: resultPairObj->setDenseElementWithType(cx, 1, range->front().value); break; case MapObject::Entries: { resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get()); resultPairObj->setDenseElementWithType(cx, 1, range->front().value); break; } } range->popFront(); return false; }
bool SetIteratorObject::next(Handle<SetIteratorObject*> setIterator, HandleArrayObject resultObj, JSContext* cx) { // Check invariants for inlined _GetNextSetEntryForIterator. // The array should be tenured, so that post-barrier can be done simply. MOZ_ASSERT(resultObj->isTenured()); // The array elements should be fixed. MOZ_ASSERT(resultObj->hasFixedElements()); MOZ_ASSERT(resultObj->getDenseInitializedLength() == 1); MOZ_ASSERT(resultObj->getDenseCapacity() >= 1); ValueSet::Range* range = SetIteratorObjectRange(setIterator); if (!range || range->empty()) { js_delete(range); setIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr)); return true; } resultObj->setDenseElementWithType(cx, 0, range->front().get()); range->popFront(); return false; }
bool MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator, HandleArrayObject resultPairObj) { // Check invariants for inlined _GetNextMapEntryForIterator. // The array should be tenured, so that post-barrier can be done simply. MOZ_ASSERT(resultPairObj->isTenured()); // The array elements should be fixed. MOZ_ASSERT(resultPairObj->hasFixedElements()); MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2); MOZ_ASSERT(resultPairObj->getDenseCapacity() >= 2); ValueMap::Range* range = MapIteratorObjectRange(mapIterator); if (!range || range->empty()) { js_delete(range); mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr)); return true; } switch (mapIterator->kind()) { case MapObject::Keys: resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get()); break; case MapObject::Values: resultPairObj->setDenseElementWithType(cx, 1, range->front().value); break; case MapObject::Entries: { resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get()); resultPairObj->setDenseElementWithType(cx, 1, range->front().value); break; } } range->popFront(); return false; }
bool js::ForOfPIC::Chain::tryOptimizeArray(JSContext *cx, HandleArrayObject array, bool *optimized) { MOZ_ASSERT(optimized); *optimized = false; if (!initialized_) { // If PIC is not initialized, initialize it. if (!initialize(cx)) return false; } else if (!disabled_ && !isArrayStateStillSane()) { // Otherwise, if array state is no longer sane, reinitialize. reset(cx); if (!initialize(cx)) return false; } MOZ_ASSERT(initialized_); // If PIC is disabled, don't bother trying to optimize. if (disabled_) return true; // By the time we get here, we should have a sane array state to work with. MOZ_ASSERT(isArrayStateStillSane()); // Check if stub already exists. ForOfPIC::Stub *stub = isArrayOptimized(&array->as<ArrayObject>()); if (stub) { *optimized = true; return true; } // If the number of stubs is about to exceed the limit, throw away entire // existing cache before adding new stubs. We shouldn't really have heavy // churn on these. if (numStubs() >= MAX_STUBS) eraseChain(); // Ensure array's prototype is the actual Array.prototype if (!isOptimizableArray(array)) return true; // Ensure array doesn't define '@@iterator' directly. if (array->lookup(cx, cx->names().std_iterator)) return true; // Good to optimize now, create stub to add. RootedShape shape(cx, array->lastProperty()); stub = cx->new_<Stub>(shape); if (!stub) return false; // Add the stub. addStub(stub); *optimized = true; return true; }