diff options
Diffstat (limited to 'js/src/jit/BaselineIC.cpp')
-rw-r--r-- | js/src/jit/BaselineIC.cpp | 482 |
1 files changed, 435 insertions, 47 deletions
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index e65f10aac..9c8cd9835 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -44,8 +44,8 @@ #include "jit/shared/Lowering-shared-inl.h" #include "vm/EnvironmentObject-inl.h" #include "vm/Interpreter-inl.h" -#include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" +#include "vm/UnboxedObject-inl.h" using mozilla::DebugOnly; @@ -741,6 +741,11 @@ LastPropertyForSetProp(JSObject* obj) if (obj->isNative()) return obj->as<NativeObject>().lastProperty(); + if (obj->is<UnboxedPlainObject>()) { + UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando(); + return expando ? expando->lastProperty() : nullptr; + } + return nullptr; } @@ -1157,6 +1162,56 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); + if (obj->is<UnboxedPlainObject>() && holder == obj) { + const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id); + + // Once unboxed objects support symbol-keys, we need to change the following accordingly + MOZ_ASSERT_IF(!keyVal.isString(), !property); + + if (property) { + if (!cx->runtime()->jitSupportsFloatingPoint) + return true; + + RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName()); + ICGetElemNativeCompiler<PropertyName*> compiler(cx, ICStub::GetElem_UnboxedPropertyName, + monitorStub, obj, holder, + name, + ICGetElemNativeStub::UnboxedProperty, + needsAtomize, property->offset + + UnboxedPlainObject::offsetOfData(), + property->type); + ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); + if (!newStub) + return false; + + stub->addNewStub(newStub); + *attached = true; + return true; + } + + Shape* shape = obj->as<UnboxedPlainObject>().maybeExpando()->lookup(cx, id); + if (!shape->hasDefaultGetter() || !shape->hasSlot()) + return true; + + bool isFixedSlot; + uint32_t offset; + GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset); + + ICGetElemNativeStub::AccessType acctype = + isFixedSlot ? ICGetElemNativeStub::FixedSlot + : ICGetElemNativeStub::DynamicSlot; + ICGetElemNativeCompiler<T> compiler(cx, getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName), + monitorStub, obj, holder, key, + acctype, needsAtomize, offset); + ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); + if (!newStub) + return false; + + stub->addNewStub(newStub); + *attached = true; + return true; + } + if (!holder->isNative()) return true; @@ -1320,7 +1375,7 @@ IsNativeDenseElementAccess(HandleObject obj, HandleValue key) static bool IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key) { - if (!obj->isNative()) + if (!obj->isNative() && !obj->is<UnboxedArrayObject>()) return false; if (key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>()) return true; @@ -1404,7 +1459,7 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ } // Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses. - if (obj->isNative()) { + if (obj->isNative() || obj->is<UnboxedPlainObject>()) { RootedScript rootedScript(cx, script); if (rhs.isString()) { if (!TryAttachNativeOrUnboxedGetValueElemStub<PropertyName*>(cx, rootedScript, pc, stub, @@ -1424,6 +1479,20 @@ 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() && @@ -1816,6 +1885,14 @@ ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm) Register holderReg; if (obj_ == holder_) { holderReg = objReg; + + if (obj_->is<UnboxedPlainObject>() && acctype_ != ICGetElemNativeStub::UnboxedProperty) { + // The property will be loaded off the unboxed expando. + masm.push(R1.scratchReg()); + popR1 = true; + holderReg = R1.scratchReg(); + masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); + } } else { // Shape guard holder. if (regs.empty()) { @@ -1866,6 +1943,13 @@ ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm) if (popR1) masm.addToStackPtr(ImmWord(sizeof(size_t))); + } else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) { + masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()), + scratchReg); + masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_, + TypedOrValueRegister(R0)); + if (popR1) + masm.addToStackPtr(ImmWord(sizeof(size_t))); } else { MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter || acctype_ == ICGetElemNativeStub::ScriptedGetter); @@ -2015,6 +2099,56 @@ 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 // @@ -2318,8 +2452,8 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index, Shape* oldShape, uint32_t oldCapacity, uint32_t oldInitLength, bool* isAddingCaseOut, size_t* protoDepthOut) { - uint32_t initLength = obj->as<NativeObject>().getDenseInitializedLength(); - uint32_t capacity = obj->as<NativeObject>().getDenseCapacity(); + uint32_t initLength = GetAnyBoxedOrUnboxedInitializedLength(obj); + uint32_t capacity = GetAnyBoxedOrUnboxedCapacity(obj); *isAddingCaseOut = false; *protoDepthOut = 0; @@ -2328,6 +2462,10 @@ 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. @@ -2409,8 +2547,8 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ uint32_t oldCapacity = 0; uint32_t oldInitLength = 0; if (index.isInt32() && index.toInt32() >= 0) { - oldCapacity = obj->as<NativeObject>().getDenseCapacity(); - oldInitLength = obj->as<NativeObject>().getDenseInitializedLength(); + oldCapacity = GetAnyBoxedOrUnboxedCapacity(obj); + oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj); } if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) { @@ -2618,6 +2756,18 @@ BaselineScript::noteArrayWriteHole(uint32_t pcOffset) // SetElem_DenseOrUnboxedArray // +template <typename T> +void +EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, T address, JSValueType type) +{ + if (type == JSVAL_TYPE_OBJECT) + EmitPreBarrier(masm, address, MIRType::Object); + else if (type == JSVAL_TYPE_STRING) + EmitPreBarrier(masm, address, MIRType::String); + else + MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type)); +} + bool ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) { @@ -2736,6 +2886,29 @@ 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); @@ -2929,6 +3102,40 @@ 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); @@ -4061,7 +4268,18 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC return true; if (!obj->isNative()) { - return true; + if (obj->is<UnboxedPlainObject>()) { + UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando(); + if (expando) { + shape = expando->lookup(cx, name); + if (!shape) + return true; + } else { + return true; + } + } else { + return true; + } } size_t chainDepth; @@ -4209,6 +4427,40 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc, } static bool +TryAttachUnboxedSetPropStub(JSContext* cx, HandleScript script, + ICSetProp_Fallback* stub, HandleId id, + HandleObject obj, HandleValue rhs, bool* attached) +{ + MOZ_ASSERT(!*attached); + + if (!cx->runtime()->jitSupportsFloatingPoint) + return true; + + if (!obj->is<UnboxedPlainObject>()) + return true; + + const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id); + if (!property) + return true; + + ICSetProp_Unboxed::Compiler compiler(cx, obj->group(), + property->offset + UnboxedPlainObject::offsetOfData(), + property->type); + ICUpdatedStub* newStub = compiler.getStub(compiler.getStubSpace(script)); + if (!newStub) + return false; + if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs)) + return false; + + stub->addNewStub(newStub); + + StripPreliminaryObjectStubs(cx, stub); + + *attached = true; + return true; +} + +static bool TryAttachTypedObjectSetPropStub(JSContext* cx, HandleScript script, ICSetProp_Fallback* stub, HandleId id, HandleObject obj, HandleValue rhs, bool* attached) @@ -4291,6 +4543,12 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ return false; RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj)); + if (obj->is<UnboxedPlainObject>()) { + MOZ_ASSERT(!oldShape); + if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) + oldShape = expando->lastProperty(); + } + bool attached = false; // There are some reasons we can fail to attach a stub that are temporary. // We want to avoid calling noteUnoptimizableAccess() if the reason we @@ -4363,6 +4621,15 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ if (!attached && lhs.isObject() && + !TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached)) + { + return false; + } + if (attached) + return true; + + if (!attached && + lhs.isObject() && !TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached)) { return false; @@ -4445,7 +4712,20 @@ GuardGroupAndShapeMaybeUnboxedExpando(MacroAssembler& masm, JSObject* obj, // Guard against shape or expando shape. masm.loadPtr(Address(ICStubReg, offsetOfShape), scratch); - masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); + if (obj->is<UnboxedPlainObject>()) { + Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando()); + masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure); + Label done; + masm.push(object); + masm.loadPtr(expandoAddress, object); + masm.branchTestObjShape(Assembler::Equal, object, scratch, &done); + masm.pop(object); + masm.jump(failure); + masm.bind(&done); + masm.pop(object); + } else { + masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure); + } } bool @@ -4484,7 +4764,13 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm) regs.takeUnchecked(objReg); Register holderReg; - if (isFixedSlot_) { + if (obj_->is<UnboxedPlainObject>()) { + // We are loading off the expando object, so use that for the holder. + holderReg = regs.takeAny(); + masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); + if (!isFixedSlot_) + masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg); + } else if (isFixedSlot_) { holderReg = objReg; } else { holderReg = regs.takeAny(); @@ -4621,17 +4907,31 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) regs.add(R0); regs.takeUnchecked(objReg); - // Write the object's new shape. - Address shapeAddr(objReg, ShapedObject::offsetOfShape()); - EmitPreBarrier(masm, shapeAddr, MIRType::Shape); - masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); - masm.storePtr(scratch, shapeAddr); + if (obj_->is<UnboxedPlainObject>()) { + holderReg = regs.takeAny(); + masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg); + + // Write the expando object's new shape. + Address shapeAddr(holderReg, ShapedObject::offsetOfShape()); + EmitPreBarrier(masm, shapeAddr, MIRType::Shape); + masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); + masm.storePtr(scratch, shapeAddr); - if (isFixedSlot_) { - holderReg = objReg; + if (!isFixedSlot_) + masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg); } else { - holderReg = regs.takeAny(); - masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg); + // Write the object's new shape. + Address shapeAddr(objReg, ShapedObject::offsetOfShape()); + EmitPreBarrier(masm, shapeAddr, MIRType::Shape); + masm.loadPtr(Address(ICStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); + masm.storePtr(scratch, shapeAddr); + + if (isFixedSlot_) { + holderReg = objReg; + } else { + holderReg = regs.takeAny(); + masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg); + } } // Perform the store. No write barrier required since this is a new @@ -4663,6 +4963,70 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm) } bool +ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm) +{ + MOZ_ASSERT(engine_ == Engine::Baseline); + + Label failure; + + // Guard input is an object. + masm.branchTestObject(Assembler::NotEqual, R0, &failure); + + AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); + Register scratch = regs.takeAny(); + + // Unbox and group guard. + Register object = masm.extractObject(R0, ExtractTemp0); + masm.loadPtr(Address(ICStubReg, ICSetProp_Unboxed::offsetOfGroup()), scratch); + masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), scratch, + &failure); + + if (needsUpdateStubs()) { + // Stow both R0 and R1 (object and value). + EmitStowICValues(masm, 2); + + // Move RHS into R0 for TypeUpdate check. + masm.moveValue(R1, R0); + + // Call the type update stub. + if (!callTypeUpdateIC(masm, sizeof(Value))) + return false; + + // Unstow R0 and R1 (object and key) + EmitUnstowICValues(masm, 2); + + // The TypeUpdate IC may have smashed object. Rederive it. + masm.unboxObject(R0, object); + + // Trigger post barriers here on the values being written. Fields which + // objects can be written to also need update stubs. + LiveGeneralRegisterSet saveRegs; + saveRegs.add(R0); + saveRegs.add(R1); + saveRegs.addUnchecked(object); + saveRegs.add(ICStubReg); + emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs); + } + + // Compute the address being written to. + masm.load32(Address(ICStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch); + BaseIndex address(object, scratch, TimesOne); + + EmitUnboxedPreBarrierForBaseline(masm, address, fieldType_); + masm.storeUnboxedProperty(address, fieldType_, + ConstantOrRegister(TypedOrValueRegister(R1)), &failure); + + // The RHS has to be in R0. + masm.moveValue(R1, R0); + + EmitReturnFromIC(masm); + + masm.bind(&failure); + EmitStubGuardFailure(masm); + return true; +} + +bool ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) { MOZ_ASSERT(engine_ == Engine::Baseline); @@ -5135,6 +5499,13 @@ GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject return true; } +static void +EnsureArrayGroupAnalyzed(JSContext* cx, JSObject* obj) +{ + if (PreliminaryObjectArrayWithTemplate* objects = obj->group()->maybePreliminaryObjects()) + objects->maybeAnalyze(cx, obj->group(), /* forceAnalyze = */ true); +} + static bool GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& args, MutableHandleObject res, bool* skipAttach) @@ -5166,7 +5537,10 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& // With this and other array templates, analyze the group so that // we don't end up with a template whose structure might change later. res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject)); - return !!res; + if (!res) + return false; + EnsureArrayGroupAnalyzed(cx, res); + return true; } } @@ -5191,7 +5565,10 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& return true; } res.set(NewFullyAllocatedArrayTryReuseGroup(cx, obj, 0, TenuredObject)); - return !!res; + if (!res) + return false; + EnsureArrayGroupAnalyzed(cx, res); + return true; } } } @@ -5208,7 +5585,10 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& } res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject)); - return !!res; + if (!res) + return false; + EnsureArrayGroupAnalyzed(cx, res); + return true; } if (native == StringConstructor) { @@ -5421,7 +5801,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb if (!thisObject) return false; - if (thisObject->is<PlainObject>()) + if (thisObject->is<PlainObject>() || thisObject->is<UnboxedPlainObject>()) templateObject = thisObject; } @@ -5521,24 +5901,15 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb } static bool -CopyArray(JSContext* cx, HandleArrayObject arr, MutableHandleValue result) +CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result) { - uint32_t length = arr->length(); - ArrayObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, arr, length, TenuredObject); + uint32_t length = GetAnyBoxedOrUnboxedArrayLength(obj); + JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, obj, length, TenuredObject); if (!nobj) return false; - - MOZ_ASSERT(arr->isNative()); - MOZ_ASSERT(nobj->isNative()); - MOZ_ASSERT(nobj->as<NativeObject>().getDenseInitializedLength() == 0); - MOZ_ASSERT(arr->as<NativeObject>().getDenseInitializedLength() >= length); - MOZ_ASSERT(nobj->as<NativeObject>().getDenseCapacity() >= length); - - nobj->as<NativeObject>().setDenseInitializedLength(length); - - const Value* vp = arr->as<NativeObject>().getDenseElements(); - nobj->as<NativeObject>().initDenseElements(0, vp, length); - + EnsureArrayGroupAnalyzed(cx, nobj); + CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length); + result.setObject(*nobj); return true; } @@ -5569,22 +5940,26 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script, RootedValue arr(cx); // Copy the array before storing in stub. - if (!CopyArray(cx, obj.as<ArrayObject>(), &arr)) + if (!CopyArray(cx, obj, &arr)) return false; // Atomize all elements of the array. - RootedArrayObject arrObj(cx, &arr.toObject().as<ArrayObject>()); - uint32_t initLength = arrObj->length(); + RootedObject arrObj(cx, &arr.toObject()); + uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(arrObj); for (uint32_t i = 0; i < initLength; i++) { - JSAtom* str = js::AtomizeString(cx, arrObj->getDenseElement(i).toString()); + JSAtom* str = js::AtomizeString(cx, GetAnyBoxedOrUnboxedDenseElement(arrObj, i).toString()); if (!str) return false; - arrObj->setDenseElementWithType(cx, i, StringValue(str)); + if (!SetAnyBoxedOrUnboxedDenseElement(cx, arrObj, i, StringValue(str))) { + // The value could not be stored to an unboxed dense element. + return true; + } } ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - script->pcToOffset(pc), str, sep, arrObj); + script->pcToOffset(pc), str, sep, + arr); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -6472,7 +6847,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm) return true; } -typedef bool (*CopyArrayFn)(JSContext*, HandleArrayObject, MutableHandleValue); +typedef bool (*CopyArrayFn)(JSContext*, HandleObject, MutableHandleValue); static const VMFunction CopyArrayInfo = FunctionInfo<CopyArrayFn>(CopyArray, "CopyArray"); bool @@ -7949,6 +8324,19 @@ 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) @@ -8324,8 +8712,8 @@ static bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICRest_Fallback* unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; Value* rest = frame->argv() + numFormals; - ArrayObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject, - ObjectGroup::NewArrayKind::UnknownIndex); + JSObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject, + ObjectGroup::NewArrayKind::UnknownIndex); if (!obj) return false; res.setObject(*obj); |