author | Wes Kocher <wkocher@mozilla.com> |
Thu, 06 Aug 2015 18:42:15 -0700 | |
changeset 256741 | ca5ebc4c7af9d67938e94ba4c97614635c95ece4 |
parent 256740 | bd9983f167c2658d1a9f5863fc43f2c0860f0e45 (current diff) |
parent 256645 | d6ea652c579992daa9041cc9718bb7c6abefbc91 (diff) |
child 256742 | 4367154a39b1afb2a0e9f573b26ee49cb5cad138 |
push id | 29187 |
push user | cbook@mozilla.com |
push date | Fri, 07 Aug 2015 11:13:32 +0000 |
treeherder | mozilla-central@3e51753a099f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -9536,74 +9536,54 @@ TryAttachFunCallStub(JSContext* cx, ICCa return true; } return true; } static bool GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, - MutableHandleObject res, bool* skipAttach) + MutableHandleObject res) { // Check for natives to which template objects can be attached. This is // done to provide templates to Ion for inlining these natives later on. if (native == ArrayConstructor) { // Note: the template array won't be used if its length is inaccurately // computed here. (We allocate here because compilation may occur on a // separate thread where allocation is impossible.) size_t count = 0; if (args.length() != 1) count = args.length(); else if (args.length() == 1 && args[0].isInt32() && args[0].toInt32() >= 0) count = args[0].toInt32(); if (count <= ArrayObject::EagerAllocationMaxLength) { - ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); - if (!group) - return false; - if (group->maybePreliminaryObjects()) { - *skipAttach = true; - return true; - } - // With this and other array templates, set forceAnalyze so that we // don't end up with a template whose structure might change later. - res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject)); + res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject, + /* forceAnalyze = */ true)); if (!res) return false; return true; } } if (native == js::array_concat || native == js::array_slice) { - if (args.thisv().isObject()) { - JSObject* obj = &args.thisv().toObject(); - if (!obj->isSingleton()) { - if (obj->group()->maybePreliminaryObjects()) { - *skipAttach = true; - return true; - } - res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, - TenuredObject)); - return !!res; - } + if (args.thisv().isObject() && !args.thisv().toObject().isSingleton()) { + res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, + TenuredObject, /* forceAnalyze = */ true)); + if (!res) + return false; } } if (native == js::str_split && args.length() == 1 && args[0].isString()) { - ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); - if (!group) - return false; - if (group->maybePreliminaryObjects()) { - *skipAttach = true; - return true; - } - - res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject)); + res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject, + /* forceAnalyze = */ true)); if (!res) return false; return true; } if (native == StringConstructor) { RootedString emptyString(cx, cx->runtime()->emptyString); res.set(StringObject::create(cx, emptyString, TenuredObject)); @@ -9892,25 +9872,19 @@ TryAttachCallStub(JSContext* cx, ICCall_ stub->addNewStub(newStub); *handled = true; return true; } RootedObject templateObject(cx); if (MOZ_LIKELY(!isSpread)) { - bool skipAttach = false; CallArgs args = CallArgsFromVp(argc, vp); - if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach)) + if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject)) return false; - if (skipAttach) { - *handled = true; - return true; - } - MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects()); } JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)", fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no"); ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), fun, templateObject, constructing, isSpread, script->pcToOffset(pc)); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7217,33 +7217,32 @@ CodeGenerator::visitArrayConcat(LArrayCo Register rhs = ToRegister(lir->rhs()); Register temp1 = ToRegister(lir->temp1()); Register temp2 = ToRegister(lir->temp2()); // If 'length == initializedLength' for both arrays we try to allocate an object // inline and pass it to the stub. Else, we just pass nullptr and the stub falls // back to a slow path. Label fail, call; - if (lir->mir()->unboxedThis()) { - masm.load32(Address(lhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1); - masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1); - masm.branch32(Assembler::NotEqual, Address(lhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail); - } else { + if (lir->mir()->unboxedType() == JSVAL_TYPE_MAGIC) { masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1); masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); - } - if (lir->mir()->unboxedArg()) { + + masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1); + masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); + masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); + } else { + masm.load32(Address(lhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1); + masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1); + masm.branch32(Assembler::NotEqual, Address(lhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail); + masm.load32(Address(rhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1); masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1); masm.branch32(Assembler::NotEqual, Address(rhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail); - } else { - masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1); - masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); - masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); } // Try to allocate an object. masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail); masm.jump(&call); { masm.bind(&fail); masm.movePtr(ImmPtr(nullptr), temp1);
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -859,38 +859,44 @@ IonBuilder::inlineArrayConcat(CallInfo& return InliningStatus_NotInlined; // |this| and the argument must be dense arrays. TemporaryTypeSet* thisTypes = thisArg->resultTypeSet(); TemporaryTypeSet* argTypes = objArg->resultTypeSet(); if (!thisTypes || !argTypes) return InliningStatus_NotInlined; - const Class* thisClasp = thisTypes->getKnownClass(constraints()); - if (thisClasp != &ArrayObject::class_ && thisClasp != &UnboxedArrayObject::class_) + const Class* clasp = thisTypes->getKnownClass(constraints()); + if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) return InliningStatus_NotInlined; - bool unboxedThis = (thisClasp == &UnboxedArrayObject::class_); if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; } - const Class* argClasp = argTypes->getKnownClass(constraints()); - if (argClasp != &ArrayObject::class_ && argClasp != &UnboxedArrayObject::class_) + if (argTypes->getKnownClass(constraints()) != clasp) return InliningStatus_NotInlined; - bool unboxedArg = (argClasp == &UnboxedArrayObject::class_); if (argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; } + JSValueType unboxedType = JSVAL_TYPE_MAGIC; + if (clasp == &UnboxedArrayObject::class_) { + unboxedType = UnboxedArrayElementType(constraints(), thisArg, nullptr); + if (unboxedType == JSVAL_TYPE_MAGIC) + return InliningStatus_NotInlined; + if (unboxedType != UnboxedArrayElementType(constraints(), objArg, nullptr)) + return InliningStatus_NotInlined; + } + // Watch out for indexed properties on the prototype. if (ArrayPrototypeHasIndexedProperty(this, script())) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); return InliningStatus_NotInlined; } // Require the 'this' types to have a specific type matching the current // global, so we can create the result object inline. @@ -940,17 +946,17 @@ IonBuilder::inlineArrayConcat(CallInfo& if (!templateObj || templateObj->group() != thisGroup) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked(); MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(), thisArg, objArg, templateObj, templateObj->group()->initialHeap(constraints()), - unboxedThis, unboxedArg); + unboxedType); current->add(ins); current->push(ins); if (!resumeAfter(ins)) return InliningStatus_Error; return InliningStatus_Inlined; }
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9181,62 +9181,55 @@ class MArrayPush // Array.prototype.concat on two dense arrays. class MArrayConcat : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data { CompilerObject templateObj_; gc::InitialHeap initialHeap_; - bool unboxedThis_, unboxedArg_; + JSValueType unboxedType_; MArrayConcat(CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs, - JSObject* templateObj, gc::InitialHeap initialHeap, - bool unboxedThis, bool unboxedArg) + JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType) : MBinaryInstruction(lhs, rhs), templateObj_(templateObj), initialHeap_(initialHeap), - unboxedThis_(unboxedThis), - unboxedArg_(unboxedArg) + unboxedType_(unboxedType) { setResultType(MIRType_Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj)); } public: INSTRUCTION_HEADER(ArrayConcat) static MArrayConcat* New(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs, JSObject* templateObj, gc::InitialHeap initialHeap, - bool unboxedThis, bool unboxedArg) + JSValueType unboxedType) { return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj, - initialHeap, unboxedThis, unboxedArg); + initialHeap, unboxedType); } JSObject* templateObj() const { return templateObj_; } gc::InitialHeap initialHeap() const { return initialHeap_; } - bool unboxedThis() const { - return unboxedThis_; - } - - bool unboxedArg() const { - return unboxedArg_; - } - - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedThis() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) | - AliasSet::BoxedOrUnboxedElements(unboxedArg() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) | + JSValueType unboxedType() const { + return unboxedType_; + } + + AliasSet getAliasSet() const override { + return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) | AliasSet::ObjectFields); } bool possiblyCalls() const override { return true; } }; // Array.prototype.slice on a dense array.
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2558,51 +2558,50 @@ js::array_splice_impl(JSContext* cx, uns /* Step 17. */ if (returnValueIsUsed) args.rval().setObject(*arr); return true; } -template <JSValueType TypeOne, JSValueType TypeTwo> +template <JSValueType Type> DenseElementResult ArrayConcatDenseKernel(JSContext* cx, JSObject* obj1, JSObject* obj2, JSObject* result) { - uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength<TypeOne>(obj1); + uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength<Type>(obj1); MOZ_ASSERT(initlen1 == GetAnyBoxedOrUnboxedArrayLength(obj1)); - uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength<TypeTwo>(obj2); + uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength<Type>(obj2); MOZ_ASSERT(initlen2 == GetAnyBoxedOrUnboxedArrayLength(obj2)); /* No overflow here due to nelements limit. */ uint32_t len = initlen1 + initlen2; - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<TypeOne>(result) == 0); - - DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<TypeOne>(cx, result, len); - if (rv != DenseElementResult::Success) - return rv; - - CopyBoxedOrUnboxedDenseElements<TypeOne, TypeOne>(cx, result, obj1, 0, 0, initlen1); - CopyBoxedOrUnboxedDenseElements<TypeOne, TypeTwo>(cx, result, obj2, initlen1, 0, initlen2); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<Type>(result) == 0); + + if (!EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, len)) + return DenseElementResult::Failure; + + CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj1, 0, 0, initlen1); + CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj2, initlen1, 0, initlen2); SetAnyBoxedOrUnboxedArrayLength(cx, result, len); return DenseElementResult::Success; } -DefineBoxedOrUnboxedFunctorPair4(ArrayConcatDenseKernel, - JSContext*, JSObject*, JSObject*, JSObject*); +DefineBoxedOrUnboxedFunctor4(ArrayConcatDenseKernel, + JSContext*, JSObject*, JSObject*, JSObject*); bool js::array_concat_dense(JSContext* cx, HandleObject obj1, HandleObject obj2, HandleObject result) { ArrayConcatDenseKernelFunctor functor(cx, obj1, obj2, result); - DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, obj1, obj2); + DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result); MOZ_ASSERT(rv != DenseElementResult::Incomplete); return rv == DenseElementResult::Success; } /* * Python-esque sequence operations. */ bool @@ -2623,73 +2622,27 @@ js::array_concat(JSContext* cx, unsigned if (IsArray(aobj, cx) && !ObjectMayHaveExtraIndexedProperties(aobj)) { if (!GetLengthProperty(cx, aobj, &length)) return false; size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(aobj); narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, initlen); if (!narr) return false; - CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen); SetAnyBoxedOrUnboxedArrayLength(cx, narr, length); + DebugOnly<DenseElementResult> result = + CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen); + MOZ_ASSERT(result.value == DenseElementResult::Success); + args.rval().setObject(*narr); if (argc == 0) return true; argc--; p++; - - if (length == initlen) { - while (argc) { - HandleValue v = HandleValue::fromMarkedLocation(p); - if (!v.isObject()) - break; - RootedObject obj(cx, &v.toObject()); - - // This should be IsConcatSpreadable - if (!IsArray(obj, cx) || ObjectMayHaveExtraIndexedProperties(obj)) - break; - - uint32_t argLength; - if (!GetLengthProperty(cx, obj, &argLength)) - return false; - - initlen = GetAnyBoxedOrUnboxedInitializedLength(obj); - if (argLength != initlen) - break; - - DenseElementResult result = - EnsureAnyBoxedOrUnboxedDenseElements(cx, narr, length + argLength); - if (result == DenseElementResult::Failure) - return false; - if (result == DenseElementResult::Incomplete) - break; - - SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length + argLength); - - bool success = true; - for (size_t i = 0; i < initlen; i++) { - Value v = GetAnyBoxedOrUnboxedDenseElement(obj, i); - if (!InitAnyBoxedOrUnboxedDenseElement(cx, narr, length + i, v)) { - success = false; - break; - } - } - if (!success) { - SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length); - break; - } - - length += argLength; - SetAnyBoxedOrUnboxedArrayLength(cx, narr, length); - - argc--; - p++; - } - } } else { narr = NewDenseEmptyArray(cx); if (!narr) return false; args.rval().setObject(*narr); length = 0; } @@ -2976,20 +2929,19 @@ ArraySliceDenseKernel(JSContext* cx, JSO if (begin > end) begin = end; size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); if (initlen > begin) { size_t count = Min<size_t>(initlen - begin, end - begin); if (count) { - DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count); - if (rv != DenseElementResult::Success) - return rv; - CopyBoxedOrUnboxedDenseElements<Type, Type>(cx, result, obj, 0, begin, count); + if (!EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count)) + return DenseElementResult::Failure; + CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj, 0, begin, count); } } SetAnyBoxedOrUnboxedArrayLength(cx, result, end - begin); return DenseElementResult::Success; } DefineBoxedOrUnboxedFunctor5(ArraySliceDenseKernel,
--- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -267,22 +267,16 @@ UnboxedArrayObject::triggerPreBarrier(si MOZ_CRASH("Bad type"); } } ///////////////////////////////////////////////////////////////////// // Combined methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// -static inline bool -HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) -{ - return obj->isNative() || obj->is<UnboxedArrayObject>(); -} - static inline size_t GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) { if (obj->isNative()) return obj->as<NativeObject>().getDenseInitializedLength(); if (obj->is<UnboxedArrayObject>()) return obj->as<UnboxedArrayObject>().initializedLength(); return 0; @@ -331,26 +325,16 @@ SetAnyBoxedOrUnboxedDenseElement(JSConte { if (obj->isNative()) { obj->as<NativeObject>().setDenseElementWithType(cx, index, value); return true; } return obj->as<UnboxedArrayObject>().setElement(cx, index, value); } -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); -} - ///////////////////////////////////////////////////////////////////// // Template methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// static inline JSValueType GetBoxedOrUnboxedType(JSObject* obj) { if (obj->isNative()) @@ -428,29 +412,29 @@ SetBoxedOrUnboxedDenseElement(JSContext* if (Type == JSVAL_TYPE_MAGIC) { obj->as<NativeObject>().setDenseElementWithType(cx, index, value); return true; } return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value); } template <JSValueType Type> -static inline DenseElementResult +static inline bool EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) { if (Type == JSVAL_TYPE_MAGIC) { if (!obj->as<ArrayObject>().ensureElements(cx, count)) - return DenseElementResult::Failure; + return false; } else { if (obj->as<UnboxedArrayObject>().capacity() < count) { if (!obj->as<UnboxedArrayObject>().growElements(cx, count)) - return DenseElementResult::Failure; + return false; } } - return DenseElementResult::Success; + return true; } template <JSValueType Type> static inline DenseElementResult SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) { @@ -558,64 +542,43 @@ MoveBoxedOrUnboxedDenseElements(JSContex memmove(data + dstStart * elementSize, data + srcStart * elementSize, length * elementSize); } return DenseElementResult::Success; } -template <JSValueType DstType, JSValueType SrcType> +template <JSValueType Type> 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<DstType>(src) >= srcStart + length); - MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length); - - SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(src)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(dst)); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<Type>(dst) == dstStart); + MOZ_ASSERT(GetBoxedOrUnboxedCapacity<Type>(dst) >= 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) { + SetBoxedOrUnboxedInitializedLength<Type>(cx, dst, dstStart + length); + + if (Type == JSVAL_TYPE_MAGIC) { + const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart; + dst->as<NativeObject>().initDenseElements(dstStart, vp, length); + } else { uint8_t* dstData = dst->as<UnboxedArrayObject>().elements(); uint8_t* srcData = src->as<UnboxedArrayObject>().elements(); - size_t elementSize = UnboxedTypeSize(DstType); + size_t elementSize = UnboxedTypeSize(Type); 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)) + if (UnboxedTypeNeedsPostBarrier(Type) && !IsInsideNursery(dst)) dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(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); - } } return DenseElementResult::Success; } ///////////////////////////////////////////////////////////////////// // Dispatch to specialized methods based on the type of an object. ///////////////////////////////////////////////////////////////////// @@ -628,80 +591,29 @@ CopyBoxedOrUnboxedDenseElements(JSContex #endif // Function to dispatch a method specialized to whatever boxed or unboxed dense // elements which an input object has. template <typename F> DenseElementResult CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) { - if (!HasAnyBoxedOrUnboxedDenseElements(obj)) - return DenseElementResult::Incomplete; - switch (GetBoxedOrUnboxedType(obj)) { - case JSVAL_TYPE_MAGIC: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>(); - case JSVAL_TYPE_BOOLEAN: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_BOOLEAN>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>(); - case JSVAL_TYPE_INT32: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_INT32>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>(); - case JSVAL_TYPE_DOUBLE: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_DOUBLE>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>(); - case JSVAL_TYPE_STRING: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_STRING>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>(); - case JSVAL_TYPE_OBJECT: + if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_OBJECT>(obj)) return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>(); - default: - MOZ_CRASH(); - } -} - -// As above, except the specialization can reflect the unboxed type of two objects. -template <typename F> -DenseElementResult -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 DenseElementResult::Incomplete; } #undef DEPENDENT_TEMPLATE_HINT #define DefineBoxedOrUnboxedFunctor1(Signature, A) \ struct Signature ## Functor { \ A a; \ explicit Signature ## Functor(A a) \ @@ -732,28 +644,16 @@ struct Signature ## Functor { : a(a), b(b), c(c), d(d) \ {} \ template <JSValueType Type> \ DenseElementResult operator()() { \ return Signature<Type>(a, b, c, d); \ } \ } -#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; \ - Signature ## Functor(A a, B b, C c, D d) \ - : a(a), b(b), c(c), d(d) \ - {} \ - template <JSValueType TypeOne, JSValueType TypeTwo> \ - DenseElementResult operator()() { \ - return Signature<TypeOne, TypeTwo>(a, b, c, d); \ - } \ -} - #define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \ struct Signature ## Functor { \ A a; B b; C c; D d; E e; \ Signature ## Functor(A a, B b, C c, D d, E e) \ : a(a), b(b), c(c), d(d), e(e) \ {} \ template <JSValueType Type> \ DenseElementResult operator()() { \ @@ -768,42 +668,30 @@ struct Signature ## Functor { : a(a), b(b), c(c), d(d), e(e), f(f) \ {} \ template <JSValueType Type> \ DenseElementResult operator()() { \ return Signature<Type>(a, b, c, d, e, f); \ } \ } -#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \ -struct Signature ## Functor { \ - A a; B b; C c; D d; E e; F f; \ - Signature ## Functor(A a, B b, C c, D d, E e, F f) \ - : a(a), b(b), c(c), d(d), e(e), f(f) \ - {} \ - template <JSValueType TypeOne, JSValueType TypeTwo> \ - DenseElementResult operator()() { \ - return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f); \ - } \ -} - 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 +bool EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count); } // namespace js #endif // vm_UnboxedObject_inl_h
--- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -1666,19 +1666,21 @@ CombinePlainObjectProperties(PlainObject return true; } static bool CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType) { if (obj->inDictionaryMode() || obj->lastProperty()->propid() != AtomToId(cx->names().length) || - !obj->lastProperty()->previous()->isEmptyShape()) + !obj->lastProperty()->previous()->isEmptyShape() || + !obj->getDenseInitializedLength()) { - // Only use an unboxed representation if the object has no properties. + // Only use an unboxed representation if the object has at + // least one element, and no properties. return false; } for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { Value val = obj->getDenseElement(i); // For now, unboxed arrays cannot have holes. if (val.isMagic(JS_ELEMENTS_HOLE)) @@ -1823,18 +1825,16 @@ UnboxedArrayObject::fillAfterConvert(Exc MOZ_ASSERT(CapacityArray[1] == 0); setCapacityIndex(1); setInitializedLength(0); setInlineElements(); setLength(cx, NextValue(values, valueCursor).toInt32()); int32_t initlen = NextValue(values, valueCursor).toInt32(); - if (!initlen) - return; if (!growElements(cx, initlen)) CrashAtUnhandlableOOM("UnboxedArrayObject::fillAfterConvert"); setInitializedLength(initlen); for (size_t i = 0; i < size_t(initlen); i++) JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); } @@ -2050,38 +2050,28 @@ DefineBoxedOrUnboxedFunctor5(MoveBoxedOr 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); +DefineBoxedOrUnboxedFunctor6(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); + return CallBoxedOrUnboxedSpecialization(functor, dst); } 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); -}