diff options
-rw-r--r-- | js/src/gc/Marking.cpp | 2 | ||||
-rw-r--r-- | js/src/jit/BaselineIC.cpp | 8 | ||||
-rw-r--r-- | js/src/jit/BaselineIC.h | 56 | ||||
-rw-r--r-- | js/src/jit/CodeGenerator.cpp | 19 | ||||
-rw-r--r-- | js/src/jit/MCallOptimize.cpp | 4 | ||||
-rw-r--r-- | js/src/jit/MIR.h | 6 | ||||
-rw-r--r-- | js/src/jsarray.cpp | 18 | ||||
-rw-r--r-- | js/src/jsobj.cpp | 27 | ||||
-rw-r--r-- | js/src/jsobjinlines.h | 2 | ||||
-rw-r--r-- | js/src/vm/Interpreter-inl.h | 2 | ||||
-rw-r--r-- | js/src/vm/Interpreter.cpp | 9 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup.cpp | 73 | ||||
-rw-r--r-- | js/src/vm/ReceiverGuard.cpp | 8 | ||||
-rw-r--r-- | js/src/vm/TypeInference.cpp | 2 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject-inl.h | 466 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject.cpp | 826 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject.h | 207 |
17 files changed, 124 insertions, 1611 deletions
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 47d2314c1..da3ef7d0d 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2504,8 +2504,6 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind InlineTypedObject::objectMovedDuringMinorGC(this, dst, src); } else if (src->is<TypedArrayObject>()) { tenuredSize += TypedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); - } else if (src->is<UnboxedArrayObject>()) { - tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); } else if (src->is<ArgumentsObject>()) { tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src); } else if (src->is<ProxyObject>()) { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f43fc5bf9..1d230e083 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -280,6 +280,12 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H RootedId id(cx); switch(stub->kind()) { + case ICStub::SetElem_DenseOrUnboxedArray: + case ICStub::SetElem_DenseOrUnboxedArrayAdd: { + id = JSID_VOID; + AddTypePropertyId(cx, obj, id, value); + break; + } case ICStub::SetProp_Native: case ICStub::SetProp_NativeAdd: case ICStub::SetProp_Unboxed: { @@ -5763,7 +5769,7 @@ CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result) if (!nobj) return false; EnsureArrayGroupAnalyzed(cx, nobj); - CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); + CopyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); result.setObject(*nobj); return true; diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index a57556d99..afbea3b69 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -892,54 +892,6 @@ class ICGetElem_Dense : public ICMonitoredStub }; }; -class ICGetElem_UnboxedArray : public ICMonitoredStub -{ - friend class ICStubSpace; - - GCPtrObjectGroup group_; - - ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group); - - public: - static ICGetElem_UnboxedArray* Clone(JSContext* cx, ICStubSpace* space, - ICStub* firstMonitorStub, ICGetElem_UnboxedArray& other); - - static size_t offsetOfGroup() { - return offsetof(ICGetElem_UnboxedArray, group_); - } - - GCPtrObjectGroup& group() { - return group_; - } - - class Compiler : public ICStubCompiler { - ICStub* firstMonitorStub_; - RootedObjectGroup group_; - JSValueType elementType_; - - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); - - virtual int32_t getKey() const { - return static_cast<int32_t>(engine_) | - (static_cast<int32_t>(kind) << 1) | - (static_cast<int32_t>(elementType_) << 17); - } - - public: - Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group) - : ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline), - firstMonitorStub_(firstMonitorStub), - group_(cx, group), - elementType_(group->unboxedLayoutDontCheckGeneration().elementType()) - {} - - ICStub* getStub(ICStubSpace* space) { - return newStub<ICGetElem_UnboxedArray>(space, getStubCode(), firstMonitorStub_, group_); - } - }; -}; - // Accesses scalar elements of a typed array or typed object. class ICGetElem_TypedArray : public ICStub { @@ -1115,9 +1067,7 @@ class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray, Engine::Baseline), shape_(cx, shape), group_(cx, group), - unboxedType_(shape - ? JSVAL_TYPE_MAGIC - : group->unboxedLayoutDontCheckGeneration().elementType()) + unboxedType_(JSVAL_TYPE_MAGIC) {} ICUpdatedStub* getStub(ICStubSpace* space) { @@ -1225,9 +1175,7 @@ class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler { : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, Engine::Baseline), obj_(cx, obj), protoChainDepth_(protoChainDepth), - unboxedType_(obj->is<UnboxedArrayObject>() - ? obj->as<UnboxedArrayObject>().elementType() - : JSVAL_TYPE_MAGIC) + unboxedType_(JSVAL_TYPE_MAGIC) {} template <size_t ProtoChainDepth> diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index bd275a2c1..485e881fe 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -10336,22 +10336,11 @@ CodeGenerator::visitLoadElementHole(LLoadElementHole* lir) else masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined); - if (mir->unboxedType() != JSVAL_TYPE_MAGIC) { - size_t width = UnboxedTypeSize(mir->unboxedType()); - if (lir->index()->isConstant()) { - Address addr(elements, ToInt32(lir->index()) * width); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } else { - BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width)); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } + if (lir->index()->isConstant()) { + NativeObject::elementsSizeMustNotOverflow(); + masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out); } else { - if (lir->index()->isConstant()) { - NativeObject::elementsSizeMustNotOverflow(); - masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out); - } else { - masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out); - } + masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out); } // If a hole check is needed, and the value wasn't a hole, we're done. diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 7283497ea..748a70973 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -541,7 +541,7 @@ IonBuilder::inlineArray(CallInfo& callInfo) if (!alloc().ensureBallast()) return InliningStatus_Error; MDefinition* value = callInfo.getArg(i); - if (!initializeArrayElement(array, i, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false)) return InliningStatus_Error; } @@ -578,7 +578,7 @@ IonBuilder::inlineArrayIsArray(CallInfo& callInfo) if (!clasp || clasp->isProxy()) return InliningStatus_NotInlined; - isArray = (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_); + isArray = (clasp == &ArrayObject::class_); } pushConstant(BooleanValue(isArray)); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index cdd737b56..f316827dc 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9245,7 +9245,7 @@ class MLoadElementHole bool needsHoleCheck_; MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength, - JSValueType unboxedType, bool needsHoleCheck) + bool needsHoleCheck) : MTernaryInstruction(elements, index, initLength), needsNegativeIntCheck_(true), needsHoleCheck_(needsHoleCheck) @@ -9717,10 +9717,6 @@ class MArraySlice return initialHeap_; } - JSValueType unboxedType() const { - return unboxedType_; - } - bool possiblyCalls() const override { return true; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 190439d4b..fa5ef2ab3 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -395,7 +395,7 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) if (obj->is<ArrayObject>() && !obj->isIndexed() && index <= UINT32_MAX) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1068,12 +1068,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_ // length > initLength we rely on the second loop to add the // other elements. MOZ_ASSERT(*numProcessed == 0); - uint32_t initLength = Min<uint32_t>(GetBoxedOrUnboxedInitializedLength<Type>(obj), length); + uint32_t initLength = Min<uint32_t>(GetBoxedOrUnboxedInitializedLength(obj), length); while (*numProcessed < initLength) { if (!CheckForInterrupt(cx)) return DenseElementResult::Failure; - Value elem = GetBoxedOrUnboxedDenseElement<Type>(obj, *numProcessed); + Value elem = GetBoxedOrUnboxedDenseElement(obj, *numProcessed); if (elem.isString()) { if (!sb.append(elem.toString())) @@ -1320,7 +1320,7 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1359,7 +1359,7 @@ DenseElementResult ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) { /* An empty array or an array with no elements is already reversed. */ - if (length == 0 || GetBoxedOrUnboxedInitializedLength<Type>(obj) == 0) + if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0) return DenseElementResult::Success; if (obj->as<NativeObject>().denseElementsAreFrozen()) @@ -2074,7 +2074,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) uint32_t newlength = length + args.length(); args.rval().setNumber(newlength); - // SetOrExtendAnyBoxedOrUnboxedDenseElements takes care of updating the + // SetOrExtendBoxedOrUnboxedDenseElements takes care of updating the // length for boxed and unboxed arrays. Handle updates to the length of // non-arrays here. bool isArray; @@ -2360,7 +2360,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co return false; /* There's no optimizing possible if it's not an array. */ - if (!arr->is<ArrayObject>() && !arr->is<UnboxedArrayObject>()) + if (!arr->is<ArrayObject>()) return false; /* If it's a frozen array, always pick the slow path */ @@ -2863,7 +2863,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be if (count) { DebugOnly<DenseElementResult> result = - CopyAnyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count); + CopyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count); MOZ_ASSERT(result.value == DenseElementResult::Success); } arr.set(narr); @@ -3608,7 +3608,7 @@ static inline JSObject* NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, NewObjectKind newKind = GenericObject) { - if (!obj->is<ArrayObject>() && !obj->is<UnboxedArrayObject>()) + if (!obj->is<ArrayObject>()) return NewArray<maxLength>(cx, length, nullptr, newKind); if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f22ecb445..c26a42f48 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1146,7 +1146,7 @@ static bool GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values) { MOZ_ASSERT(!obj->isSingleton()); - MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()); + MOZ_ASSERT(obj->is<ArrayObject>()); MOZ_ASSERT(!obj->isIndexed()); size_t length = GetAnyBoxedOrUnboxedArrayLength(obj); @@ -1207,11 +1207,10 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin MOZ_ASSERT_IF(obj->isSingleton(), cx->compartment()->behaviors().getSingletonsAsTemplates()); MOZ_ASSERT(obj->is<PlainObject>() || - obj->is<ArrayObject>() || - obj->is<UnboxedArrayObject>()); + obj->is<ArrayObject>()); MOZ_ASSERT(newKind != SingletonObject); - if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) { + if (obj->is<ArrayObject>()) { Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx)); if (!GetScriptArrayObjectElements(cx, obj, &values)) return nullptr; @@ -1327,9 +1326,8 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj) { if (mode == XDR_ENCODE) { MOZ_ASSERT(obj->is<PlainObject>() || - obj->is<ArrayObject>() || - obj->is<UnboxedArrayObject>()); - isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0; + obj->is<ArrayObject>()); + isArray = obj->is<ArrayObject>() ? 1 : 0; } if (!xdr->codeUint32(&isArray)) @@ -2312,11 +2310,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** // us the resolve hook won't define a property with this id. if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) return false; - } else if (obj->is<UnboxedArrayObject>()) { - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - MarkNonNativePropertyFound<NoGC>(propp); - return true; - } } else if (obj->is<TypedObject>()) { if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) { MarkNonNativePropertyFound<NoGC>(propp); @@ -3680,16 +3673,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const if (IsProxy(this)) return as<ProxyObject>().allocKindForTenure(); - // Unboxed arrays use inline data if their size is small enough. - if (is<UnboxedArrayObject>()) { - const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>(); - size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() + - nobj->capacity() * nobj->elementSize(); - if (nbytes <= JSObject::MAX_BYTE_SIZE) - return GetGCObjectKindForBytes(nbytes); - return AllocKind::OBJECT0; - } - // Inlined typed objects are followed by their data, so make sure we copy // it all over to the new object. if (is<InlineTypedObject>()) { diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 6be4d0d28..26f9eacce 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -40,8 +40,6 @@ MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj) { if (obj->is<UnboxedPlainObject>()) return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj); - if (obj->is<UnboxedArrayObject>()) - return UnboxedArrayObject::convertToNative(cx->asJSContext(), obj); return true; } diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 710f1d89b..a2c8e220a 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -593,7 +593,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t JSOp op = JSOp(*pc); MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC); - MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()); + MOZ_ASSERT(obj->is<ArrayObject>()); if (op == JSOP_INITELEM_INC && index == INT32_MAX) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 3cf2deb83..7d05b2d4c 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -5001,9 +5001,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32 if (group->shouldPreTenure() || group->maybePreliminaryObjects()) newKind = TenuredObject; - - if (group->maybeUnboxedLayout()) - return UnboxedArrayObject::create(cx, group, length, newKind); } ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind); @@ -5029,12 +5026,6 @@ js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject) NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject; - if (templateObject->is<UnboxedArrayObject>()) { - uint32_t length = templateObject->as<UnboxedArrayObject>().length(); - RootedObjectGroup group(cx, templateObject->group()); - return UnboxedArrayObject::create(cx, group, length, newKind); - } - ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(), nullptr, newKind); if (!obj) diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 46159a972..a227b7c9c 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -861,32 +861,6 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, return nullptr; if (group->maybePreliminaryObjects()) group->maybePreliminaryObjects()->maybeAnalyze(cx, group); - if (group->maybeUnboxedLayout()) { - switch (group->unboxedLayout().elementType()) { - case JSVAL_TYPE_BOOLEAN: - if (elementType != TypeSet::BooleanType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_INT32: - if (elementType != TypeSet::Int32Type()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_DOUBLE: - if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_STRING: - if (elementType != TypeSet::StringType()) - updateTypes = ShouldUpdateTypes::Update; - break; - case JSVAL_TYPE_OBJECT: - if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked()) - updateTypes = ShouldUpdateTypes::Update; - break; - default: - MOZ_CRASH(); - } - } return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes); } @@ -897,7 +871,7 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) { MOZ_ASSERT(source->group() != target->group()); - if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>()) + if (!target->is<ArrayObject>()) return true; if (target->group()->maybePreliminaryObjects()) { @@ -905,41 +879,21 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force); } - if (target->is<ArrayObject>()) { - ObjectGroup* sourceGroup = source->group(); - - if (source->is<UnboxedArrayObject>()) { - Shape* shape = target->as<ArrayObject>().lastProperty(); - if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape)) - return false; - } else if (source->is<ArrayObject>()) { - source->setGroup(target->group()); - } else { - return true; - } - - if (sourceGroup->maybePreliminaryObjects()) - sourceGroup->maybePreliminaryObjects()->unregisterObject(source); - if (target->group()->maybePreliminaryObjects()) - target->group()->maybePreliminaryObjects()->registerNewObject(source); - - for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) { - Value v = source->as<ArrayObject>().getDenseElement(i); - AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); - } + ObjectGroup* sourceGroup = source->group(); + if (source->is<ArrayObject>()) { + source->setGroup(target->group()); + } else { return true; } - if (target->is<UnboxedArrayObject>()) { - if (!source->is<UnboxedArrayObject>()) - return true; - if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32) - return true; - if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE) - return true; - - return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group()); + if (sourceGroup->maybePreliminaryObjects()) + sourceGroup->maybePreliminaryObjects()->unregisterObject(source); + if (target->group()->maybePreliminaryObjects()) + target->group()->maybePreliminaryObjects()->registerNewObject(source); + for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) { + Value v = source->as<ArrayObject>().getDenseElement(i); + AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); } return true; @@ -1503,7 +1457,8 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* } } - if (kind == JSProto_Array && + // FIXME: This block can probably go because of cx->options().unboxedArrays() + if (kind == JSProto_Array && (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) && cx->options().unboxedArrays()) { diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index 11c2d0727..e37bf8ee5 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -19,7 +19,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj) group = obj->group(); if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) shape = expando->lastProperty(); - } else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) { + } else if (obj->is<TypedObject>()) { group = obj->group(); } else { shape = obj->maybeShape(); @@ -34,7 +34,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) const Class* clasp = group->clasp(); if (clasp == &UnboxedPlainObject::class_) { // Keep both group and shape. - } else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) { + } else if (IsTypedObjectClass(clasp)) { this->shape = nullptr; } else { this->group = nullptr; @@ -49,8 +49,8 @@ HeapReceiverGuard::keyBits(JSObject* obj) // Both the group and shape need to be guarded for unboxed plain objects. return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1; } - if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) { - // Only the group needs to be guarded for unboxed arrays and typed objects. + if (obj->is<TypedObject>()) { + // Only the group needs to be guarded for typed objects. return 2; } // Other objects only need the shape to be guarded. diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 9e0342382..2160dbc51 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2505,7 +2505,7 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid bool js::ClassCanHaveExtraProperties(const Class* clasp) { - if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_) + if (clasp == &UnboxedPlainObject::class_) return false; return clasp->getResolve() || clasp->getOpsLookupProperty() diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 93ad7bf28..499f3604b 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -173,130 +173,13 @@ UnboxedPlainObject::layout() const } ///////////////////////////////////////////////////////////////////// -// UnboxedArrayObject -///////////////////////////////////////////////////////////////////// - -inline const UnboxedLayout& -UnboxedArrayObject::layout() const -{ - return group()->unboxedLayout(); -} - -inline void -UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length) -{ - if (length > INT32_MAX) { - // Track objects with overflowing lengths in type information. - MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW); - } - - length_ = length; -} - -inline void -UnboxedArrayObject::setInitializedLength(uint32_t initlen) -{ - if (initlen < initializedLength()) { - switch (elementType()) { - case JSVAL_TYPE_STRING: - for (size_t i = initlen; i < initializedLength(); i++) - triggerPreBarrier<JSVAL_TYPE_STRING>(i); - break; - case JSVAL_TYPE_OBJECT: - for (size_t i = initlen; i < initializedLength(); i++) - triggerPreBarrier<JSVAL_TYPE_OBJECT>(i); - break; - default: - MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType())); - } - } - setInitializedLengthNoBarrier(initlen); -} - -template <JSValueType Type> -inline bool -UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true); -} - -template <JSValueType Type> -inline void -UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true); -} - -template <JSValueType Type> -inline bool -UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false); -} - -template <JSValueType Type> -inline void -UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false); -} - -template <JSValueType Type> -inline Value -UnboxedArrayObject::getElementSpecific(size_t index) -{ - MOZ_ASSERT(index < initializedLength()); - MOZ_ASSERT(Type == elementType()); - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false); -} - -template <JSValueType Type> -inline void -UnboxedArrayObject::triggerPreBarrier(size_t index) -{ - MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type)); - - uint8_t* p = elements() + index * UnboxedTypeSize(Type); - - switch (Type) { - case JSVAL_TYPE_STRING: { - JSString** np = reinterpret_cast<JSString**>(p); - JSString::writeBarrierPre(*np); - break; - } - - case JSVAL_TYPE_OBJECT: { - JSObject** np = reinterpret_cast<JSObject**>(p); - JSObject::writeBarrierPre(*np); - break; - } - - default: - MOZ_CRASH("Bad type"); - } -} - -///////////////////////////////////////////////////////////////////// // Combined methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// static inline bool HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) { - return obj->isNative() || obj->is<UnboxedArrayObject>(); + return obj->isNative(); } static inline size_t @@ -304,8 +187,6 @@ GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) { if (obj->isNative()) return obj->as<NativeObject>().getDenseInitializedLength(); - if (obj->is<UnboxedArrayObject>()) - return obj->as<UnboxedArrayObject>().initializedLength(); return 0; } @@ -314,57 +195,40 @@ GetAnyBoxedOrUnboxedCapacity(JSObject* obj) { if (obj->isNative()) return obj->as<NativeObject>().getDenseCapacity(); - if (obj->is<UnboxedArrayObject>()) - return obj->as<UnboxedArrayObject>().capacity(); return 0; } static inline Value GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) { - if (obj->isNative()) - return obj->as<NativeObject>().getDenseElement(index); - return obj->as<UnboxedArrayObject>().getElement(index); + return obj->as<NativeObject>().getDenseElement(index); } static inline size_t GetAnyBoxedOrUnboxedArrayLength(JSObject* obj) { - if (obj->is<ArrayObject>()) - return obj->as<ArrayObject>().length(); - return obj->as<UnboxedArrayObject>().length(); + return obj->as<ArrayObject>().length(); } static inline void SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length) { - if (obj->is<ArrayObject>()) { - MOZ_ASSERT(length >= obj->as<ArrayObject>().length()); - obj->as<ArrayObject>().setLength(cx, length); - } else { - MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length()); - obj->as<UnboxedArrayObject>().setLength(cx, length); - } + MOZ_ASSERT(length >= obj->as<ArrayObject>().length()); + obj->as<ArrayObject>().setLength(cx, length); } static inline bool SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (obj->isNative()) { - obj->as<NativeObject>().setDenseElementWithType(cx, index, value); - return true; - } - return obj->as<UnboxedArrayObject>().setElement(cx, index, value); + obj->as<NativeObject>().setDenseElementWithType(cx, index, value); + return true; } static inline bool InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (obj->isNative()) { - obj->as<NativeObject>().initDenseElementWithType(cx, index, value); - return true; - } - return obj->as<UnboxedArrayObject>().initElement(cx, index, value); + obj->as<NativeObject>().initDenseElementWithType(cx, index, value); + return true; } ///////////////////////////////////////////////////////////////////// @@ -374,273 +238,128 @@ InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, co static inline JSValueType GetBoxedOrUnboxedType(JSObject* obj) { - if (obj->isNative()) - return JSVAL_TYPE_MAGIC; - return obj->as<UnboxedArrayObject>().elementType(); + return JSVAL_TYPE_MAGIC; } -template <JSValueType Type> static inline bool HasBoxedOrUnboxedDenseElements(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->isNative(); - return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type; + return obj->isNative(); } -template <JSValueType Type> static inline size_t GetBoxedOrUnboxedInitializedLength(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as<NativeObject>().getDenseInitializedLength(); - return obj->as<UnboxedArrayObject>().initializedLength(); + return obj->as<NativeObject>().getDenseInitializedLength(); } -template <JSValueType Type> static inline DenseElementResult SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) { - size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); - if (Type == JSVAL_TYPE_MAGIC) { - obj->as<NativeObject>().setDenseInitializedLength(initlen); - if (initlen < oldInitlen) - obj->as<NativeObject>().shrinkElements(cx, initlen); - } else { - obj->as<UnboxedArrayObject>().setInitializedLength(initlen); - if (initlen < oldInitlen) - obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen); - } + size_t oldInitlen = GetBoxedOrUnboxedInitializedLength(obj); + obj->as<NativeObject>().setDenseInitializedLength(initlen); + if (initlen < oldInitlen) + obj->as<NativeObject>().shrinkElements(cx, initlen); return DenseElementResult::Success; } -template <JSValueType Type> static inline size_t GetBoxedOrUnboxedCapacity(JSObject* obj) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as<NativeObject>().getDenseCapacity(); - return obj->as<UnboxedArrayObject>().capacity(); + return obj->as<NativeObject>().getDenseCapacity(); } -template <JSValueType Type> static inline Value GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) { - if (Type == JSVAL_TYPE_MAGIC) - return obj->as<NativeObject>().getDenseElement(index); - return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index); + return obj->as<NativeObject>().getDenseElement(index); } -template <JSValueType Type> static inline void SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value) { - if (Type == JSVAL_TYPE_MAGIC) - obj->as<NativeObject>().setDenseElement(index, value); - else - obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value); + obj->as<NativeObject>().setDenseElement(index, value); } -template <JSValueType Type> static inline bool SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) { - if (Type == JSVAL_TYPE_MAGIC) { - obj->as<NativeObject>().setDenseElementWithType(cx, index, value); - return true; - } - return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value); + obj->as<NativeObject>().setDenseElementWithType(cx, index, value); + return true; } -template <JSValueType Type> static inline DenseElementResult EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) { - if (Type == JSVAL_TYPE_MAGIC) { - if (!obj->as<ArrayObject>().ensureElements(cx, count)) - return DenseElementResult::Failure; - } else { - if (obj->as<UnboxedArrayObject>().capacity() < count) { - if (!obj->as<UnboxedArrayObject>().growElements(cx, count)) - return DenseElementResult::Failure; - } - } + if (!obj->as<ArrayObject>().ensureElements(cx, count)) + return DenseElementResult::Failure; return DenseElementResult::Success; } -template <JSValueType Type> static inline DenseElementResult SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) { - if (Type == JSVAL_TYPE_MAGIC) { - NativeObject* nobj = &obj->as<NativeObject>(); - - if (nobj->denseElementsAreFrozen()) - return DenseElementResult::Incomplete; - - if (obj->is<ArrayObject>() && - !obj->as<ArrayObject>().lengthIsWritable() && - start + count >= obj->as<ArrayObject>().length()) - { - return DenseElementResult::Incomplete; - } - - DenseElementResult result = nobj->ensureDenseElements(cx, start, count); - if (result != DenseElementResult::Success) - return result; - - if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length()) - obj->as<ArrayObject>().setLengthInt32(start + count); - - if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { - nobj->copyDenseElements(start, vp, count); - } else { - for (size_t i = 0; i < count; i++) - nobj->setDenseElementWithType(cx, start + i, vp[i]); - } - - return DenseElementResult::Success; - } - - UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>(); + NativeObject* nobj = &obj->as<NativeObject>(); - if (start > nobj->initializedLength()) + if (nobj->denseElementsAreFrozen()) return DenseElementResult::Incomplete; - if (start + count >= UnboxedArrayObject::MaximumCapacity) + if (obj->is<ArrayObject>() && + !obj->as<ArrayObject>().lengthIsWritable() && + start + count >= obj->as<ArrayObject>().length()) + { return DenseElementResult::Incomplete; + } - if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count)) - return DenseElementResult::Failure; + DenseElementResult result = nobj->ensureDenseElements(cx, start, count); + if (result != DenseElementResult::Success) + return result; - size_t oldInitlen = nobj->initializedLength(); - - // Overwrite any existing elements covered by the new range. If we fail - // after this point due to some incompatible type being written to the - // object's elements, afterwards the contents will be different from when - // we started. The caller must retry the operation using a generic path, - // which will overwrite the already-modified elements as well as the ones - // that were left alone. - size_t i = 0; - if (updateTypes == ShouldUpdateTypes::DontUpdate) { - for (size_t j = start; i < count && j < oldInitlen; i++, j++) - nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]); - } else { - for (size_t j = start; i < count && j < oldInitlen; i++, j++) { - if (!nobj->setElementSpecific<Type>(cx, j, vp[i])) - return DenseElementResult::Incomplete; - } - } + if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length()) + obj->as<ArrayObject>().setLengthInt32(start + count); - if (i != count) { - obj->as<UnboxedArrayObject>().setInitializedLength(start + count); - if (updateTypes == ShouldUpdateTypes::DontUpdate) { - for (; i < count; i++) - nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]); - } else { - for (; i < count; i++) { - if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) { - nobj->setInitializedLengthNoBarrier(oldInitlen); - return DenseElementResult::Incomplete; - } - } - } + if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { + nobj->copyDenseElements(start, vp, count); + } else { + for (size_t i = 0; i < count; i++) + nobj->setDenseElementWithType(cx, start + i, vp[i]); } - if (start + count >= nobj->length()) - nobj->setLength(cx, start + count); - return DenseElementResult::Success; } -template <JSValueType Type> static inline DenseElementResult MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj)); - - if (Type == JSVAL_TYPE_MAGIC) { - if (obj->as<NativeObject>().denseElementsAreFrozen()) - return DenseElementResult::Incomplete; + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); - if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx)) - return DenseElementResult::Failure; - obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length); - } else { - uint8_t* data = obj->as<UnboxedArrayObject>().elements(); - size_t elementSize = UnboxedTypeSize(Type); - - if (UnboxedTypeNeedsPreBarrier(Type) && - JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier()) - { - // Trigger pre barriers on any elements we are overwriting. See - // NativeObject::moveDenseElements. No post barrier is needed as - // only whole cell post barriers are used with unboxed objects. - for (size_t i = 0; i < length; i++) - obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i); - } + if (obj->as<NativeObject>().denseElementsAreFrozen()) + return DenseElementResult::Incomplete; - memmove(data + dstStart * elementSize, - data + srcStart * elementSize, - length * elementSize); - } + if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx)) + return DenseElementResult::Failure; + obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length); return DenseElementResult::Success; } -template <JSValueType DstType, JSValueType SrcType> static inline DenseElementResult CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src)); - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst)); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length); - MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length); - - SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length); - - if (DstType == JSVAL_TYPE_MAGIC) { - if (SrcType == JSVAL_TYPE_MAGIC) { - const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart; - dst->as<NativeObject>().initDenseElements(dstStart, vp, length); - } else { - for (size_t i = 0; i < length; i++) { - Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i); - dst->as<NativeObject>().initDenseElement(dstStart + i, v); - } - } - } else if (DstType == SrcType) { - uint8_t* dstData = dst->as<UnboxedArrayObject>().elements(); - uint8_t* srcData = src->as<UnboxedArrayObject>().elements(); - size_t elementSize = UnboxedTypeSize(DstType); - - memcpy(dstData + dstStart * elementSize, - srcData + srcStart * elementSize, - length * elementSize); - - // Add a store buffer entry if we might have copied a nursery pointer to dst. - if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst)) - dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst); - } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) { - uint8_t* dstData = dst->as<UnboxedArrayObject>().elements(); - uint8_t* srcData = src->as<UnboxedArrayObject>().elements(); - - for (size_t i = 0; i < length; i++) { - int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t)); - *reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v; - } - } else { - for (size_t i = 0; i < length; i++) { - Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i); - dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v); - } - } + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length); + MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length); + + SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); + + const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart; + dst->as<NativeObject>().initDenseElements(dstStart, vp, length); return DenseElementResult::Success; } @@ -666,22 +385,7 @@ CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) { if (!HasAnyBoxedOrUnboxedDenseElements(obj)) return DenseElementResult::Incomplete; - switch (GetBoxedOrUnboxedType(obj)) { - case JSVAL_TYPE_MAGIC: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>(); - case JSVAL_TYPE_BOOLEAN: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>(); - case JSVAL_TYPE_INT32: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>(); - case JSVAL_TYPE_DOUBLE: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>(); - case JSVAL_TYPE_STRING: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>(); - case JSVAL_TYPE_OBJECT: - return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>(); - default: - MOZ_CRASH(); - } + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>(); } // As above, except the specialization can reflect the unboxed type of two objects. @@ -692,42 +396,7 @@ CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2)) return DenseElementResult::Incomplete; -#define SPECIALIZE_OBJ2(TYPE) \ - switch (GetBoxedOrUnboxedType(obj2)) { \ - case JSVAL_TYPE_MAGIC: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \ - case JSVAL_TYPE_BOOLEAN: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \ - case JSVAL_TYPE_INT32: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \ - case JSVAL_TYPE_DOUBLE: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \ - case JSVAL_TYPE_STRING: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \ - case JSVAL_TYPE_OBJECT: \ - return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \ - default: \ - MOZ_CRASH(); \ - } - - switch (GetBoxedOrUnboxedType(obj1)) { - case JSVAL_TYPE_MAGIC: - SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC) - case JSVAL_TYPE_BOOLEAN: - SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN) - case JSVAL_TYPE_INT32: - SPECIALIZE_OBJ2(JSVAL_TYPE_INT32) - case JSVAL_TYPE_DOUBLE: - SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE) - case JSVAL_TYPE_STRING: - SPECIALIZE_OBJ2(JSVAL_TYPE_STRING) - case JSVAL_TYPE_OBJECT: - SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT) - default: - MOZ_CRASH(); - } - -#undef SPECIALIZE_OBJ2 + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC, JSVAL_TYPE_MAGIC>(); } #undef DEPENDENT_TEMPLATE_HINT @@ -816,25 +485,6 @@ struct Signature ## Functor { \ } \ } -DenseElementResult -SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, - uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); - -DenseElementResult -MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, - uint32_t dstStart, uint32_t srcStart, uint32_t length); - -DenseElementResult -CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, - uint32_t dstStart, uint32_t srcStart, uint32_t length); - -void -SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen); - -DenseElementResult -EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count); - } // namespace js #endif // vm_UnboxedObject_inl_h diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index d7ad91de4..806a9db81 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -417,8 +417,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) RootedObjectGroup replacementGroup(cx); - const Class* clasp = layout.isArray() ? &ArrayObject::class_ : &PlainObject::class_; - // Immediately clear any new script on the group. This is done by replacing // the existing new script with one for a replacement default new group. // This is done so that the size of the replacment group's objects is the @@ -426,8 +424,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) // slot accesses later on for sites that see converted objects from this // group and objects that were allocated using the replacement new group. if (layout.newScript()) { - MOZ_ASSERT(!layout.isArray()); - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); if (!replacementGroup) return false; @@ -453,15 +449,14 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) RootedScript script(cx, layout.allocationScript()); jsbytecode* pc = layout.allocationPc(); - replacementGroup = ObjectGroupCompartment::makeGroup(cx, clasp, proto); + replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); if (!replacementGroup) return false; PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>(); replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty()); - JSProtoKey key = layout.isArray() ? JSProto_Array : JSProto_Object; - cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, key, + cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object, replacementGroup); // Clear any baseline information at this opcode which might use the old group. @@ -477,22 +472,12 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) } } - size_t nfixed = layout.isArray() ? 0 : gc::GetGCKindSlots(layout.getAllocKind()); - - if (layout.isArray()) { - // The length shape to use for arrays is cached via a modified initial - // shape for array objects. Create an array now to make sure this entry - // is instantiated. - if (!NewDenseEmptyArray(cx)) - return false; - } + size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind()); - RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, proto, nfixed, 0)); + RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, nfixed, 0)); if (!shape) return false; - MOZ_ASSERT_IF(layout.isArray(), !shape->isEmptyShape() && shape->slotSpan() == 0); - // Add shapes for each property, if this is for a plain object. for (size_t i = 0; i < layout.properties().length(); i++) { const UnboxedLayout::Property& property = layout.properties()[i]; @@ -505,7 +490,7 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) } ObjectGroup* nativeGroup = - ObjectGroupCompartment::makeGroup(cx, clasp, proto, + ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto, group->flags() & OBJECT_FLAG_DYNAMIC_MASK); if (!nativeGroup) return false; @@ -513,24 +498,19 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) // No sense propagating if we don't know what we started with. if (!group->unknownProperties()) { // Propagate all property types from the old group to the new group. - if (layout.isArray()) { - if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup)) + for (size_t i = 0; i < layout.properties().length(); i++) { + const UnboxedLayout::Property& property = layout.properties()[i]; + jsid id = NameToId(property.name); + if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) return false; - } else { - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - jsid id = NameToId(property.name); - if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) - return false; - // If we are OOM we may not be able to propagate properties. - if (nativeGroup->unknownProperties()) - break; + // If we are OOM we may not be able to propagate properties. + if (nativeGroup->unknownProperties()) + break; - HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); - if (nativeProperty && nativeProperty->canSetDefinite(i)) - nativeProperty->setDefinite(i); - } + HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); + if (nativeProperty && nativeProperty->canSetDefinite(i)) + nativeProperty->setDefinite(i); } } else { // If we skip, though, the new group had better agree. @@ -956,702 +936,6 @@ const Class UnboxedPlainObject::class_ = { }; ///////////////////////////////////////////////////////////////////// -// UnboxedArrayObject -///////////////////////////////////////////////////////////////////// - -template <JSValueType Type> -DenseElementResult -AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, - MutableHandle<GCVector<Value>> values) -{ - for (size_t i = 0; i < initlen; i++) - values.infallibleAppend(obj->getElementSpecific<Type>(i)); - return DenseElementResult::Success; -} - -DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements, - UnboxedArrayObject*, uint32_t, MutableHandle<GCVector<Value>>); - -/* static */ bool -UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, - ObjectGroup* group, Shape* shape) -{ - size_t length = obj->as<UnboxedArrayObject>().length(); - size_t initlen = obj->as<UnboxedArrayObject>().initializedLength(); - - Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx)); - if (!values.reserve(initlen)) - return false; - - AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values); - DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj); - MOZ_ASSERT(result.value == DenseElementResult::Success); - - obj->setGroup(group); - - ArrayObject* aobj = &obj->as<ArrayObject>(); - aobj->setLastPropertyMakeNative(cx, shape); - - // Make sure there is at least one element, so that this array does not - // use emptyObjectElements / emptyObjectElementsShared. - if (!aobj->ensureElements(cx, Max<size_t>(initlen, 1))) - return false; - - MOZ_ASSERT(!aobj->getDenseInitializedLength()); - aobj->setDenseInitializedLength(initlen); - aobj->initDenseElements(0, values.begin(), initlen); - aobj->setLengthInt32(length); - - return true; -} - -/* static */ bool -UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) -{ - const UnboxedLayout& layout = obj->as<UnboxedArrayObject>().layout(); - - if (!layout.nativeGroup()) { - if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) - return false; - } - - return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape()); -} - -bool -UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group) -{ - MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32); - MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE); - - Vector<int32_t> values(cx); - if (!values.reserve(initializedLength())) - return false; - for (size_t i = 0; i < initializedLength(); i++) - values.infallibleAppend(getElementSpecific<JSVAL_TYPE_INT32>(i).toInt32()); - - uint8_t* newElements; - if (hasInlineElements()) { - newElements = AllocateObjectBuffer<uint8_t>(cx, this, capacity() * sizeof(double)); - } else { - newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(), - capacity() * sizeof(int32_t), - capacity() * sizeof(double)); - } - if (!newElements) - return false; - - setGroup(group); - elements_ = newElements; - - for (size_t i = 0; i < initializedLength(); i++) - setElementNoTypeChangeSpecific<JSVAL_TYPE_DOUBLE>(i, DoubleValue(values[i])); - - return true; -} - -/* static */ UnboxedArrayObject* -UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length, - NewObjectKind newKind, uint32_t maxLength) -{ - MOZ_ASSERT(length <= MaximumCapacity); - - MOZ_ASSERT(group->clasp() == &class_); - uint32_t elementSize = UnboxedTypeSize(group->unboxedLayout().elementType()); - uint32_t capacity = Min(length, maxLength); - uint32_t nbytes = offsetOfInlineElements() + elementSize * capacity; - - UnboxedArrayObject* res; - if (nbytes <= JSObject::MAX_BYTE_SIZE) { - gc::AllocKind allocKind = gc::GetGCObjectKindForBytes(nbytes); - - // If there was no provided length information, pick an allocation kind - // to accommodate small arrays (as is done for normal native arrays). - if (capacity == 0) - allocKind = gc::AllocKind::OBJECT8; - - res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, allocKind, newKind); - if (!res) - return nullptr; - res->setInitializedLengthNoBarrier(0); - res->setInlineElements(); - - size_t actualCapacity = (GetGCKindBytes(allocKind) - offsetOfInlineElements()) / elementSize; - MOZ_ASSERT(actualCapacity >= capacity); - res->setCapacityIndex(exactCapacityIndex(actualCapacity)); - } else { - res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, gc::AllocKind::OBJECT0, newKind); - if (!res) - return nullptr; - res->setInitializedLengthNoBarrier(0); - - uint32_t capacityIndex = (capacity == length) - ? CapacityMatchesLengthIndex - : chooseCapacityIndex(capacity, length); - uint32_t actualCapacity = computeCapacity(capacityIndex, length); - - res->elements_ = AllocateObjectBuffer<uint8_t>(cx, res, actualCapacity * elementSize); - if (!res->elements_) { - // Make the object safe for GC. - res->setInlineElements(); - return nullptr; - } - - res->setCapacityIndex(capacityIndex); - } - - res->setLength(cx, length); - return res; -} - -bool -UnboxedArrayObject::setElement(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true); -} - -bool -UnboxedArrayObject::initElement(ExclusiveContext* cx, size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false); -} - -void -UnboxedArrayObject::initElementNoTypeChange(size_t index, const Value& v) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - if (UnboxedTypeNeedsPreBarrier(elementType())) - *reinterpret_cast<void**>(p) = nullptr; - SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false); -} - -Value -UnboxedArrayObject::getElement(size_t index) -{ - MOZ_ASSERT(index < initializedLength()); - uint8_t* p = elements() + index * elementSize(); - return GetUnboxedValue(p, elementType(), /* maybeUninitialized = */ false); -} - -/* static */ void -UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj) -{ - JSValueType type = obj->as<UnboxedArrayObject>().elementType(); - if (!UnboxedTypeNeedsPreBarrier(type)) - return; - - MOZ_ASSERT(obj->as<UnboxedArrayObject>().elementSize() == sizeof(uintptr_t)); - size_t initlen = obj->as<UnboxedArrayObject>().initializedLength(); - void** elements = reinterpret_cast<void**>(obj->as<UnboxedArrayObject>().elements()); - - switch (type) { - case JSVAL_TYPE_OBJECT: - for (size_t i = 0; i < initlen; i++) { - GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(elements + i); - TraceNullableEdge(trc, heap, "unboxed_object"); - } - break; - - case JSVAL_TYPE_STRING: - for (size_t i = 0; i < initlen; i++) { - GCPtrString* heap = reinterpret_cast<GCPtrString*>(elements + i); - TraceEdge(trc, heap, "unboxed_string"); - } - break; - - default: - MOZ_CRASH(); - } -} - -/* static */ void -UnboxedArrayObject::objectMoved(JSObject* obj, const JSObject* old) -{ - UnboxedArrayObject& dst = obj->as<UnboxedArrayObject>(); - const UnboxedArrayObject& src = old->as<UnboxedArrayObject>(); - - // Fix up possible inline data pointer. - if (src.hasInlineElements()) - dst.setInlineElements(); -} - -/* static */ void -UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj) -{ - MOZ_ASSERT(!IsInsideNursery(obj)); - if (!obj->as<UnboxedArrayObject>().hasInlineElements()) - js_free(obj->as<UnboxedArrayObject>().elements()); -} - -/* static */ size_t -UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind) -{ - UnboxedArrayObject* ndst = &dst->as<UnboxedArrayObject>(); - UnboxedArrayObject* nsrc = &src->as<UnboxedArrayObject>(); - MOZ_ASSERT(ndst->elements() == nsrc->elements()); - - Nursery& nursery = trc->runtime()->gc.nursery; - - if (!nursery.isInside(nsrc->elements())) { - nursery.removeMallocedBuffer(nsrc->elements()); - return 0; - } - - // Determine if we can use inline data for the target array. If this is - // possible, the nursery will have picked an allocation size that is large - // enough. - size_t nbytes = nsrc->capacity() * nsrc->elementSize(); - if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) { - ndst->setInlineElements(); - } else { - MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0); - - AutoEnterOOMUnsafeRegion oomUnsafe; - uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes); - if (!data) - oomUnsafe.crash("Failed to allocate unboxed array elements while tenuring."); - ndst->elements_ = data; - } - - PodCopy(ndst->elements(), nsrc->elements(), nsrc->initializedLength() * nsrc->elementSize()); - - // Set a forwarding pointer for the element buffers in case they were - // preserved on the stack by Ion. - bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t); - nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct); - - return ndst->hasInlineElements() ? 0 : nbytes; -} - -// Possible capacities for unboxed arrays. Some of these capacities might seem -// a little weird, but were chosen to allow the inline data of objects of each -// size to be fully utilized for arrays of the various types on both 32 bit and -// 64 bit platforms. -// -// To find the possible inline capacities, the following script was used: -// -// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16]; -// var dataSizes = [1, 4, 8]; -// var header32 = 4 * 2 + 4 * 2; -// var header64 = 8 * 2 + 4 * 2; -// -// for (var i = 0; i < fixedSlotCapacities.length; i++) { -// var nfixed = fixedSlotCapacities[i]; -// var size32 = 4 * 4 + 8 * nfixed - header32; -// var size64 = 8 * 4 + 8 * nfixed - header64; -// for (var j = 0; j < dataSizes.length; j++) { -// print(size32 / dataSizes[j]); -// print(size64 / dataSizes[j]); -// } -// } -// -/* static */ const uint32_t -UnboxedArrayObject::CapacityArray[] = { - UINT32_MAX, // For CapacityMatchesLengthIndex. - 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, - 1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336, - 13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464, - 46137344, 52428800, 59768832, MaximumCapacity -}; - -static const uint32_t -Pow2CapacityIndexes[] = { - 2, // 1 - 3, // 2 - 5, // 4 - 8, // 8 - 13, // 16 - 18, // 32 - 21, // 64 - 25, // 128 - 27, // 256 - 28, // 512 - 29, // 1024 - 30, // 2048 - 31, // 4096 - 32, // 8192 - 33, // 16384 - 34, // 32768 - 35, // 65536 - 36, // 131072 - 37, // 262144 - 38, // 524288 - 39 // 1048576 -}; - -static const uint32_t MebiCapacityIndex = 39; - -/* static */ uint32_t -UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length) -{ - // Note: the structure and behavior of this method follow along with - // NativeObject::goodAllocated. Changes to the allocation strategy in one - // should generally be matched by the other. - - // Make sure we have enough space to store all possible values for the capacity index. - // This ought to be a static_assert, but MSVC doesn't like that. - MOZ_ASSERT(mozilla::ArrayLength(CapacityArray) - 1 <= (CapacityMask >> CapacityShift)); - - // The caller should have ensured the capacity is possible for an unboxed array. - MOZ_ASSERT(capacity <= MaximumCapacity); - - static const uint32_t Mebi = 1024 * 1024; - - if (capacity <= Mebi) { - capacity = mozilla::RoundUpPow2(capacity); - - // When the required capacity is close to the array length, then round - // up to the array length itself, as for NativeObject. - if (length >= capacity && capacity > (length / 3) * 2) - return CapacityMatchesLengthIndex; - - if (capacity < MinimumDynamicCapacity) - capacity = MinimumDynamicCapacity; - - uint32_t bit = mozilla::FloorLog2Size(capacity); - MOZ_ASSERT(capacity == uint32_t(1 << bit)); - MOZ_ASSERT(bit <= 20); - MOZ_ASSERT(mozilla::ArrayLength(Pow2CapacityIndexes) == 21); - - uint32_t index = Pow2CapacityIndexes[bit]; - MOZ_ASSERT(CapacityArray[index] == capacity); - - return index; - } - - MOZ_ASSERT(CapacityArray[MebiCapacityIndex] == Mebi); - - for (uint32_t i = MebiCapacityIndex + 1;; i++) { - if (CapacityArray[i] >= capacity) - return i; - } - - MOZ_CRASH("Invalid capacity"); -} - -/* static */ uint32_t -UnboxedArrayObject::exactCapacityIndex(uint32_t capacity) -{ - for (size_t i = CapacityMatchesLengthIndex + 1; i < ArrayLength(CapacityArray); i++) { - if (CapacityArray[i] == capacity) - return i; - } - MOZ_CRASH(); -} - -bool -UnboxedArrayObject::growElements(ExclusiveContext* cx, size_t cap) -{ - // The caller should have checked if this capacity is possible for an - // unboxed array, so the only way this call can fail is from OOM. - MOZ_ASSERT(cap <= MaximumCapacity); - - uint32_t oldCapacity = capacity(); - uint32_t newCapacityIndex = chooseCapacityIndex(cap, length()); - uint32_t newCapacity = computeCapacity(newCapacityIndex, length()); - - MOZ_ASSERT(oldCapacity < cap); - MOZ_ASSERT(cap <= newCapacity); - - // The allocation size computation below cannot have integer overflows. - JS_STATIC_ASSERT(MaximumCapacity < UINT32_MAX / sizeof(double)); - - uint8_t* newElements; - if (hasInlineElements()) { - newElements = AllocateObjectBuffer<uint8_t>(cx, this, newCapacity * elementSize()); - if (!newElements) - return false; - js_memcpy(newElements, elements(), initializedLength() * elementSize()); - } else { - newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(), - oldCapacity * elementSize(), - newCapacity * elementSize()); - if (!newElements) - return false; - } - - elements_ = newElements; - setCapacityIndex(newCapacityIndex); - - return true; -} - -void -UnboxedArrayObject::shrinkElements(ExclusiveContext* cx, size_t cap) -{ - if (hasInlineElements()) - return; - - uint32_t oldCapacity = capacity(); - uint32_t newCapacityIndex = chooseCapacityIndex(cap, 0); - uint32_t newCapacity = computeCapacity(newCapacityIndex, 0); - - MOZ_ASSERT(cap < oldCapacity); - MOZ_ASSERT(cap <= newCapacity); - - if (newCapacity >= oldCapacity) - return; - - uint8_t* newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(), - oldCapacity * elementSize(), - newCapacity * elementSize()); - if (!newElements) - return; - - elements_ = newElements; - setCapacityIndex(newCapacityIndex); -} - -bool -UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id) -{ - if (JSID_IS_INT(id) && uint32_t(JSID_TO_INT(id)) < initializedLength()) - return true; - if (JSID_IS_ATOM(id) && JSID_TO_ATOM(id) == cx->names().length) - return true; - return false; -} - -/* static */ bool -UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - MarkNonNativePropertyFound<CanGC>(propp); - objp.set(obj); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - objp.set(nullptr); - propp.set(nullptr); - return true; - } - - return LookupProperty(cx, proto, id, objp, propp); -} - -/* static */ bool -UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle<PropertyDescriptor> desc, - ObjectOpResult& result) -{ - if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) { - UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>(); - - uint32_t index = JSID_TO_INT(id); - if (index < nobj->initializedLength()) { - if (nobj->setElement(cx, index, desc.value())) - return result.succeed(); - } else if (index == nobj->initializedLength() && index < MaximumCapacity) { - if (nobj->initializedLength() == nobj->capacity()) { - if (!nobj->growElements(cx, index + 1)) - return false; - } - nobj->setInitializedLength(index + 1); - if (nobj->initElement(cx, index, desc.value())) { - if (nobj->length() <= index) - nobj->setLengthInt32(index + 1); - return result.succeed(); - } - nobj->setInitializedLengthNoBarrier(index); - } - } - - if (!convertToNative(cx, obj)) - return false; - - return DefineProperty(cx, obj, id, desc, result); -} - -/* static */ bool -UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - *foundp = true; - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - *foundp = false; - return true; - } - - return HasProperty(cx, proto, id, foundp); -} - -/* static */ bool -UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - if (JSID_IS_INT(id)) - vp.set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id))); - else - vp.set(Int32Value(obj->as<UnboxedArrayObject>().length())); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - vp.setUndefined(); - return true; - } - - return GetProperty(cx, proto, receiver, id, vp); -} - -/* static */ bool -UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - if (receiver.isObject() && obj == &receiver.toObject()) { - if (JSID_IS_INT(id)) { - if (obj->as<UnboxedArrayObject>().setElement(cx, JSID_TO_INT(id), v)) - return result.succeed(); - } else { - uint32_t len; - if (!CanonicalizeArrayLengthValue(cx, v, &len)) - return false; - UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>(); - if (len < nobj->initializedLength()) { - nobj->setInitializedLength(len); - nobj->shrinkElements(cx, len); - } - nobj->setLength(cx, len); - return result.succeed(); - } - - if (!convertToNative(cx, obj)) - return false; - return SetProperty(cx, obj, id, v, receiver, result); - } - - return SetPropertyByDefining(cx, id, v, receiver, result); - } - - return SetPropertyOnProto(cx, obj, id, v, receiver, result); -} - -/* static */ bool -UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<PropertyDescriptor> desc) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - if (JSID_IS_INT(id)) { - desc.value().set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id))); - desc.setAttributes(JSPROP_ENUMERATE); - } else { - desc.value().set(Int32Value(obj->as<UnboxedArrayObject>().length())); - desc.setAttributes(JSPROP_PERMANENT); - } - desc.object().set(obj); - return true; - } - - desc.object().set(nullptr); - return true; -} - -/* static */ bool -UnboxedArrayObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result) -{ - if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { - size_t initlen = obj->as<UnboxedArrayObject>().initializedLength(); - if (JSID_IS_INT(id) && JSID_TO_INT(id) == int32_t(initlen - 1)) { - obj->as<UnboxedArrayObject>().setInitializedLength(initlen - 1); - obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen - 1); - return result.succeed(); - } - } - - if (!convertToNative(cx, obj)) - return false; - return DeleteProperty(cx, obj, id, result); -} - -/* static */ bool -UnboxedArrayObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - if (!convertToNative(cx, obj)) - return false; - return WatchProperty(cx, obj, id, callable); -} - -/* static */ bool -UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly) -{ - for (size_t i = 0; i < obj->as<UnboxedArrayObject>().initializedLength(); i++) { - if (!properties.append(INT_TO_JSID(i))) - return false; - } - - if (!enumerableOnly && !properties.append(NameToId(cx->names().length))) - return false; - - return true; -} - -static const ClassOps UnboxedArrayObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - UnboxedArrayObject::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedArrayObject::trace, -}; - -static const ClassExtension UnboxedArrayObjectClassExtension = { - nullptr, /* weakmapKeyDelegateOp */ - UnboxedArrayObject::objectMoved -}; - -static const ObjectOps UnboxedArrayObjectObjectOps = { - UnboxedArrayObject::obj_lookupProperty, - UnboxedArrayObject::obj_defineProperty, - UnboxedArrayObject::obj_hasProperty, - UnboxedArrayObject::obj_getProperty, - UnboxedArrayObject::obj_setProperty, - UnboxedArrayObject::obj_getOwnPropertyDescriptor, - UnboxedArrayObject::obj_deleteProperty, - UnboxedArrayObject::obj_watch, - nullptr, /* No unwatch needed, as watch() converts the object to native */ - nullptr, /* getElements */ - UnboxedArrayObject::obj_enumerate, - nullptr /* funToString */ -}; - -const Class UnboxedArrayObject::class_ = { - "Array", - Class::NON_NATIVE | - JSCLASS_SKIP_NURSERY_FINALIZE | - JSCLASS_BACKGROUND_FINALIZE, - &UnboxedArrayObjectClassOps, - JS_NULL_CLASS_SPEC, - &UnboxedArrayObjectClassExtension, - &UnboxedArrayObjectObjectOps -}; - -///////////////////////////////////////////////////////////////////// // API ///////////////////////////////////////////////////////////////////// @@ -1662,31 +946,6 @@ NextValue(Handle<GCVector<Value>> values, size_t* valueCursor) } void -UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, - Handle<GCVector<Value>> values, size_t* valueCursor) -{ - MOZ_ASSERT(CapacityArray[1] == 0); - setCapacityIndex(1); - setInitializedLengthNoBarrier(0); - setInlineElements(); - - setLength(cx, NextValue(values, valueCursor).toInt32()); - - int32_t initlen = NextValue(values, valueCursor).toInt32(); - if (!initlen) - return; - - AutoEnterOOMUnsafeRegion oomUnsafe; - if (!growElements(cx, initlen)) - oomUnsafe.crash("UnboxedArrayObject::fillAfterConvert"); - - setInitializedLength(initlen); - - for (size_t i = 0; i < size_t(initlen); i++) - JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); -} - -void UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, Handle<GCVector<Value>> values, size_t* valueCursor) { @@ -1695,58 +954,3 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, for (size_t i = 0; i < layout().properties().length(); i++) JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); } - -DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, - ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, - ShouldUpdateTypes); - -DenseElementResult -js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, - uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes) -{ - SetOrExtendBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, start, vp, count, updateTypes); - return CallBoxedOrUnboxedSpecialization(functor, obj); -}; - -DefineBoxedOrUnboxedFunctor5(MoveBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, uint32_t, uint32_t, uint32_t); - -DenseElementResult -js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, - uint32_t dstStart, uint32_t srcStart, uint32_t length) -{ - MoveBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, dstStart, srcStart, length); - return CallBoxedOrUnboxedSpecialization(functor, obj); -} - -DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t); - -DenseElementResult -js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, - uint32_t dstStart, uint32_t srcStart, uint32_t length) -{ - CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length); - return CallBoxedOrUnboxedSpecialization(functor, dst, src); -} - -DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength, - JSContext*, JSObject*, size_t); - -void -js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) -{ - SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen); - JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success); -} - -DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, size_t); - -DenseElementResult -js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen) -{ - EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen); - return CallBoxedOrUnboxedSpecialization(functor, obj); -} diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 779dd14c7..ba66434bc 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -96,17 +96,11 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> // from an array of values. GCPtrJitCode constructorCode_; - // The following members are only used for unboxed arrays. - - // The type of array elements. - JSValueType elementType_; - public: UnboxedLayout() : nativeGroup_(nullptr), nativeShape_(nullptr), allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), - size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr), - elementType_(JSVAL_TYPE_MAGIC) + size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) {} bool initProperties(const PropertyVector& properties, size_t size) { @@ -114,10 +108,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> return properties_.appendAll(properties); } - void initArray(JSValueType elementType) { - elementType_ = elementType; - } - ~UnboxedLayout() { if (newScript_) newScript_->clear(); @@ -130,10 +120,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> constructorCode_.init(nullptr); } - bool isArray() const { - return elementType_ != JSVAL_TYPE_MAGIC; - } - void detachFromCompartment(); const PropertyVector& properties() const { @@ -201,10 +187,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> constructorCode_ = code; } - JSValueType elementType() const { - return elementType_; - } - inline gc::AllocKind getAllocKind() const; void trace(JSTracer* trc); @@ -324,193 +306,6 @@ UnboxedLayout::getAllocKind() const return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); } -// Class for an array object using an unboxed representation. -class UnboxedArrayObject : public JSObject -{ - // Elements pointer for the object. - uint8_t* elements_; - - // The nominal array length. This always fits in an int32_t. - uint32_t length_; - - // Value indicating the allocated capacity and initialized length of the - // array. The top CapacityBits bits are an index into CapacityArray, which - // indicates the elements capacity. The low InitializedLengthBits store the - // initialized length of the array. - uint32_t capacityIndexAndInitializedLength_; - - // If the elements are inline, they will point here. - uint8_t inlineElements_[1]; - - public: - static const uint32_t CapacityBits = 6; - static const uint32_t CapacityShift = 26; - - static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift; - static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1; - - static const uint32_t MaximumCapacity = InitializedLengthMask; - static const uint32_t MinimumDynamicCapacity = 8; - - static const uint32_t CapacityArray[]; - - // Capacity index which indicates the array's length is also its capacity. - static const uint32_t CapacityMatchesLengthIndex = 0; - - private: - static inline uint32_t computeCapacity(uint32_t index, uint32_t length) { - if (index == CapacityMatchesLengthIndex) - return length; - return CapacityArray[index]; - } - - static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length); - static uint32_t exactCapacityIndex(uint32_t capacity); - - public: - static const Class class_; - - static bool obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp); - - static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle<PropertyDescriptor> desc, - ObjectOpResult& result); - - static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); - - static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp); - - static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result); - - static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<PropertyDescriptor> desc); - - static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result); - - static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly); - static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); - - inline const UnboxedLayout& layout() const; - - const UnboxedLayout& layoutDontCheckGeneration() const { - return group()->unboxedLayoutDontCheckGeneration(); - } - - JSValueType elementType() const { - return layoutDontCheckGeneration().elementType(); - } - - uint32_t elementSize() const { - return UnboxedTypeSize(elementType()); - } - - static bool convertToNative(JSContext* cx, JSObject* obj); - static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group, - uint32_t length, NewObjectKind newKind, - uint32_t maxLength = MaximumCapacity); - - static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, - ObjectGroup* group, Shape* shape); - bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group); - - void fillAfterConvert(ExclusiveContext* cx, - Handle<GCVector<Value>> values, size_t* valueCursor); - - static void trace(JSTracer* trc, JSObject* object); - static void objectMoved(JSObject* obj, const JSObject* old); - static void finalize(FreeOp* fop, JSObject* obj); - - static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, - gc::AllocKind allocKind); - - uint8_t* elements() { - return elements_; - } - - bool hasInlineElements() const { - return elements_ == &inlineElements_[0]; - } - - uint32_t length() const { - return length_; - } - - uint32_t initializedLength() const { - return capacityIndexAndInitializedLength_ & InitializedLengthMask; - } - - uint32_t capacityIndex() const { - return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift; - } - - uint32_t capacity() const { - return computeCapacity(capacityIndex(), length()); - } - - bool containsProperty(ExclusiveContext* cx, jsid id); - - bool setElement(ExclusiveContext* cx, size_t index, const Value& v); - bool initElement(ExclusiveContext* cx, size_t index, const Value& v); - void initElementNoTypeChange(size_t index, const Value& v); - Value getElement(size_t index); - - template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index, - const Value& v); - template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v); - template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index, - const Value& v); - template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v); - template <JSValueType Type> inline Value getElementSpecific(size_t index); - template <JSValueType Type> inline void triggerPreBarrier(size_t index); - - bool growElements(ExclusiveContext* cx, size_t cap); - void shrinkElements(ExclusiveContext* cx, size_t cap); - - static uint32_t offsetOfElements() { - return offsetof(UnboxedArrayObject, elements_); - } - static uint32_t offsetOfLength() { - return offsetof(UnboxedArrayObject, length_); - } - static uint32_t offsetOfCapacityIndexAndInitializedLength() { - return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_); - } - static uint32_t offsetOfInlineElements() { - return offsetof(UnboxedArrayObject, inlineElements_); - } - - void setLengthInt32(uint32_t length) { - MOZ_ASSERT(length <= INT32_MAX); - length_ = length; - } - - inline void setLength(ExclusiveContext* cx, uint32_t len); - inline void setInitializedLength(uint32_t initlen); - - inline void setInitializedLengthNoBarrier(uint32_t initlen) { - MOZ_ASSERT(initlen <= InitializedLengthMask); - capacityIndexAndInitializedLength_ = - (capacityIndexAndInitializedLength_ & CapacityMask) | initlen; - } - - private: - void setInlineElements() { - elements_ = &inlineElements_[0]; - } - - void setCapacityIndex(uint32_t index) { - MOZ_ASSERT(index <= (CapacityMask >> CapacityShift)); - capacityIndexAndInitializedLength_ = - (index << CapacityShift) | initializedLength(); - } -}; - } // namespace js namespace JS { |