/* static */ bool ObjectElements::ConvertElementsToDoubles(JSContext *cx, uintptr_t elementsPtr) { /* * This function is infallible, but has a fallible interface so that it can * be called directly from Ion code. Only arrays can have their dense * elements converted to doubles, and arrays never have empty elements. */ HeapSlot *elementsHeapPtr = (HeapSlot *) elementsPtr; JS_ASSERT(elementsHeapPtr != emptyObjectElements); ObjectElements *header = ObjectElements::fromElements(elementsHeapPtr); JS_ASSERT(!header->shouldConvertDoubleElements()); // Note: the elements can be mutated in place even for copy on write // arrays. See comment on ObjectElements. Value *vp = (Value *) elementsPtr; for (size_t i = 0; i < header->initializedLength; i++) { if (vp[i].isInt32()) vp[i].setDouble(vp[i].toInt32()); } header->setShouldConvertDoubleElements(); return true; }
size_t js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKind) { if (src->hasEmptyElements()) return 0; Zone *zone = src->zone(); ObjectElements *srcHeader = src->getElementsHeader(); ObjectElements *dstHeader; /* TODO Bug 874151: Prefer to put element data inline if we have space. */ if (!isInside(srcHeader)) { JS_ASSERT(src->elements == dst->elements); hugeSlots.remove(reinterpret_cast<HeapSlot*>(srcHeader)); return 0; } /* ArrayBuffer stores byte-length, not Value count. */ if (src->is<ArrayBufferObject>()) { size_t nbytes; if (src->hasDynamicElements()) { nbytes = sizeof(ObjectElements) + srcHeader->initializedLength; dstHeader = static_cast<ObjectElements *>(zone->malloc_(nbytes)); if (!dstHeader) CrashAtUnhandlableOOM("Failed to allocate array buffer elements while tenuring."); } else { dst->setFixedElements(); nbytes = GetGCKindSlots(dst->tenuredGetAllocKind()) * sizeof(HeapSlot); dstHeader = dst->getElementsHeader(); } js_memcpy(dstHeader, srcHeader, nbytes); setElementsForwardingPointer(srcHeader, dstHeader, nbytes / sizeof(HeapSlot)); dst->elements = dstHeader->elements(); return src->hasDynamicElements() ? nbytes : 0; } size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; /* Unlike other objects, Arrays can have fixed elements. */ if (src->is<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); return nslots * sizeof(HeapSlot); } JS_ASSERT(nslots >= 2); size_t nbytes = nslots * sizeof(HeapValue); dstHeader = static_cast<ObjectElements *>(zone->malloc_(nbytes)); if (!dstHeader) CrashAtUnhandlableOOM("Failed to allocate elements while tenuring."); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); dst->elements = dstHeader->elements(); return nslots * sizeof(HeapSlot); }
void js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKind) { if (src->hasEmptyElements()) return; Allocator *alloc = &src->zone()->allocator; ObjectElements *srcHeader = src->getElementsHeader(); ObjectElements *dstHeader; if (!isInside(srcHeader)) { JS_ASSERT(src->elements == dst->elements); hugeSlots.remove(reinterpret_cast<HeapSlot*>(srcHeader)); return; } /* ArrayBuffer stores byte-length, not Value count. */ if (src->isArrayBuffer()) { size_t nbytes = sizeof(ObjectElements) + srcHeader->initializedLength; if (src->hasDynamicElements()) { dstHeader = static_cast<ObjectElements *>(alloc->malloc_(nbytes)); if (!dstHeader) MOZ_CRASH(); } else { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); } js_memcpy(dstHeader, srcHeader, nbytes); dst->elements = dstHeader->elements(); return; } size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->initializedLength; /* Unlike other objects, Arrays can have fixed elements. */ if (src->isArray() && nslots <= GetGCKindSlots(dstKind)) { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); dstHeader->capacity = GetGCKindSlots(dstKind) - ObjectElements::VALUES_PER_HEADER; return; } size_t nbytes = nslots * sizeof(HeapValue); dstHeader = static_cast<ObjectElements *>(alloc->malloc_(nbytes)); if (!dstHeader) MOZ_CRASH(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); dstHeader->capacity = srcHeader->initializedLength; dst->elements = dstHeader->elements(); }
/* static */ bool ObjectElements::MakeElementsCopyOnWrite(ExclusiveContext *cx, JSObject *obj) { // Make sure there is enough room for the owner object pointer at the end // of the elements. JS_STATIC_ASSERT(sizeof(HeapSlot) >= sizeof(HeapPtrObject)); if (!obj->ensureElements(cx, obj->getDenseInitializedLength() + 1)) return false; ObjectElements *header = obj->getElementsHeader(); // Note: this method doesn't update type information to indicate that the // elements might be copy on write. Handling this is left to the caller. JS_ASSERT(!header->isCopyOnWrite()); header->flags |= COPY_ON_WRITE; header->ownerObject().init(obj); return true; }
size_t ForkJoinNursery::copyElementsToTospace(JSObject *dst, JSObject *src, AllocKind dstKind) { if (src->hasEmptyElements()) return 0; ObjectElements *srcHeader = src->getElementsHeader(); ObjectElements *dstHeader; // TODO Bug 874151: Prefer to put element data inline if we have space. // (Note, not a correctness issue.) if (!isInsideFromspace(srcHeader)) { JS_ASSERT(src->elements == dst->elements); hugeSlots[hugeSlotsFrom].remove(reinterpret_cast<HeapSlot*>(srcHeader)); if (!isEvacuating_) hugeSlots[hugeSlotsNew].put(reinterpret_cast<HeapSlot*>(srcHeader)); return 0; } size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; // Unlike other objects, Arrays can have fixed elements. if (src->is<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); return nslots * sizeof(HeapSlot); } JS_ASSERT(nslots >= 2); dstHeader = reinterpret_cast<ObjectElements *>(allocateInTospace(nslots, sizeof(HeapSlot))); if (!dstHeader) CrashAtUnhandlableOOM("Failed to allocate elements while moving object."); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); dst->elements = dstHeader->elements(); return nslots * sizeof(HeapSlot); }