diff options
Diffstat (limited to 'js/src/jit/BaselineIC.cpp')
-rw-r--r-- | js/src/jit/BaselineIC.cpp | 213 |
1 files changed, 181 insertions, 32 deletions
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 1b98325b79..9c8cd98350 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1375,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; @@ -1479,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() && @@ -2085,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 // @@ -2388,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; @@ -2398,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. @@ -2479,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) { @@ -2818,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); @@ -3011,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); @@ -5374,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) @@ -5405,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; } } @@ -5430,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; } } } @@ -5447,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) { @@ -5760,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; } @@ -5808,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; @@ -6711,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 @@ -8188,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) @@ -8563,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); |