diff options
Diffstat (limited to 'js/src')
38 files changed, 368 insertions, 2835 deletions
diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 710c7a76c..c6bd2d300 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -947,7 +947,7 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports) { MOZ_ASSERT(!self->namespace_()); - MOZ_ASSERT(exports->is<ArrayObject>() || exports->is<UnboxedArrayObject>()); + MOZ_ASSERT(exports->is<ArrayObject>()); RootedModuleNamespaceObject ns(cx, ModuleNamespaceObject::create(cx, self)); if (!ns) 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/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index 3b83df74e..0f0d4a66a 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -93,10 +93,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_Elements: case MDefinition::Op_MaybeCopyElementsForWrite: case MDefinition::Op_MaybeToDoubleElement: - case MDefinition::Op_UnboxedArrayLength: - case MDefinition::Op_UnboxedArrayInitializedLength: - case MDefinition::Op_IncrementUnboxedArrayInitializedLength: - case MDefinition::Op_SetUnboxedArrayInitializedLength: case MDefinition::Op_TypedArrayLength: case MDefinition::Op_SetTypedObjectOffset: case MDefinition::Op_SetDisjointTypedElements: diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index bf96932d1..7fb586811 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -787,9 +787,6 @@ BaselineCacheIRCompiler::emitGuardClass() case GuardClassKind::Array: clasp = &ArrayObject::class_; break; - case GuardClassKind::UnboxedArray: - clasp = &UnboxedArrayObject::class_; - break; case GuardClassKind::MappedArguments: clasp = &MappedArgumentsObject::class_; break; @@ -1004,19 +1001,6 @@ BaselineCacheIRCompiler::emitLoadInt32ArrayLengthResult() } bool -BaselineCacheIRCompiler::emitLoadUnboxedArrayLengthResult() -{ - Register obj = allocator.useRegister(masm, reader.objOperandId()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), R0.scratchReg()); - masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0); - - // The int32 type was monitored when attaching the stub, so we can - // just return. - emitReturnFromIC(); - return true; -} - -bool BaselineCacheIRCompiler::emitLoadArgumentsObjectLengthResult() { Register obj = allocator.useRegister(masm, reader.objOperandId()); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 863c61161..1d230e083 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1366,7 +1366,7 @@ IsNativeDenseElementAccess(HandleObject obj, HandleValue key) static bool IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key) { - if (!obj->isNative() && !obj->is<UnboxedArrayObject>()) + if (!obj->isNative()) return false; if (key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>()) return true; @@ -1470,20 +1470,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ script = rootedScript; } - // Check for UnboxedArray[int] accesses. - if (obj->is<UnboxedArrayObject>() && rhs.isInt32() && rhs.toInt32() >= 0) { - JitSpew(JitSpew_BaselineIC, " Generating GetElem(UnboxedArray[Int32]) stub"); - ICGetElem_UnboxedArray::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - obj->group()); - ICStub* unboxedStub = compiler.getStub(compiler.getStubSpace(script)); - if (!unboxedStub) - return false; - - stub->addNewStub(unboxedStub); - *attached = true; - return true; - } - // Check for TypedArray[int] => Number and TypedObject[int] => Number accesses. if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) && rhs.isNumber() && @@ -2090,56 +2076,6 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler& masm) } // -// GetElem_UnboxedArray -// - -bool -ICGetElem_UnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) -{ - MOZ_ASSERT(engine_ == Engine::Baseline); - - Label failure; - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - masm.branchTestInt32(Assembler::NotEqual, R1, &failure); - - AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); - Register scratchReg = regs.takeAny(); - - // Unbox R0 and group guard. - Register obj = masm.extractObject(R0, ExtractTemp0); - masm.loadPtr(Address(ICStubReg, ICGetElem_UnboxedArray::offsetOfGroup()), scratchReg); - masm.branchTestObjGroup(Assembler::NotEqual, obj, scratchReg, &failure); - - // Unbox key. - Register key = masm.extractInt32(R1, ExtractTemp1); - - // Bounds check. - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), - scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Load value. - size_t width = UnboxedTypeSize(elementType_); - BaseIndex addr(scratchReg, key, ScaleFromElemWidth(width)); - masm.loadUnboxedProperty(addr, elementType_, R0); - - // Only monitor the result if its type might change. - if (elementType_ == JSVAL_TYPE_OBJECT) - EmitEnterTypeMonitorIC(masm); - else - EmitReturnFromIC(masm); - - // Failure case - jump to next stub - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - -// // GetElem_TypedArray // @@ -2447,10 +2383,6 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index, if (initLength < oldInitLength || capacity < oldCapacity) return false; - // Unboxed arrays need to be able to emit floating point code. - if (obj->is<UnboxedArrayObject>() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint) - return false; - Shape* shape = obj->maybeShape(); // Cannot optimize if the shape changed. @@ -2871,29 +2803,6 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) masm.loadValue(valueAddr, tmpVal); EmitPreBarrier(masm, element, MIRType::Value); masm.storeValue(tmpVal, element); - } else { - // Set element on an unboxed array. - - // Bounds check. - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Compute the address being written to. - BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_))); - - EmitUnboxedPreBarrierForBaseline(masm, address, unboxedType_); - - Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value)); - masm.Push(R0); - masm.loadValue(valueAddr, R0); - masm.storeUnboxedProperty(address, unboxedType_, - ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0); - masm.Pop(R0); } EmitReturnFromIC(masm); @@ -3087,40 +2996,6 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm) BaseIndex element(scratchReg, key, TimesEight); masm.loadValue(valueAddr, tmpVal); masm.storeValue(tmpVal, element); - } else { - // Adding element to an unboxed array. - - // Bounds check (key == initLength) - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLengthAddr, scratchReg); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg); - masm.branch32(Assembler::NotEqual, scratchReg, key, &failure); - - // Capacity check. - masm.checkUnboxedArrayCapacity(obj, RegisterOrInt32Constant(key), scratchReg, &failure); - - // Load obj->elements. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg); - - // Write the value first, since this can fail. No need for pre-barrier - // since we're not overwriting an old value. - masm.Push(R0); - Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value)); - masm.loadValue(valueAddr, R0); - BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_))); - masm.storeUnboxedProperty(address, unboxedType_, - ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0); - masm.Pop(R0); - - // Increment initialized length. - masm.add32(Imm32(1), initLengthAddr); - - // If length is now <= key, increment length. - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - Label skipIncrementLength; - masm.branch32(Assembler::Above, lengthAddr, key, &skipIncrementLength); - masm.add32(Imm32(1), lengthAddr); - masm.bind(&skipIncrementLength); } EmitReturnFromIC(masm); @@ -5894,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; @@ -8301,19 +8176,6 @@ ICGetElem_Dense::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorSt return New<ICGetElem_Dense>(cx, space, other.jitCode(), firstMonitorStub, other.shape_); } -ICGetElem_UnboxedArray::ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, - ObjectGroup *group) - : ICMonitoredStub(GetElem_UnboxedArray, stubCode, firstMonitorStub), - group_(group) -{ } - -/* static */ ICGetElem_UnboxedArray* -ICGetElem_UnboxedArray::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, - ICGetElem_UnboxedArray& other) -{ - return New<ICGetElem_UnboxedArray>(cx, space, other.jitCode(), firstMonitorStub, other.group_); -} - ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type) : ICStub(GetElem_TypedArray, stubCode), shape_(shape) 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/CacheIR.cpp b/js/src/jit/CacheIR.cpp index f1061af70..6822a70af 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -175,7 +175,7 @@ TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOper } else { writer.guardNoUnboxedExpando(objId); } - } else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) { + } else if (obj->is<TypedObject>()) { writer.guardGroup(objId, obj->group()); } else { Shape* shape = obj->maybeShape(); @@ -368,13 +368,6 @@ GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject ob return true; } - if (obj->is<UnboxedArrayObject>()) { - writer.guardClass(objId, GuardClassKind::UnboxedArray); - writer.loadUnboxedArrayLengthResult(objId); - emitted_ = true; - return true; - } - if (obj->is<ArgumentsObject>() && !obj->as<ArgumentsObject>().hasOverriddenLength()) { if (obj->is<MappedArgumentsObject>()) { writer.guardClass(objId, GuardClassKind::MappedArguments); diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 51e55f48b..4fd8575f0 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -96,7 +96,6 @@ class ObjOperandId : public OperandId _(LoadUnboxedPropertyResult) \ _(LoadTypedObjectResult) \ _(LoadInt32ArrayLengthResult) \ - _(LoadUnboxedArrayLengthResult) \ _(LoadArgumentsObjectLengthResult) \ _(LoadUndefinedResult) @@ -128,7 +127,6 @@ struct StubField { enum class GuardClassKind { Array, - UnboxedArray, MappedArguments, UnmappedArguments, }; @@ -327,9 +325,6 @@ class MOZ_RAII CacheIRWriter void loadInt32ArrayLengthResult(ObjOperandId obj) { writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj); } - void loadUnboxedArrayLengthResult(ObjOperandId obj) { - writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj); - } void loadArgumentsObjectLengthResult(ObjOperandId obj) { writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 6d1fb6b9b..485e881fe 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3183,9 +3183,7 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins) void CodeGenerator::visitElements(LElements* lir) { - Address elements(ToRegister(lir->object()), - lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements() - : NativeObject::offsetOfElements()); + Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements()); masm.loadPtr(elements, ToRegister(lir->output())); } @@ -5341,21 +5339,11 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir) bool canInline = true; size_t inlineLength = 0; - if (templateObject->is<ArrayObject>()) { - if (templateObject->as<ArrayObject>().hasFixedElements()) { - size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()); - inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER; - } else { - canInline = false; - } + if (templateObject->as<ArrayObject>().hasFixedElements()) { + size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()); + inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER; } else { - if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) { - size_t nbytes = - templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements(); - inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize(); - } else { - canInline = false; - } + canInline = false; } if (canInline) { @@ -7812,49 +7800,6 @@ CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir) } void -CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->output()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result); -} - -void -CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - Register result = ToRegister(lir->output()); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result); -} - -void -CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); -} - -void -CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir) -{ - Register obj = ToRegister(lir->object()); - RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length()); - Register temp = ToRegister(lir->temp()); - - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLengthAddr, temp); - masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp); - - if (key.isRegister()) - masm.or32(key.reg(), temp); - else - masm.or32(Imm32(key.constant()), temp); - - masm.store32(temp, initLengthAddr); -} - -void CodeGenerator::visitNotO(LNotO* lir) { MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(), @@ -8150,46 +8095,19 @@ CodeGenerator::emitStoreElementHoleT(T* lir) OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir); addOutOfLineCode(ool, lir->mir()); - Register obj = ToRegister(lir->object()); Register elements = ToRegister(lir->elements()); const LAllocation* index = lir->index(); RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); - JSValueType unboxedType = lir->mir()->unboxedType(); - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - - if (lir->mir()->needsBarrier()) - emitPreBarrier(elements, index, 0); - - masm.bind(ool->rejoinStore()); - emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(), - elements, index, 0); - } else { - Register temp = ToRegister(lir->getTemp(0)); - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, temp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp); - masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry()); - - ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type()); - - if (index->isConstant()) { - Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType)); - EmitUnboxedPreBarrier(masm, address, unboxedType); + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, v, nullptr); - } else { - BaseIndex address(elements, ToRegister(index), - ScaleFromElemWidth(UnboxedTypeSize(unboxedType))); - EmitUnboxedPreBarrier(masm, address, unboxedType); + if (lir->mir()->needsBarrier()) + emitPreBarrier(elements, index, 0); - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, v, nullptr); - } - } + masm.bind(ool->rejoinStore()); + emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(), + elements, index, 0); masm.bind(ool->rejoin()); } @@ -8209,47 +8127,22 @@ CodeGenerator::emitStoreElementHoleV(T* lir) OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir); addOutOfLineCode(ool, lir->mir()); - Register obj = ToRegister(lir->object()); Register elements = ToRegister(lir->elements()); const LAllocation* index = lir->index(); const ValueOperand value = ToValue(lir, T::Value); RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); - JSValueType unboxedType = lir->mir()->unboxedType(); - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - - if (lir->mir()->needsBarrier()) - emitPreBarrier(elements, index, 0); + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); - masm.bind(ool->rejoinStore()); - if (index->isConstant()) - masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value))); - else - masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight)); - } else { - Register temp = ToRegister(lir->getTemp(0)); - Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, temp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp); - masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry()); - - if (index->isConstant()) { - Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType)); - EmitUnboxedPreBarrier(masm, address, unboxedType); - - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr); - } else { - BaseIndex address(elements, ToRegister(index), - ScaleFromElemWidth(UnboxedTypeSize(unboxedType))); - EmitUnboxedPreBarrier(masm, address, unboxedType); + if (lir->mir()->needsBarrier()) + emitPreBarrier(elements, index, 0); - masm.bind(ool->rejoinStore()); - masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr); - } - } + masm.bind(ool->rejoinStore()); + if (index->isConstant()) + masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value))); + else + masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight)); masm.bind(ool->rejoin()); } @@ -8334,8 +8227,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) const LAllocation* index; MIRType valueType; ConstantOrRegister value; - JSValueType unboxedType; - LDefinition *temp = nullptr; if (ins->isStoreElementHoleV()) { LStoreElementHoleV* store = ins->toStoreElementHoleV(); @@ -8344,8 +8235,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) index = store->index(); valueType = store->mir()->value()->type(); value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value)); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else if (ins->isFallibleStoreElementV()) { LFallibleStoreElementV* store = ins->toFallibleStoreElementV(); object = ToRegister(store->object()); @@ -8353,8 +8242,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) index = store->index(); valueType = store->mir()->value()->type(); value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value)); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else if (ins->isStoreElementHoleT()) { LStoreElementHoleT* store = ins->toStoreElementHoleT(); object = ToRegister(store->object()); @@ -8365,8 +8252,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) value = ConstantOrRegister(store->value()->toConstant()->toJSValue()); else value = TypedOrValueRegister(valueType, ToAnyRegister(store->value())); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } else { // ins->isFallibleStoreElementT() LFallibleStoreElementT* store = ins->toFallibleStoreElementT(); object = ToRegister(store->object()); @@ -8377,8 +8262,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) value = ConstantOrRegister(store->value()->toConstant()->toJSValue()); else value = TypedOrValueRegister(valueType, ToAnyRegister(store->value())); - unboxedType = store->mir()->unboxedType(); - temp = store->getTemp(0); } RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); @@ -8389,54 +8272,32 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) Label callStub; #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) // Had to reimplement for MIPS because there are no flags. - if (unboxedType == JSVAL_TYPE_MAGIC) { - Address initLength(elements, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, &callStub); - } else { - Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - masm.load32(initLength, ToRegister(temp)); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp)); - masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub); - } + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, &callStub); #else masm.j(Assembler::NotEqual, &callStub); #endif - if (unboxedType == JSVAL_TYPE_MAGIC) { - // Check array capacity. - masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()), - key, &callStub); - - // Update initialized length. The capacity guard above ensures this won't overflow, - // due to MAX_DENSE_ELEMENTS_COUNT. - masm.inc32(&key); - masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength())); + // Check array capacity. + masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()), + key, &callStub); - // Update length if length < initializedLength. - Label dontUpdate; - masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()), - key, &dontUpdate); - masm.store32(key, Address(elements, ObjectElements::offsetOfLength())); - masm.bind(&dontUpdate); - - masm.dec32(&key); - } else { - // Check array capacity. - masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub); + // Update initialized length. The capacity guard above ensures this won't overflow, + // due to MAX_DENSE_ELEMENTS_COUNT. + masm.inc32(&key); + masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength())); - // Update initialized length. - masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); + // Update length if length < initializedLength. + Label dontUpdate; + masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()), + key, &dontUpdate); + masm.store32(key, Address(elements, ObjectElements::offsetOfLength())); + masm.bind(&dontUpdate); - // Update length if length < initializedLength. - Address lengthAddr(object, UnboxedArrayObject::offsetOfLength()); - Label dontUpdate; - masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate); - masm.add32(Imm32(1), lengthAddr); - masm.bind(&dontUpdate); - } + masm.dec32(&key); if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) && - unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double) + valueType != MIRType::Double) { // The inline path for StoreElementHoleT and FallibleStoreElementT does not always store // the type tag, so we do the store on the OOL path. We use MIRType::None for the element @@ -8526,9 +8387,6 @@ typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*); static const VMFunction ConvertUnboxedPlainObjectToNativeInfo = FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedPlainObject::convertToNative, "UnboxedPlainObject::convertToNative"); -static const VMFunction ConvertUnboxedArrayObjectToNativeInfo = - FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative, - "UnboxedArrayObject::convertToNative"); typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = @@ -8554,20 +8412,11 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R // Load elements and length, and VM call if length != initializedLength. RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); - masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp); + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); + masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp); - Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - } else { - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp); - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp); - - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry()); - } + Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); // Test for length != 0. On zero length either take a VM call or generate // an undefined value, depending on whether the call is known to produce @@ -8579,13 +8428,10 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R // According to the spec we need to set the length 0 (which is already 0). // This is observable when the array length is made non-writable. - // Handle this case in the OOL. When freezing an unboxed array it is converted - // to an normal array. - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); - Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); - masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); - } + // Handle this case in the OOL. + Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); + Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); + masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); masm.moveValue(UndefinedValue(), out.valueReg()); masm.jump(&done); @@ -8597,41 +8443,25 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R masm.dec32(&key); if (mir->mode() == MArrayPopShift::Pop) { - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - BaseIndex addr(elementsTemp, lengthTemp, TimesEight); - masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); - } else { - size_t elemSize = UnboxedTypeSize(mir->unboxedType()); - BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize)); - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); - } + BaseIndex addr(elementsTemp, lengthTemp, TimesEight); + masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); } else { MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift); Address addr(elementsTemp, 0); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) - masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); - else - masm.loadUnboxedProperty(addr, mir->unboxedType(), out); + masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry()); } - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - // Handle the failure case when the array length is non-writable in the - // OOL path. (Unlike in the adding-an-element cases, we can't rely on the - // capacity <= length invariant for such arrays to avoid an explicit - // check.) - Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); - Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); - masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); + // Handle the failure case when the array length is non-writable in the + // OOL path. (Unlike in the adding-an-element cases, we can't rely on the + // capacity <= length invariant for such arrays to avoid an explicit + // check.) + Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags()); + Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH); + masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry()); - // Now adjust length and initializedLength. - masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength())); - masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); - } else { - // Unboxed arrays always have writable lengths. Adjust length and - // initializedLength. - masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength())); - masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); - } + // Now adjust length and initializedLength. + masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength())); + masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); if (mir->mode() == MArrayPopShift::Shift) { // Don't save the temp registers. @@ -8681,50 +8511,27 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length)); RegisterOrInt32Constant key = RegisterOrInt32Constant(length); - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - // Load elements and length. - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); - masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length); - - // Guard length == initializedLength. - Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); - masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - // Guard length < capacity. - Address capacity(elementsTemp, ObjectElements::offsetOfCapacity()); - masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry()); + // Load elements and length. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp); + masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length); - // Do the store. - masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight)); - } else { - // Load initialized length. - masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length); + // Guard length == initializedLength. + Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, key, ool->entry()); - // Guard length == initializedLength. - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry()); + // Guard length < capacity. + Address capacity(elementsTemp, ObjectElements::offsetOfCapacity()); + masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry()); - // Guard length < capacity. - masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry()); - - // Load elements and do the store. - masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp); - size_t elemSize = UnboxedTypeSize(mir->unboxedType()); - BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize)); - masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr); - } + // Do the store. + masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight)); masm.inc32(&key); // Update length and initialized length. - if (mir->unboxedType() == JSVAL_TYPE_MAGIC) { - masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength())); - masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); - } else { - masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength())); - masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); - } + masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength())); + masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength())); masm.bind(ool->rejoin()); } @@ -10529,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. @@ -10922,7 +10718,7 @@ CodeGenerator::visitInArray(LInArray* lir) } masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength); - if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) { + if (mir->needsHoleCheck()) { NativeObject::elementsSizeMustNotOverflow(); Address address = Address(elements, index * sizeof(Value)); masm.branchTestMagic(Assembler::Equal, address, &falseBranch); @@ -10935,7 +10731,7 @@ CodeGenerator::visitInArray(LInArray* lir) failedInitLength = &negativeIntCheck; masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength); - if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) { + if (mir->needsHoleCheck()) { BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight); masm.branchTestMagic(Assembler::Equal, address, &falseBranch); } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 292f163b5..b5f170d84 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -234,10 +234,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitSubstr(LSubstr* lir); void visitInitializedLength(LInitializedLength* lir); void visitSetInitializedLength(LSetInitializedLength* lir); - void visitUnboxedArrayLength(LUnboxedArrayLength* lir); - void visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir); - void visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir); - void visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir); void visitNotO(LNotO* ins); void visitNotV(LNotV* ins); void visitBoundsCheck(LBoundsCheck* lir); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index af85011be..3d964d1c6 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -7336,12 +7336,6 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u if (!templateObject) return true; - if (templateObject->is<UnboxedArrayObject>()) { - MOZ_ASSERT(templateObject->as<UnboxedArrayObject>().capacity() >= length); - if (!templateObject->as<UnboxedArrayObject>().hasInlineElements()) - return true; - } - MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); size_t arraySlots = @@ -7597,7 +7591,6 @@ IonBuilder::jsop_initelem_array() // intializer, and that arrays are marked as non-packed when writing holes // to them during initialization. bool needStub = false; - JSValueType unboxedType = JSVAL_TYPE_MAGIC; if (shouldAbortOnPreliminaryGroups(obj)) { needStub = true; } else if (!obj->resultTypeSet() || @@ -7608,12 +7601,6 @@ IonBuilder::jsop_initelem_array() } else { MOZ_ASSERT(obj->resultTypeSet()->getObjectCount() == 1); TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0); - if (initializer->clasp() == &UnboxedArrayObject::class_) { - if (initializer->group()->unboxedLayout().nativeGroup()) - needStub = true; - else - unboxedType = initializer->group()->unboxedLayout().elementType(); - } if (value->type() == MIRType::MagicHole) { if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED)) needStub = true; @@ -7633,60 +7620,46 @@ IonBuilder::jsop_initelem_array() return resumeAfter(store); } - return initializeArrayElement(obj, index, value, unboxedType, /* addResumePoint = */ true); + return initializeArrayElement(obj, index, value, /* addResumePoint = */ true); } bool IonBuilder::initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, - JSValueType unboxedType, bool addResumePointAndIncrementInitializedLength) { MConstant* id = MConstant::New(alloc(), Int32Value(index)); current->add(id); // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); - if (unboxedType != JSVAL_TYPE_MAGIC) { - // Note: storeUnboxedValue takes care of any post barriers on the value. - storeUnboxedValue(obj, elements, 0, id, unboxedType, value, /* preBarrier = */ false); - - if (addResumePointAndIncrementInitializedLength) { - MInstruction* increment = MIncrementUnboxedArrayInitializedLength::New(alloc(), obj); - current->add(increment); - - if (!resumeAfter(increment)) - return false; - } - } else { - if (NeedsPostBarrier(value)) - current->add(MPostWriteBarrier::New(alloc(), obj, value)); + if (NeedsPostBarrier(value)) + current->add(MPostWriteBarrier::New(alloc(), obj, value)); - if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) || - (obj->isNullarySharedStub() && - obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles)) - { - MInstruction* valueDouble = MToDouble::New(alloc(), value); - current->add(valueDouble); - value = valueDouble; - } + if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) || + (obj->isNullarySharedStub() && + obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles)) + { + MInstruction* valueDouble = MToDouble::New(alloc(), value); + current->add(valueDouble); + value = valueDouble; + } - // Store the value. - MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, + // Store the value. + MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, /* needsHoleCheck = */ false); - current->add(store); + current->add(store); - if (addResumePointAndIncrementInitializedLength) { - // Update the initialized length. (The template object for this - // array has the array's ultimate length, so the length field is - // already correct: no updating needed.) - MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id); - current->add(initLength); + if (addResumePointAndIncrementInitializedLength) { + // Update the initialized length. (The template object for this + // array has the array's ultimate length, so the length field is + // already correct: no updating needed.) + MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id); + current->add(initLength); - if (!resumeAfter(initLength)) - return false; - } + if (!resumeAfter(initLength)) + return false; } return true; @@ -8175,8 +8148,7 @@ IonBuilder::maybeMarkEmpty(MDefinition* ins) static bool ClassHasEffectlessLookup(const Class* clasp) { - return (clasp == &UnboxedArrayObject::class_) || - IsTypedObjectClass(clasp) || + return IsTypedObjectClass(clasp) || (clasp->isNative() && !clasp->getOpsLookupProperty()); } @@ -9452,12 +9424,9 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index) { MOZ_ASSERT(*emitted == false); - JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, index); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), obj, index)) { - trackOptimizationOutcome(TrackedOutcome::AccessNotDense); - return true; - } + if (!ElementAccessIsDenseNative(constraints(), obj, index)) { + trackOptimizationOutcome(TrackedOutcome::AccessNotDense); + return true; } // Don't generate a fast path if there have been bounds check failures @@ -9474,7 +9443,7 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index) return true; } - if (!jsop_getelem_dense(obj, index, unboxedType)) + if (!jsop_getelem_dense(obj, index)) return false; trackOptimizationSuccess(); @@ -9826,7 +9795,7 @@ IonBuilder::computeHeapType(const TemporaryTypeSet* objTypes, const jsid id) } bool -IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType) +IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index) { TemporaryTypeSet* types = bytecodeTypes(pc); @@ -9850,7 +9819,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType !ElementAccessHasExtraIndexedProperty(this, obj); MIRType knownType = MIRType::Value; - if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier) + if (barrier == BarrierKind::NoBarrier) knownType = GetElemKnownType(needsHoleCheck, types); // Ensure index is an integer. @@ -9859,13 +9828,13 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType index = idInt32; // Get the elements vector. - MInstruction* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MInstruction* elements = MElements::New(alloc(), obj); current->add(elements); // Note: to help GVN, use the original MElements instruction and not // MConvertElementsToDoubles as operand. This is fine because converting // elements to double does not change the initialized length. - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); // If we can load the element as a definite double, make sure to check that // the array has been converted to homogenous doubles first. @@ -9881,7 +9850,6 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType } bool loadDouble = - unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier && loopDepth_ && inBounds && @@ -9900,18 +9868,13 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType // hoisting. index = addBoundsCheck(index, initLength); - if (unboxedType != JSVAL_TYPE_MAGIC) { - load = loadUnboxedValue(elements, 0, index, unboxedType, barrier, types); - } else { - load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); - current->add(load); - } + load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); + current->add(load); } else { // This load may return undefined, so assume that we *can* read holes, // or that we can read out-of-bounds accesses. In this case, the bounds // check is part of the opcode. - load = MLoadElementHole::New(alloc(), elements, index, initLength, - unboxedType, needsHoleCheck); + load = MLoadElementHole::New(alloc(), elements, index, initLength, needsHoleCheck); current->add(load); // If maybeUndefined was true, the typeset must have undefined, and @@ -9921,8 +9884,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType } if (knownType != MIRType::Value) { - if (unboxedType == JSVAL_TYPE_MAGIC) - load->setResultType(knownType); + load->setResultType(knownType); load->setResultTypeSet(types); } @@ -10369,12 +10331,9 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object, { MOZ_ASSERT(*emitted == false); - JSValueType unboxedType = UnboxedArrayElementType(constraints(), object, index); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), object, index)) { - trackOptimizationOutcome(TrackedOutcome::AccessNotDense); - return true; - } + if (!ElementAccessIsDenseNative(constraints(), object, index)) { + trackOptimizationOutcome(TrackedOutcome::AccessNotDense); + return true; } if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, @@ -10408,7 +10367,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object, } // Emit dense setelem variant. - if (!jsop_setelem_dense(conversion, object, index, value, unboxedType, writeHole, emitted)) + if (!jsop_setelem_dense(conversion, object, index, value, writeHole, emitted)) return false; if (!*emitted) { @@ -10498,13 +10457,11 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object, bool IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MDefinition* obj, MDefinition* id, MDefinition* value, - JSValueType unboxedType, bool writeHole, bool* emitted) + bool writeHole, bool* emitted) { MOZ_ASSERT(*emitted == false); - MIRType elementType = MIRType::None; - if (unboxedType == JSVAL_TYPE_MAGIC) - elementType = DenseNativeElementType(constraints(), obj); + MIRType elementType = DenseNativeElementType(constraints(), obj); bool packed = ElementAccessIsPacked(constraints(), obj); // Writes which are on holes in the object do not have to bail out if they @@ -10534,7 +10491,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); // Ensure the value is a double, if double conversion might be needed. @@ -10571,7 +10528,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MInstruction* store; MStoreElementCommon* common = nullptr; if (writeHole && hasNoExtraIndexedProperty && !mayBeFrozen) { - MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue, unboxedType); + MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue); store = ins; common = ins; @@ -10583,27 +10540,23 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, bool strict = IsStrictSetPC(pc); MFallibleStoreElement* ins = MFallibleStoreElement::New(alloc(), obj, elements, id, - newValue, unboxedType, strict); + newValue, strict); store = ins; common = ins; current->add(ins); current->push(value); } else { - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); id = addBoundsCheck(id, initLength); bool needsHoleCheck = !packed && !hasNoExtraIndexedProperty; - if (unboxedType != JSVAL_TYPE_MAGIC) { - store = storeUnboxedValue(obj, elements, 0, id, unboxedType, newValue); - } else { - MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); - store = ins; - common = ins; + MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); + store = ins; + common = ins; - current->add(store); - } + current->add(store); current->push(value); } @@ -10721,18 +10674,6 @@ IonBuilder::jsop_length_fastPath() return true; } - // Compute the length for unboxed array objects. - if (UnboxedArrayElementType(constraints(), obj, nullptr) != JSVAL_TYPE_MAGIC && - !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW)) - { - current->pop(); - - MUnboxedArrayLength* length = MUnboxedArrayLength::New(alloc(), obj); - current->add(length); - current->push(length); - return true; - } - // Compute the length for array typed objects. TypedObjectPrediction prediction = typedObjectPrediction(obj); if (!prediction.isUseless()) { @@ -13687,11 +13628,8 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) if (shouldAbortOnPreliminaryGroups(obj)) return true; - JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id); - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!ElementAccessIsDenseNative(constraints(), obj, id)) - return true; - } + if (!ElementAccessIsDenseNative(constraints(), obj, id)) + return true; if (ElementAccessHasExtraIndexedProperty(this, obj)) return true; @@ -13706,10 +13644,10 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) id = idInt32; // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC); + MElements* elements = MElements::New(alloc(), obj); current->add(elements); - MInstruction* initLength = initializedLength(obj, elements, unboxedType); + MInstruction* initLength = initializedLength(obj, elements); // If there are no holes, speculate the InArray check will not fail. if (!needsHoleCheck && !failedBoundsCheck_) { @@ -13719,8 +13657,7 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id) } // Check if id < initLength and elem[id] not a hole. - MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck, - unboxedType); + MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck); current->add(ins); current->push(ins); @@ -14398,32 +14335,24 @@ IonBuilder::constantInt(int32_t i) } MInstruction* -IonBuilder::initializedLength(MDefinition* obj, MDefinition* elements, JSValueType unboxedType) +IonBuilder::initializedLength(MDefinition* obj, MDefinition* elements) { - MInstruction* res; - if (unboxedType != JSVAL_TYPE_MAGIC) - res = MUnboxedArrayInitializedLength::New(alloc(), obj); - else - res = MInitializedLength::New(alloc(), elements); + MInstruction* res = MInitializedLength::New(alloc(), elements); current->add(res); return res; } MInstruction* -IonBuilder::setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count) +IonBuilder::setInitializedLength(MDefinition* obj, size_t count) { MOZ_ASSERT(count); - MInstruction* res; - if (unboxedType != JSVAL_TYPE_MAGIC) { - res = MSetUnboxedArrayInitializedLength::New(alloc(), obj, constant(Int32Value(count))); - } else { - // MSetInitializedLength takes the index of the last element, rather - // than the count itself. - MInstruction* elements = MElements::New(alloc(), obj, /* unboxed = */ false); - current->add(elements); - res = MSetInitializedLength::New(alloc(), elements, constant(Int32Value(count - 1))); - } + // MSetInitializedLength takes the index of the last element, rather + // than the count itself. + MInstruction* elements = MElements::New(alloc(), obj, /* unboxed = */ false); + current->add(elements); + MInstruction* res = + MSetInitializedLength::New(alloc(), elements, constant(Int32Value(count - 1))); current->add(res); return res; } diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 77528ad37..1b97c4743 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -346,9 +346,8 @@ class IonBuilder MConstant* constant(const Value& v); MConstant* constantInt(int32_t i); - MInstruction* initializedLength(MDefinition* obj, MDefinition* elements, - JSValueType unboxedType); - MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count); + MInstruction* initializedLength(MDefinition* obj, MDefinition* elements); + MInstruction* setInitializedLength(MDefinition* obj, size_t count); // Improve the type information at tests MOZ_MUST_USE bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test); @@ -611,7 +610,6 @@ class IonBuilder TypedObjectPrediction elemTypeReprs, uint32_t elemSize); MOZ_MUST_USE bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, - JSValueType unboxedType, bool addResumePointAndIncrementInitializedLength); // jsop_getelem() helpers. @@ -723,15 +721,13 @@ class IonBuilder MOZ_MUST_USE bool jsop_bindname(PropertyName* name); MOZ_MUST_USE bool jsop_bindvar(); MOZ_MUST_USE bool jsop_getelem(); - MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, - JSValueType unboxedType); + MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index); MOZ_MUST_USE bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType); MOZ_MUST_USE bool jsop_setelem(); MOZ_MUST_USE bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, MDefinition* object, MDefinition* index, - MDefinition* value, JSValueType unboxedType, - bool writeHole, bool* emitted); + MDefinition* value, bool writeHole, bool* emitted); MOZ_MUST_USE bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType, MDefinition* object, MDefinition* index, MDefinition* value); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 0208db6ae..81cf9d9bb 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -639,9 +639,6 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher, } else { masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure); } - } else if (obj->is<UnboxedArrayObject>()) { - MOZ_ASSERT(failure); - masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure); } else if (obj->is<TypedObject>()) { attacher.branchNextStubOrLabel(masm, Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), @@ -1188,39 +1185,6 @@ GenerateArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& return true; } -static void -GenerateUnboxedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher, - JSObject* array, Register object, TypedOrValueRegister output, - Label* failures) -{ - Register outReg; - if (output.hasValue()) { - outReg = output.valueReg().scratchReg(); - } else { - MOZ_ASSERT(output.type() == MIRType::Int32); - outReg = output.typedReg().gpr(); - } - MOZ_ASSERT(object != outReg); - - TestMatchingReceiver(masm, attacher, object, array, failures); - - // Load length. - masm.load32(Address(object, UnboxedArrayObject::offsetOfLength()), outReg); - - // Check for a length that fits in an int32. - masm.branchTest32(Assembler::Signed, outReg, outReg, failures); - - if (output.hasValue()) - masm.tagValue(JSVAL_TYPE_INT32, outReg, output.valueReg()); - - // Success. - attacher.jumpRejoin(masm); - - // Failure. - masm.bind(failures); - attacher.jumpNextStub(masm); -} - // In this case, the code for TypedArray and SharedTypedArray is not the same, // because the code embeds pointers to the respective class arrays. Code that // caches the stub code must distinguish between the two cases. @@ -1595,40 +1559,6 @@ GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, } bool -GetPropertyIC::tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject obj, HandleId id, void* returnAddr, - bool* emitted) -{ - MOZ_ASSERT(canAttachStub()); - MOZ_ASSERT(!*emitted); - MOZ_ASSERT(outerScript->ionScript() == ion); - - if (!obj->is<UnboxedArrayObject>()) - return true; - - if (!JSID_IS_ATOM(id, cx->names().length)) - return true; - - if (obj->as<UnboxedArrayObject>().length() > INT32_MAX) - return true; - - if (!allowArrayLength(cx)) - return true; - - *emitted = true; - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - - Label failures; - emitIdGuard(masm, id, &failures); - - StubAttacher attacher(*this); - GenerateUnboxedArrayLength(cx, masm, attacher, obj, object(), output(), &failures); - return linkAndAttachStub(cx, masm, attacher, ion, "unboxed array length", - JS::TrackedOutcome::ICGetPropStub_UnboxedArrayLength); -} - -bool GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion, HandleObject obj, HandleId id, bool* emitted) { @@ -2203,9 +2133,6 @@ GetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, returnAddr, emitted)) return false; - if (!*emitted && !tryAttachUnboxedArrayLength(cx, outerScript, ion, obj, id, returnAddr, emitted)) - return false; - if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, id, emitted)) return false; } @@ -4026,7 +3953,7 @@ GetPropertyIC::tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval, TypedOrValueRegister output) { - if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>()) + if (!obj->is<TypedArrayObject>()) return false; MOZ_ASSERT(idval.isInt32() || idval.isString()); @@ -4057,13 +3984,6 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i return output.hasValue() || !output.typedReg().isFloat(); } - if (index >= obj->as<UnboxedArrayObject>().initializedLength()) - return false; - - JSValueType elementType = obj->as<UnboxedArrayObject>().elementType(); - if (elementType == JSVAL_TYPE_DOUBLE) - return output.hasValue(); - return output.hasValue() || !output.typedReg().isFloat(); } @@ -4140,46 +4060,27 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm, Label popObjectAndFail; - if (array->is<TypedArrayObject>()) { - // Guard on the initialized length. - Address length(object, TypedArrayObject::lengthOffset()); - masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures); + // Guard on the initialized length. + Address length(object, TypedArrayObject::lengthOffset()); + masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures); - // Save the object register on the stack in case of failure. - Register elementReg = object; - masm.push(object); + // Save the object register on the stack in case of failure. + Register elementReg = object; + masm.push(object); - // Load elements vector. - masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg); + // Load elements vector. + masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg); - // Load the value. We use an invalid register because the destination - // register is necessary a non double register. - Scalar::Type arrayType = array->as<TypedArrayObject>().type(); - int width = Scalar::byteSize(arrayType); - BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width)); - if (output.hasValue()) { - masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult, - elementReg, &popObjectAndFail); - } else { - masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail); - } + // Load the value. We use an invalid register because the destination + // register is necessary a non double register. + Scalar::Type arrayType = array->as<TypedArrayObject>().type(); + int width = Scalar::byteSize(arrayType); + BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width)); + if (output.hasValue()) { + masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult, + elementReg, &popObjectAndFail); } else { - // Save the object register on the stack in case of failure. - masm.push(object); - - // Guard on the initialized length. - masm.load32(Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), object); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), object); - masm.branch32(Assembler::BelowOrEqual, object, indexReg, &popObjectAndFail); - - // Load elements vector. - Register elementReg = object; - masm.loadPtr(Address(masm.getStackPointer(), 0), object); - masm.loadPtr(Address(object, UnboxedArrayObject::offsetOfElements()), elementReg); - - JSValueType elementType = array->as<UnboxedArrayObject>().elementType(); - BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(UnboxedTypeSize(elementType))); - masm.loadUnboxedProperty(source, elementType, output); + masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail); } masm.pop(object); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index aafa57c09..e185b5746 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2889,32 +2889,6 @@ LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) } void -LIRGenerator::visitUnboxedArrayLength(MUnboxedArrayLength* ins) -{ - define(new(alloc()) LUnboxedArrayLength(useRegisterAtStart(ins->object())), ins); -} - -void -LIRGenerator::visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins) -{ - define(new(alloc()) LUnboxedArrayInitializedLength(useRegisterAtStart(ins->object())), ins); -} - -void -LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins) -{ - add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins); -} - -void -LIRGenerator::visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins) -{ - add(new(alloc()) LSetUnboxedArrayInitializedLength(useRegister(ins->object()), - useRegisterOrConstant(ins->length()), - temp()), ins); -} - -void LIRGenerator::visitNot(MNot* ins) { MDefinition* op = ins->input(); @@ -3165,8 +3139,6 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) // Use a temp register when adding new elements to unboxed arrays. LDefinition tempDef = LDefinition::BogusTemp(); - if (ins->unboxedType() != JSVAL_TYPE_MAGIC) - tempDef = temp(); LInstruction* lir; switch (ins->value()->type()) { @@ -3199,8 +3171,6 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins) // Use a temp register when adding new elements to unboxed arrays. LDefinition tempDef = LDefinition::BogusTemp(); - if (ins->unboxedType() != JSVAL_TYPE_MAGIC) - tempDef = temp(); LInstruction* lir; switch (ins->value()->type()) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index e36620bce..b096bb143 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -216,10 +216,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitTypedObjectDescr(MTypedObjectDescr* ins); void visitInitializedLength(MInitializedLength* ins); void visitSetInitializedLength(MSetInitializedLength* ins); - void visitUnboxedArrayLength(MUnboxedArrayLength* ins); - void visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins); - void visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins); - void visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins); void visitNot(MNot* ins); void visitBoundsCheck(MBoundsCheck* ins); void visitBoundsCheckLower(MBoundsCheckLower* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 41ccd0ca7..748a70973 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -475,11 +475,6 @@ IonBuilder::inlineArray(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (templateObject->is<UnboxedArrayObject>()) { - if (templateObject->group()->unboxedLayout().nativeGroup()) - return InliningStatus_NotInlined; - } - // Multiple arguments imply array initialization, not just construction. if (callInfo.argc() >= 2) { initLength = callInfo.argc(); @@ -542,16 +537,15 @@ IonBuilder::inlineArray(CallInfo& callInfo) MDefinition* array = current->peek(-1); if (callInfo.argc() >= 2) { - JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject); for (uint32_t i = 0; i < initLength; i++) { if (!alloc().ensureBallast()) return InliningStatus_Error; MDefinition* value = callInfo.getArg(i); - if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false)) return InliningStatus_Error; } - MInstruction* setLength = setInitializedLength(array, unboxedType, initLength); + MInstruction* setLength = setInitializedLength(array, initLength); if (!resumeAfter(setLength)) return InliningStatus_Error; } @@ -584,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)); @@ -620,7 +614,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) if (!thisTypes) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); @@ -632,17 +626,9 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - callInfo.setImplicitlyUsedUnchecked(); - if (clasp == &ArrayObject::class_) - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); + obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); TemporaryTypeSet* returnTypes = getInlineReturnTypeSet(); bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED); @@ -653,8 +639,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) if (barrier != BarrierKind::NoBarrier) returnType = MIRType::Value; - MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, - unboxedType, needsHoleCheck, maybeUndefined); + MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode, needsHoleCheck, maybeUndefined); current->add(ins); current->push(ins); ins->setResultType(returnType); @@ -761,7 +746,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) if (!thisTypes) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -782,13 +767,6 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - callInfo.setImplicitlyUsedUnchecked(); if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles || @@ -799,13 +777,12 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) value = valueDouble; } - if (unboxedType == JSVAL_TYPE_MAGIC) - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); + obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); if (NeedsPostBarrier(value)) current->add(MPostWriteBarrier::New(alloc(), obj, value)); - MArrayPush* ins = MArrayPush::New(alloc(), obj, value, unboxedType); + MArrayPush* ins = MArrayPush::New(alloc(), obj, value); current->add(ins); current->push(ins); @@ -846,7 +823,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + if (clasp != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) @@ -855,13 +832,6 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - } - // Watch out for indexed properties on the prototype. if (ArrayPrototypeHasIndexedProperty(this, script())) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); @@ -882,15 +852,8 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) if (!templateObj) return InliningStatus_NotInlined; - if (unboxedType == JSVAL_TYPE_MAGIC) { - if (!templateObj->is<ArrayObject>()) - return InliningStatus_NotInlined; - } else { - if (!templateObj->is<UnboxedArrayObject>()) - return InliningStatus_NotInlined; - if (templateObj->as<UnboxedArrayObject>().elementType() != unboxedType) - return InliningStatus_NotInlined; - } + if (!templateObj->is<ArrayObject>()) + return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); @@ -909,16 +872,12 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo) end = MArrayLength::New(alloc(), elements); current->add(end->toInstruction()); - } else { - end = MUnboxedArrayLength::New(alloc(), obj); - current->add(end->toInstruction()); } MArraySlice* ins = MArraySlice::New(alloc(), constraints(), obj, begin, end, templateObj, - templateObj->group()->initialHeap(constraints()), - unboxedType); + templateObj->group()->initialHeap(constraints())); current->add(ins); current->push(ins); @@ -1500,8 +1459,6 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) return InliningStatus_Inlined; } - JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject); - // Store all values, no need to initialize the length after each as // jsop_initelem_array is doing because we do not expect to bailout // because the memory is supposed to be allocated by now. @@ -1512,11 +1469,11 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo) MConstant* value = arrayValues[i]; current->add(value); - if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, /* addResumePoint = */ false)) return InliningStatus_Error; } - MInstruction* setLength = setInitializedLength(array, unboxedType, initLength); + MInstruction* setLength = setInitializedLength(array, initLength); if (!resumeAfter(setLength)) return InliningStatus_Error; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 1f33b2174..6aa46be4b 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5823,46 +5823,6 @@ jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, return clasp && clasp->isNative() && !IsTypedArrayClass(clasp); } -JSValueType -jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, - MDefinition* id) -{ - if (obj->mightBeType(MIRType::String)) - return JSVAL_TYPE_MAGIC; - - if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double) - return JSVAL_TYPE_MAGIC; - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) - return JSVAL_TYPE_MAGIC; - - JSValueType elementType = JSVAL_TYPE_MAGIC; - for (unsigned i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) - continue; - - if (key->unknownProperties() || !key->isGroup()) - return JSVAL_TYPE_MAGIC; - - if (key->clasp() != &UnboxedArrayObject::class_) - return JSVAL_TYPE_MAGIC; - - const UnboxedLayout &layout = key->group()->unboxedLayout(); - - if (layout.nativeGroup()) - return JSVAL_TYPE_MAGIC; - - if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC) - elementType = layout.elementType(); - else - return JSVAL_TYPE_MAGIC; - } - - return elementType; -} - bool jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, @@ -6022,11 +5982,6 @@ ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second) firstElements.maybeTypes()->equals(secondElements.maybeTypes()); } - if (first->clasp() == &UnboxedArrayObject::class_) { - return first->group()->unboxedLayout().elementType() == - second->group()->unboxedLayout().elementType(); - } - return false; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 3e0421789..f316827dc 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -375,8 +375,7 @@ class AliasSet { Element = 1 << 1, // A Value member of obj->elements or // a typed object. UnboxedElement = 1 << 2, // An unboxed scalar or reference member of - // a typed array, typed object, or unboxed - // object. + // typed object or unboxed object. DynamicSlot = 1 << 3, // A Value member of obj->slots. FixedSlot = 1 << 4, // A Value member of obj->fixedSlots(). DOMProperty = 1 << 5, // A DOM property @@ -433,9 +432,6 @@ class AliasSet { MOZ_ASSERT(flags && !(flags & Store_)); return AliasSet(flags | Store_); } - static uint32_t BoxedOrUnboxedElements(JSValueType type) { - return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement; - } }; typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector; @@ -8745,102 +8741,6 @@ class MSetInitializedLength ALLOW_CLONE(MSetInitializedLength) }; -// Load the length from an unboxed array. -class MUnboxedArrayLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MUnboxedArrayLength(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Int32); - setMovable(); - } - - public: - INSTRUCTION_HEADER(UnboxedArrayLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MUnboxedArrayLength) -}; - -// Load the initialized length from an unboxed array. -class MUnboxedArrayInitializedLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MUnboxedArrayInitializedLength(MDefinition* object) - : MUnaryInstruction(object) - { - setResultType(MIRType::Int32); - setMovable(); - } - - public: - INSTRUCTION_HEADER(UnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MUnboxedArrayInitializedLength) -}; - -// Increment the initialized length of an unboxed array object. -class MIncrementUnboxedArrayInitializedLength - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj) - : MUnaryInstruction(obj) - {} - - public: - INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object)) - - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength) -}; - -// Set the initialized length of an unboxed array object. -class MSetUnboxedArrayInitializedLength - : public MBinaryInstruction, - public SingleObjectPolicy::Data -{ - explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length) - : MBinaryInstruction(obj, length) - {} - - public: - INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object), (1, length)) - - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields); - } - - ALLOW_CLONE(MSetUnboxedArrayInitializedLength) -}; - // Load the array length from an elements header. class MArrayLength : public MUnaryInstruction, @@ -9341,16 +9241,12 @@ class MLoadElementHole : public MTernaryInstruction, public SingleObjectPolicy::Data { - // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements. - JSValueType unboxedType_; - bool needsNegativeIntCheck_; bool needsHoleCheck_; MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength, - JSValueType unboxedType, bool needsHoleCheck) + bool needsHoleCheck) : MTernaryInstruction(elements, index, initLength), - unboxedType_(unboxedType), needsNegativeIntCheck_(true), needsHoleCheck_(needsHoleCheck) { @@ -9372,9 +9268,6 @@ class MLoadElementHole TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, elements), (1, index), (2, initLength)) - JSValueType unboxedType() const { - return unboxedType_; - } bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } @@ -9385,8 +9278,6 @@ class MLoadElementHole if (!ins->isLoadElementHole()) return false; const MLoadElementHole* other = ins->toLoadElementHole(); - if (unboxedType() != other->unboxedType()) - return false; if (needsHoleCheck() != other->needsHoleCheck()) return false; if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) @@ -9394,7 +9285,7 @@ class MLoadElementHole return congruentIfOperandsEqual(other); } AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Load(AliasSet::Element); } void collectRangeInfoPreTrunc() override; @@ -9583,11 +9474,8 @@ class MStoreElementHole public MStoreElementCommon, public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data { - JSValueType unboxedType_; - MStoreElementHole(MDefinition* object, MDefinition* elements, - MDefinition* index, MDefinition* value, JSValueType unboxedType) - : unboxedType_(unboxedType) + MDefinition* index, MDefinition* value) { initOperand(0, object); initOperand(1, elements); @@ -9602,14 +9490,10 @@ class MStoreElementHole TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { // StoreElementHole can update the initialized length, the array length // or reallocate obj->elements. - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } ALLOW_CLONE(MStoreElementHole) @@ -9622,13 +9506,11 @@ class MFallibleStoreElement public MStoreElementCommon, public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data { - JSValueType unboxedType_; bool strict_; MFallibleStoreElement(MDefinition* object, MDefinition* elements, MDefinition* index, MDefinition* value, - JSValueType unboxedType, bool strict) - : unboxedType_(unboxedType) + bool strict) { initOperand(0, object); initOperand(1, elements); @@ -9644,12 +9526,8 @@ class MFallibleStoreElement TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } bool strict() const { return strict_; @@ -9754,13 +9632,12 @@ class MArrayPopShift private: Mode mode_; - JSValueType unboxedType_; bool needsHoleCheck_; bool maybeUndefined_; - MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType, + MArrayPopShift(MDefinition* object, Mode mode, bool needsHoleCheck, bool maybeUndefined) - : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType), + : MUnaryInstruction(object), mode_(mode), needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined) { } @@ -9778,12 +9655,8 @@ class MArrayPopShift bool mode() const { return mode_; } - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } ALLOW_CLONE(MArrayPopShift) @@ -9794,10 +9667,8 @@ class MArrayPush : public MBinaryInstruction, public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data { - JSValueType unboxedType_; - - MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType) - : MBinaryInstruction(object, value), unboxedType_(unboxedType) + MArrayPush(MDefinition* object, MDefinition* value) + : MBinaryInstruction(object, value) { setResultType(MIRType::Int32); } @@ -9807,12 +9678,8 @@ class MArrayPush TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, value)) - JSValueType unboxedType() const { - return unboxedType_; - } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | - AliasSet::BoxedOrUnboxedElements(unboxedType())); + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); } void computeRange(TempAllocator& alloc) override; @@ -9826,15 +9693,13 @@ class MArraySlice { CompilerObject templateObj_; gc::InitialHeap initialHeap_; - JSValueType unboxedType_; MArraySlice(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* begin, MDefinition* end, - JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType) + JSObject* templateObj, gc::InitialHeap initialHeap) : MTernaryInstruction(obj, begin, end), templateObj_(templateObj), - initialHeap_(initialHeap), - unboxedType_(unboxedType) + initialHeap_(initialHeap) { setResultType(MIRType::Object); } @@ -9852,10 +9717,6 @@ class MArraySlice return initialHeap_; } - JSValueType unboxedType() const { - return unboxedType_; - } - bool possiblyCalls() const override { return true; } @@ -12224,15 +12085,13 @@ class MInArray { bool needsHoleCheck_; bool needsNegativeIntCheck_; - JSValueType unboxedType_; MInArray(MDefinition* elements, MDefinition* index, MDefinition* initLength, MDefinition* object, - bool needsHoleCheck, JSValueType unboxedType) + bool needsHoleCheck) : MQuaternaryInstruction(elements, index, initLength, object), needsHoleCheck_(needsHoleCheck), - needsNegativeIntCheck_(true), - unboxedType_(unboxedType) + needsNegativeIntCheck_(true) { setResultType(MIRType::Boolean); setMovable(); @@ -12252,9 +12111,6 @@ class MInArray bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } - JSValueType unboxedType() const { - return unboxedType_; - } void collectRangeInfoPreTrunc() override; AliasSet getAliasSet() const override { return AliasSet::Load(AliasSet::Element); @@ -12267,8 +12123,6 @@ class MInArray return false; if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) return false; - if (unboxedType() != other->unboxedType()) - return false; return congruentIfOperandsEqual(other); } }; @@ -14169,8 +14023,6 @@ MDefinition::maybeConstantValue() bool ElementAccessIsDenseNative(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id); -JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, - MDefinition* id); bool ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, Scalar::Type* arrayType); diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index b80d1baf9..ab37604b4 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -198,10 +198,6 @@ namespace jit { _(SetTypedObjectOffset) \ _(InitializedLength) \ _(SetInitializedLength) \ - _(UnboxedArrayLength) \ - _(UnboxedArrayInitializedLength) \ - _(IncrementUnboxedArrayInitializedLength) \ - _(SetUnboxedArrayInitializedLength) \ _(Not) \ _(BoundsCheck) \ _(BoundsCheckLower) \ diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index f633b9b7b..e50f68722 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -705,31 +705,6 @@ template void MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type, const ConstantOrRegister& value, Label* failure); -void -MacroAssembler::checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index, - Register temp, Label* failure) -{ - Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()); - Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength()); - - Label capacityIsIndex, done; - load32(initLengthAddr, temp); - branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex); - branch32(Assembler::BelowOrEqual, lengthAddr, index, failure); - jump(&done); - bind(&capacityIsIndex); - - // Do a partial shift so that we can get an absolute offset from the base - // of CapacityArray to use. - JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4); - rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp); - and32(Imm32(~0x3), temp); - - addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp); - branch32(Assembler::BelowOrEqual, Address(temp, 0), index, failure); - bind(&done); -} - // Inlined version of gc::CheckAllocatorState that checks the bare essentials // and bails for anything that cannot be handled with our jit allocators. void @@ -1281,16 +1256,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj, storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando())); if (initContents) initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>()); - } else if (templateObj->is<UnboxedArrayObject>()) { - MOZ_ASSERT(templateObj->as<UnboxedArrayObject>().hasInlineElements()); - int elementsOffset = UnboxedArrayObject::offsetOfInlineElements(); - computeEffectiveAddress(Address(obj, elementsOffset), temp); - storePtr(temp, Address(obj, UnboxedArrayObject::offsetOfElements())); - store32(Imm32(templateObj->as<UnboxedArrayObject>().length()), - Address(obj, UnboxedArrayObject::offsetOfLength())); - uint32_t capacityIndex = templateObj->as<UnboxedArrayObject>().capacityIndex(); - store32(Imm32(capacityIndex << UnboxedArrayObject::CapacityShift), - Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength())); } else { MOZ_CRASH("Unknown object"); } diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index b6616321c..6ee989463 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1626,7 +1626,7 @@ class MacroAssembler : public MacroAssemblerSpecific void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest, unsigned numElems = 0); - // Load a property from an UnboxedPlainObject or UnboxedArrayObject. + // Load a property from an UnboxedPlainObject. template <typename T> void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output); @@ -1637,9 +1637,6 @@ class MacroAssembler : public MacroAssemblerSpecific void storeUnboxedProperty(T address, JSValueType type, const ConstantOrRegister& value, Label* failure); - void checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index, - Register temp, Label* failure); - Register extractString(const Address& address, Register scratch) { return extractObject(address, scratch); } diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 2065c0371..be9ceee2e 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -795,11 +795,6 @@ IsArrayEscaped(MInstruction* ins) return true; } - if (obj->is<UnboxedArrayObject>()) { - JitSpew(JitSpew_Escape, "Template object is an unboxed plain object."); - return true; - } - if (length >= 16) { JitSpew(JitSpew_Escape, "Array has too many elements"); return true; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 2475dfb22..313957462 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -286,11 +286,6 @@ ICStub::trace(JSTracer* trc) TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape"); break; } - case ICStub::GetElem_UnboxedArray: { - ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray(); - TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group"); - break; - } case ICStub::GetElem_TypedArray: { ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray(); TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape"); @@ -2250,7 +2245,6 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy) if (obj == holder) return false; if (!obj->is<UnboxedPlainObject>() && - !obj->is<UnboxedArrayObject>() && !obj->is<TypedObject>()) { return false; @@ -2582,9 +2576,6 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, } else if (curObj->is<UnboxedPlainObject>()) { if (curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, NameToId(name))) return false; - } else if (curObj->is<UnboxedArrayObject>()) { - if (name == cx->names().length) - return false; } else if (curObj->is<TypedObject>()) { if (curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(), NameToId(name))) return false; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 77b9e3647..0717bb86d 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -318,7 +318,7 @@ ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t delet bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { - MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()); + MOZ_ASSERT(obj->is<ArrayObject>()); AutoDetectInvalidation adi(cx, rval); @@ -341,8 +341,8 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) { *length = GetAnyBoxedOrUnboxedArrayLength(obj); DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, - ShouldUpdateTypes::DontUpdate); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) { (*length)++; return result == DenseElementResult::Success; @@ -362,7 +362,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) bool ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { - MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()); + MOZ_ASSERT(obj->is<ArrayObject>()); AutoDetectInvalidation adi(cx, rval); @@ -1151,8 +1151,8 @@ SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index, // no type changes are needed. DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, - ShouldUpdateTypes::DontUpdate); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f386d5256..35c7e7442 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5165,72 +5165,6 @@ class LSetInitializedLength : public LInstructionHelper<0, 2, 0> } }; -class LUnboxedArrayLength : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(UnboxedArrayLength) - - explicit LUnboxedArrayLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LUnboxedArrayInitializedLength : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(UnboxedArrayInitializedLength) - - explicit LUnboxedArrayInitializedLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1, 0> -{ - public: - LIR_HEADER(IncrementUnboxedArrayInitializedLength) - - explicit LIncrementUnboxedArrayInitializedLength(const LAllocation& object) { - setOperand(0, object); - } - - const LAllocation* object() { - return getOperand(0); - } -}; - -class LSetUnboxedArrayInitializedLength : public LInstructionHelper<0, 2, 1> -{ - public: - LIR_HEADER(SetUnboxedArrayInitializedLength) - - explicit LSetUnboxedArrayInitializedLength(const LAllocation& object, - const LAllocation& length, - const LDefinition& temp) { - setOperand(0, object); - setOperand(1, length); - setTemp(0, temp); - } - - const LAllocation* object() { - return getOperand(0); - } - const LAllocation* length() { - return getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } -}; - // Load the length from an elements header. class LArrayLength : public LInstructionHelper<1, 1, 0> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 6912e8904..deae92839 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -267,10 +267,6 @@ _(PostWriteElementBarrierV) \ _(InitializedLength) \ _(SetInitializedLength) \ - _(UnboxedArrayLength) \ - _(UnboxedArrayInitializedLength) \ - _(IncrementUnboxedArrayInitializedLength) \ - _(SetUnboxedArrayInitializedLength) \ _(BoundsCheck) \ _(BoundsCheckRange) \ _(BoundsCheckLower) \ diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 3b4c957dc..a8bd3f028 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -64,7 +64,7 @@ using JS::ToUint32; bool JS::IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer) { - if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) { + if (obj->is<ArrayObject>()) { *answer = IsArrayAnswer::Array; return true; } @@ -100,11 +100,6 @@ js::GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp) return true; } - if (obj->is<UnboxedArrayObject>()) { - *lengthp = obj->as<UnboxedArrayObject>().length(); - return true; - } - if (obj->is<ArgumentsObject>()) { ArgumentsObject& argsobj = obj->as<ArgumentsObject>(); if (!argsobj.hasOverriddenLength()) { @@ -284,7 +279,7 @@ ElementAdder::append(JSContext* cx, HandleValue v) MOZ_ASSERT(index_ < length_); if (resObj_) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); + SetOrExtendBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); if (result == DenseElementResult::Failure) return false; if (result == DenseElementResult::Incomplete) { @@ -342,11 +337,11 @@ GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp) { MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj)); - if (length > GetBoxedOrUnboxedInitializedLength<Type>(aobj)) + if (length > GetBoxedOrUnboxedInitializedLength(aobj)) return DenseElementResult::Incomplete; for (size_t i = 0; i < length; i++) { - vp[i] = GetBoxedOrUnboxedDenseElement<Type>(aobj, i); + vp[i] = GetBoxedOrUnboxedDenseElement(aobj, i); // No other indexed properties so hole => undefined. if (vp[i].isMagic(JS_ELEMENTS_HOLE)) @@ -398,9 +393,9 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) { MOZ_ASSERT(index >= 0); - if ((obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) && !obj->isIndexed() && index <= UINT32_MAX) { + 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; } @@ -823,7 +818,7 @@ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) static inline bool ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj) { - return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) || + return !obj->isNative() || obj->isIndexed() || obj->is<TypedArrayObject>() || ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames, @@ -1073,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())) @@ -1288,10 +1283,6 @@ array_toLocaleString(JSContext* cx, unsigned argc, Value* vp) args.rval().setString(cx->names().empty); return true; } - if (obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().length() == 0) { - args.rval().setString(cx->names().empty); - return true; - } AutoCycleDetector detector(cx, obj); if (!detector.init()) @@ -1329,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; } @@ -1368,49 +1359,41 @@ 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 (Type == JSVAL_TYPE_MAGIC) { - if (obj->as<NativeObject>().denseElementsAreFrozen()) - return DenseElementResult::Incomplete; + if (obj->as<NativeObject>().denseElementsAreFrozen()) + return DenseElementResult::Incomplete; - /* - * It's actually surprisingly complicated to reverse an array due to the - * orthogonality of array length and array capacity while handling - * leading and trailing holes correctly. Reversing seems less likely to - * be a common operation than other array mass-mutation methods, so for - * now just take a probably-small memory hit (in the absence of too many - * holes in the array at its start) and ensure that the capacity is - * sufficient to hold all the elements in the array if it were full. - */ - DenseElementResult result = obj->as<NativeObject>().ensureDenseElements(cx, length, 0); - if (result != DenseElementResult::Success) - return result; + /* + * It's actually surprisingly complicated to reverse an array due to the + * orthogonality of array length and array capacity while handling + * leading and trailing holes correctly. Reversing seems less likely to + * be a common operation than other array mass-mutation methods, so for + * now just take a probably-small memory hit (in the absence of too many + * holes in the array at its start) and ensure that the capacity is + * sufficient to hold all the elements in the array if it were full. + */ + DenseElementResult result = obj->as<NativeObject>().ensureDenseElements(cx, length, 0); + if (result != DenseElementResult::Success) + return result; - /* Fill out the array's initialized length to its proper length. */ - obj->as<NativeObject>().ensureDenseInitializedLength(cx, length, 0); - } else { - // Unboxed arrays can only be reversed here if their initialized length - // matches their actual length. Otherwise the reversal will place holes - // at the beginning of the array, which we don't support. - if (length != obj->as<UnboxedArrayObject>().initializedLength()) - return DenseElementResult::Incomplete; - } + /* Fill out the array's initialized length to its proper length. */ + obj->as<NativeObject>().ensureDenseInitializedLength(cx, length, 0); RootedValue origlo(cx), orighi(cx); uint32_t lo = 0, hi = length - 1; for (; lo < hi; lo++, hi--) { - origlo = GetBoxedOrUnboxedDenseElement<Type>(obj, lo); - orighi = GetBoxedOrUnboxedDenseElement<Type>(obj, hi); - SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, lo, orighi); + origlo = GetBoxedOrUnboxedDenseElement(obj, lo); + orighi = GetBoxedOrUnboxedDenseElement(obj, hi); + SetBoxedOrUnboxedDenseElementNoTypeChange(obj, lo, orighi); if (orighi.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) { return DenseElementResult::Failure; } - SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, hi, origlo); + SetBoxedOrUnboxedDenseElementNoTypeChange(obj, hi, origlo); if (origlo.isMagic(JS_ELEMENTS_HOLE) && !SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) { @@ -2082,8 +2065,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, length, - args.array(), args.length()); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, length, + args.array(), args.length()); if (result != DenseElementResult::Incomplete) { if (result == DenseElementResult::Failure) return false; @@ -2091,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; @@ -2158,21 +2141,15 @@ template <JSValueType Type> static inline DenseElementResult ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj)); /* * At this point the length and initialized length have already been * decremented and the result fetched, so just shift the array elements * themselves. */ - size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); - if (Type == JSVAL_TYPE_MAGIC) { - obj->as<NativeObject>().moveDenseElementsNoPreBarrier(0, 1, initlen); - } else { - uint8_t* data = obj->as<UnboxedArrayObject>().elements(); - size_t elementSize = UnboxedTypeSize(Type); - memmove(data, data + elementSize, initlen * elementSize); - } + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); + obj->as<NativeObject>().moveDenseElementsNoPreBarrier(0, 1, initlen); return DenseElementResult::Success; } @@ -2202,19 +2179,19 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED))) return DenseElementResult::Incomplete; - size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); if (initlen == 0) return DenseElementResult::Incomplete; - rval.set(GetBoxedOrUnboxedDenseElement<Type>(obj, 0)); + rval.set(GetBoxedOrUnboxedDenseElement(obj, 0)); if (rval.isMagic(JS_ELEMENTS_HOLE)) rval.setUndefined(); - DenseElementResult result = MoveBoxedOrUnboxedDenseElements<Type>(cx, obj, 0, 1, initlen - 1); + DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1); if (result != DenseElementResult::Success) return result; - SetBoxedOrUnboxedInitializedLength<Type>(cx, obj, initlen - 1); + SetBoxedOrUnboxedInitializedLength(cx, obj, initlen - 1); return DenseElementResult::Success; } @@ -2383,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 */ @@ -2520,7 +2497,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI /* Steps 10-11. */ DebugOnly<DenseElementResult> result = - CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); + CopyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); MOZ_ASSERT(result.value == DenseElementResult::Success); /* Step 12 (implicit). */ @@ -2557,14 +2534,14 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, 0, len, cx)) { /* Steps 15.a-b. */ DenseElementResult result = - MoveAnyBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex, - len - sourceIndex); + MoveBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex, + len - sourceIndex); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; /* Steps 15.c-d. */ - SetAnyBoxedOrUnboxedInitializedLength(cx, obj, finalLength); + SetBoxedOrUnboxedInitializedLength(cx, obj, finalLength); } else { /* * This is all very slow if the length is very large. We don't yet @@ -2644,15 +2621,15 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) { DenseElementResult result = - MoveAnyBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount, - actualStart + actualDeleteCount, - len - (actualStart + actualDeleteCount)); + MoveBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount, + actualStart + actualDeleteCount, + len - (actualStart + actualDeleteCount)); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return false; /* Steps 16.a-b. */ - SetAnyBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount); + SetBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount); } else { RootedValue fromValue(cx); for (double k = len - actualDeleteCount; k > actualStart; k--) { @@ -2886,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); @@ -3022,14 +2999,14 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en if (begin > end) begin = end; - size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); + size_t initlen = GetBoxedOrUnboxedInitializedLength(obj); if (initlen > begin) { size_t count = Min<size_t>(initlen - begin, end - begin); if (count) { - DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count); + DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count); if (rv != DenseElementResult::Success) return rv; - CopyBoxedOrUnboxedDenseElements<Type, Type>(cx, result, obj, 0, begin, count); + CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); } } @@ -3596,12 +3573,6 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length newKind = TenuredObject; RootedObject proto(cx, group->proto().toObject()); - if (group->maybeUnboxedLayout()) { - if (length > UnboxedArrayObject::MaximumCapacity) - return NewArray<maxLength>(cx, length, proto, newKind); - return UnboxedArrayObject::create(cx, group, length, newKind, maxLength); - } - ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind); if (!res) return nullptr; @@ -3644,7 +3615,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()) @@ -3708,8 +3679,8 @@ js::MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup if (!obj) return false; DebugOnly<DenseElementResult> result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, - ShouldUpdateTypes::Update); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, + ShouldUpdateTypes::Update); MOZ_ASSERT(result.value == DenseElementResult::Success); } objects->maybeAnalyze(cx, group, /* forceAnalyze = */ true); @@ -3731,22 +3702,10 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, return nullptr; DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); + SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; - if (result == DenseElementResult::Success) - return obj; - - MOZ_ASSERT(obj->is<UnboxedArrayObject>()); - if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj)) - return nullptr; - - result = SetOrExtendBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(cx, obj, 0, vp, length, - updateTypes); - MOZ_ASSERT(result != DenseElementResult::Incomplete); - if (result == DenseElementResult::Failure) - return nullptr; - + MOZ_ASSERT(result == DenseElementResult::Success); return obj; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index f5cd56a9b..1fd9d1d28 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -271,7 +271,7 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls) if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>()) *cls = ESClass::Object; - else if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) + else if (obj->is<ArrayObject>()) *cls = ESClass::Array; else if (obj->is<NumberObject>()) *cls = ESClass::Number; 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 { |