diff options
Diffstat (limited to 'js/src/jit/IonCaches.cpp')
-rw-r--r-- | js/src/jit/IonCaches.cpp | 135 |
1 files changed, 117 insertions, 18 deletions
diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index f5e4659c1a..c2dc573738 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -639,6 +639,9 @@ 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()), @@ -1185,6 +1188,39 @@ 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. @@ -1559,6 +1595,40 @@ 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) { @@ -2133,6 +2203,9 @@ 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; } @@ -3953,7 +4026,7 @@ GetPropertyIC::tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval, TypedOrValueRegister output) { - if (!obj->is<TypedArrayObject>()) + if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>()) return false; MOZ_ASSERT(idval.isInt32() || idval.isString()); @@ -3984,6 +4057,13 @@ 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(); } @@ -4060,27 +4140,46 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm, Label popObjectAndFail; - // Guard on the initialized length. - Address length(object, TypedArrayObject::lengthOffset()); - masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures); + if (array->is<TypedArrayObject>()) { + // 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); + // 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); + } } else { - masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail); + // 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.pop(object); |