author | André Bargull <andre.bargull@gmail.com> |
Mon, 07 Oct 2019 11:59:10 +0000 | |
changeset 496561 | 3601bf7917332395df032c833f9903e826ead8e9 |
parent 496560 | 6eead2ab3379aa4818ca3e6d4fc228ade46d4296 |
child 496562 | 42469f1d04913311bd96876eb106a8fba39d2223 |
push id | 97326 |
push user | archaeopteryx@coole-files.de |
push date | Mon, 07 Oct 2019 16:46:32 +0000 |
treeherder | autoland@144ebbca6844 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1574415 |
milestone | 71.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
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/store-typed-element-constant-double-rhs.js @@ -0,0 +1,15 @@ +// Different typed array types to ensure we emit a SetProp IC. +var xs = [ + new Float32Array(10), + new Float64Array(10), +]; + +for (var i = 0; i < 100; ++i) { + var ta = xs[i & 1]; + + // Store with constant rhs. + ta[0] = 0.1; +} + +assertEq(xs[0][0], Math.fround(0.1)); +assertEq(xs[1][0], 0.1);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/store-typed-element-payload-reg-rhs.js @@ -0,0 +1,17 @@ +// Different typed array types to ensure we emit a SetProp IC. +var xs = [ + new Float32Array(10), + new Float64Array(10), +]; + +for (var i = 0; i < 100; ++i) { + var ta = xs[i & 1]; + + var v = +ta[0]; + + // Store with payload-register rhs. + ta[0] = ~v; +} + +assertEq(xs[0][0], 0); +assertEq(xs[1][0], 0);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/store-typed-element-payload-stack-rhs.js @@ -0,0 +1,20 @@ +// Different typed array types to ensure we emit a SetProp IC. +var xs = [ + new Float32Array(10), + new Float64Array(10), +]; + +function f(ta) { + for (var k = 0;;) { + // Store with payload-stack rhs. + ta[k] = k; + break; + } +} + +for (var i = 0; i < 100; ++i) { + f(xs[i & 1]); +} + +assertEq(xs[0][0], 0); +assertEq(xs[1][0], 0);
--- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -1440,88 +1440,16 @@ bool BaselineCacheIRCompiler::emitArrayP // Return value is new length. masm.add32(Imm32(1), scratchLength); masm.tagValue(JSVAL_TYPE_INT32, scratchLength, val); return true; } -bool BaselineCacheIRCompiler::emitStoreTypedElement() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - TypedThingLayout layout = reader.typedThingLayout(); - Scalar::Type type = reader.scalarType(); - Register index = allocator.useRegister(masm, reader.int32OperandId()); - - Maybe<Register> valInt32; - Maybe<NumberOperandId> valFloat; - switch (type) { - case Scalar::Int8: - case Scalar::Uint8: - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - case Scalar::Uint32: - case Scalar::Uint8Clamped: - valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId())); - break; - - case Scalar::Float32: - case Scalar::Float64: - valFloat.emplace(reader.numberOperandId()); - break; - - case Scalar::BigInt64: - case Scalar::BigUint64: - case Scalar::MaxTypedArrayViewType: - case Scalar::Int64: - MOZ_CRASH("Unsupported TypedArray type"); - } - - bool handleOOB = reader.readBool(); - - AutoScratchRegister scratch1(allocator, masm); - AutoScratchRegister scratch2(allocator, masm); - - FailurePath* failure; - if (!addFailurePath(&failure)) { - return false; - } - - // Bounds check. - Label done; - LoadTypedThingLength(masm, layout, obj, scratch1); - - masm.spectreBoundsCheck32(index, scratch1, scratch2, - handleOOB ? &done : failure->label()); - - // Load the elements vector. - LoadTypedThingData(masm, layout, obj, scratch1); - - BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type))); - - if (type == Scalar::Float32 || type == Scalar::Float64) { - allocator.ensureDoubleRegister(masm, *valFloat, FloatReg0); - - if (type == Scalar::Float32) { - ScratchFloat32Scope fpscratch(masm); - masm.convertDoubleToFloat32(FloatReg0, fpscratch); - masm.storeToTypedFloatArray(type, fpscratch, dest); - } else { - masm.storeToTypedFloatArray(type, FloatReg0, dest); - } - } else { - masm.storeToTypedIntArray(type, *valInt32, dest); - } - - masm.bind(&done); - return true; -} - bool BaselineCacheIRCompiler::emitCallNativeSetter() { JitSpew(JitSpew_Codegen, __FUNCTION__); Register obj = allocator.useRegister(masm, reader.objOperandId()); Address setterAddr(stubAddress(reader.stubOffset())); ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId()); AutoScratchRegister scratch(allocator, masm);
--- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -128,19 +128,42 @@ void CacheRegisterAllocator::ensureDoubl } case OperandLocation::DoubleReg: { masm.moveDouble(loc.doubleReg(), dest); loc.setDoubleReg(dest); return; } - case OperandLocation::Constant: - case OperandLocation::PayloadStack: - case OperandLocation::PayloadReg: + case OperandLocation::Constant: { + MOZ_ASSERT(loc.constant().isNumber(), + "Caller must ensure the operand is a number value"); + masm.loadConstantDouble(loc.constant().toNumber(), dest); + return; + } + + case OperandLocation::PayloadReg: { + // Doubles can't be stored in payload registers, so this must be an int32. + MOZ_ASSERT(loc.payloadType() == JSVAL_TYPE_INT32, + "Caller must ensure the operand is a number value"); + masm.convertInt32ToDouble(loc.payloadReg(), dest); + return; + } + + case OperandLocation::PayloadStack: { + // Doubles can't be stored in payload registers, so this must be an int32. + MOZ_ASSERT(loc.payloadType() == JSVAL_TYPE_INT32, + "Caller must ensure the operand is a number value"); + MOZ_ASSERT(loc.payloadStack() <= stackPushed_); + masm.convertInt32ToDouble( + Address(masm.getStackPointer(), stackPushed_ - loc.payloadStack()), + dest); + return; + } + case OperandLocation::Uninitialized: MOZ_CRASH("Unhandled operand type in ensureDoubleRegister"); return; } masm.jump(&done); masm.bind(&failure); masm.assumeUnreachable( "Missing guard allowed non-number to hit ensureDoubleRegister"); @@ -3368,16 +3391,85 @@ bool CacheIRCompiler::emitArrayJoinResul // Store the value. masm.loadValue(elementAddr, output.valueReg()); masm.bind(&finished); return true; } +bool CacheIRCompiler::emitStoreTypedElement() { + JitSpew(JitSpew_Codegen, __FUNCTION__); + Register obj = allocator.useRegister(masm, reader.objOperandId()); + TypedThingLayout layout = reader.typedThingLayout(); + Scalar::Type type = reader.scalarType(); + Register index = allocator.useRegister(masm, reader.int32OperandId()); + + Maybe<Register> valInt32; + switch (type) { + case Scalar::Int8: + case Scalar::Uint8: + case Scalar::Int16: + case Scalar::Uint16: + case Scalar::Int32: + case Scalar::Uint32: + case Scalar::Uint8Clamped: + valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId())); + break; + + case Scalar::Float32: + case Scalar::Float64: + // Float register must be preserved. The SetProp ICs use the fact that + // baseline has them available, as well as fixed temps on + // LSetPropertyCache. + allocator.ensureDoubleRegister(masm, reader.numberOperandId(), FloatReg0); + break; + + case Scalar::BigInt64: + case Scalar::BigUint64: + case Scalar::MaxTypedArrayViewType: + case Scalar::Int64: + MOZ_CRASH("Unsupported TypedArray type"); + } + + bool handleOOB = reader.readBool(); + + AutoScratchRegister scratch1(allocator, masm); + AutoScratchRegister scratch2(allocator, masm); + + FailurePath* failure; + if (!addFailurePath(&failure)) { + return false; + } + + // Bounds check. + Label done; + LoadTypedThingLength(masm, layout, obj, scratch1); + masm.spectreBoundsCheck32(index, scratch1, scratch2, + handleOOB ? &done : failure->label()); + + // Load the elements vector. + LoadTypedThingData(masm, layout, obj, scratch1); + + BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type))); + + if (type == Scalar::Float32) { + ScratchFloat32Scope fpscratch(masm); + masm.convertDoubleToFloat32(FloatReg0, fpscratch); + masm.storeToTypedFloatArray(type, fpscratch, dest); + } else if (type == Scalar::Float64) { + masm.storeToTypedFloatArray(type, FloatReg0, dest); + } else { + masm.storeToTypedIntArray(type, *valInt32, dest); + } + + masm.bind(&done); + return true; +} + bool CacheIRCompiler::emitLoadTypedElementResult() { JitSpew(JitSpew_Codegen, __FUNCTION__); AutoOutputRegister output(*this); Register obj = allocator.useRegister(masm, reader.objOperandId()); Register index = allocator.useRegister(masm, reader.int32OperandId()); TypedThingLayout layout = reader.typedThingLayout(); Scalar::Type type = reader.scalarType();
--- a/js/src/jit/CacheIRCompiler.h +++ b/js/src/jit/CacheIRCompiler.h @@ -118,16 +118,17 @@ class IonCacheIRCompiler; _(LoadObjectTruthyResult) \ _(LoadNewObjectFromTemplateResult) \ _(CompareObjectResult) \ _(CompareSymbolResult) \ _(CompareInt32Result) \ _(CompareDoubleResult) \ _(CompareObjectUndefinedNullResult) \ _(ArrayJoinResult) \ + _(StoreTypedElement) \ _(CallPrintString) \ _(Breakpoint) \ _(MegamorphicLoadSlotResult) \ _(MegamorphicLoadSlotByValueResult) \ _(MegamorphicStoreSlot) \ _(MegamorphicHasPropResult) \ _(CallObjectHasSparseElementResult) \ _(CallInt32ToString) \
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -11202,30 +11202,28 @@ void CodeGenerator::addGetPropertyCache( } IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, resultFlags); addIC(ins, allocateIC(cache)); } void CodeGenerator::addSetPropertyCache( LInstruction* ins, LiveRegisterSet liveRegs, Register objReg, Register temp, - FloatRegister tempDouble, FloatRegister tempF32, const ConstantOrRegister& id, const ConstantOrRegister& value, bool strict, bool needsPostBarrier, bool needsTypeBarrier, bool guardHoles) { CacheKind kind = CacheKind::SetElem; if (id.constant() && id.value().isString()) { JSString* idString = id.value().toString(); uint32_t dummy; if (idString->isAtom() && !idString->asAtom().isIndex(&dummy)) { kind = CacheKind::SetProp; } } - IonSetPropertyIC cache(kind, liveRegs, objReg, temp, tempDouble, tempF32, id, - value, strict, needsPostBarrier, needsTypeBarrier, - guardHoles); + IonSetPropertyIC cache(kind, liveRegs, objReg, temp, id, value, strict, + needsPostBarrier, needsTypeBarrier, guardHoles); addIC(ins, allocateIC(cache)); } ConstantOrRegister CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type) { if (type == MIRType::Value) { return TypedOrValueRegister(ToValue(lir, n)); } @@ -11393,27 +11391,24 @@ void CodeGenerator::visitCallDeleteEleme callVM<Fn, DeleteElementJit<false>>(lir); } } void CodeGenerator::visitSetPropertyCache(LSetPropertyCache* ins) { LiveRegisterSet liveRegs = ins->safepoint()->liveRegs(); Register objReg = ToRegister(ins->getOperand(0)); Register temp = ToRegister(ins->temp()); - FloatRegister tempDouble = ToTempFloatRegisterOrInvalid(ins->tempDouble()); - FloatRegister tempF32 = ToTempFloatRegisterOrInvalid(ins->tempFloat32()); ConstantOrRegister id = toConstantOrRegister(ins, LSetPropertyCache::Id, ins->mir()->idval()->type()); ConstantOrRegister value = toConstantOrRegister(ins, LSetPropertyCache::Value, ins->mir()->value()->type()); - addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32, id, - value, ins->mir()->strict(), - ins->mir()->needsPostBarrier(), + addSetPropertyCache(ins, liveRegs, objReg, temp, id, value, + ins->mir()->strict(), ins->mir()->needsPostBarrier(), ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles()); } void CodeGenerator::visitThrow(LThrow* lir) { pushArg(ToValue(lir, LThrow::Value)); using Fn = bool (*)(JSContext*, HandleValue); callVM<Fn, js::ThrowOperation>(lir);
--- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -238,17 +238,16 @@ class CodeGenerator final : public CodeG void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, TypedOrValueRegister value, const ConstantOrRegister& id, TypedOrValueRegister output, Register maybeTemp, GetPropertyResultFlags flags); void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg, Register temp, - FloatRegister tempDouble, FloatRegister tempF32, const ConstantOrRegister& id, const ConstantOrRegister& value, bool strict, bool needsPostBarrier, bool needsTypeBarrier, bool guardHoles); MOZ_MUST_USE bool generateBranchV(const ValueOperand& value, Label* ifTrue, Label* ifFalse, FloatRegister fr);
--- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -1804,98 +1804,16 @@ bool IonCacheIRCompiler::emitStoreDenseE return true; } bool IonCacheIRCompiler::emitArrayPush() { MOZ_ASSERT_UNREACHABLE("emitArrayPush not supported for IonCaches."); return false; } -bool IonCacheIRCompiler::emitStoreTypedElement() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - TypedThingLayout layout = reader.typedThingLayout(); - Scalar::Type arrayType = reader.scalarType(); - Register index = allocator.useRegister(masm, reader.int32OperandId()); - - Maybe<Register> valInt32; - Maybe<ConstantOrRegister> valFloat; - switch (arrayType) { - case Scalar::Int8: - case Scalar::Uint8: - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - case Scalar::Uint32: - case Scalar::Uint8Clamped: - valInt32.emplace(allocator.useRegister(masm, reader.int32OperandId())); - break; - - case Scalar::Float32: - case Scalar::Float64: - valFloat.emplace( - allocator.useConstantOrRegister(masm, reader.numberOperandId())); - break; - - case Scalar::BigInt64: - case Scalar::BigUint64: - case Scalar::MaxTypedArrayViewType: - case Scalar::Int64: - MOZ_CRASH("Unsupported TypedArray type"); - } - - bool handleOOB = reader.readBool(); - - AutoScratchRegister scratch1(allocator, masm); - AutoScratchRegister scratch2(allocator, masm); - - FailurePath* failure; - if (!addFailurePath(&failure)) { - return false; - } - - // Bounds check. - Label done; - LoadTypedThingLength(masm, layout, obj, scratch1); - masm.spectreBoundsCheck32(index, scratch1, scratch2, - handleOOB ? &done : failure->label()); - - // Load the elements vector. - LoadTypedThingData(masm, layout, obj, scratch1); - - BaseIndex dest(scratch1, index, - ScaleFromElemWidth(Scalar::byteSize(arrayType))); - - FloatRegister maybeTempDouble = ic_->asSetPropertyIC()->maybeTempDouble(); - FloatRegister maybeTempFloat32 = ic_->asSetPropertyIC()->maybeTempFloat32(); - MOZ_ASSERT(maybeTempDouble != InvalidFloatReg); - MOZ_ASSERT_IF(jit::hasUnaliasedDouble(), maybeTempFloat32 != InvalidFloatReg); - - if (arrayType == Scalar::Float32) { - FloatRegister tempFloat = - hasUnaliasedDouble() ? maybeTempFloat32 : maybeTempDouble; - if (!masm.convertConstantOrRegisterToFloat(cx_, *valFloat, tempFloat, - failure->label())) { - return false; - } - masm.storeToTypedFloatArray(arrayType, tempFloat, dest); - } else if (arrayType == Scalar::Float64) { - if (!masm.convertConstantOrRegisterToDouble(cx_, *valFloat, maybeTempDouble, - failure->label())) { - return false; - } - masm.storeToTypedFloatArray(arrayType, maybeTempDouble, dest); - } else { - masm.storeToTypedIntArray(arrayType, *valInt32, dest); - } - - masm.bind(&done); - return true; -} - bool IonCacheIRCompiler::emitCallNativeSetter() { JitSpew(JitSpew_Codegen, __FUNCTION__); AutoSaveLiveRegisters save(*this); Register obj = allocator.useRegister(masm, reader.objOperandId()); JSFunction* target = &objectStubField(reader.stubOffset())->as<JSFunction>(); MOZ_ASSERT(target->isNative()); ConstantOrRegister val =
--- a/js/src/jit/IonIC.h +++ b/js/src/jit/IonIC.h @@ -280,53 +280,46 @@ class IonGetPropSuperIC : public IonIC { MutableHandleValue res); }; class IonSetPropertyIC : public IonIC { LiveRegisterSet liveRegs_; Register object_; Register temp_; - FloatRegister maybeTempDouble_; - FloatRegister maybeTempFloat32_; ConstantOrRegister id_; ConstantOrRegister rhs_; bool strict_ : 1; bool needsPostBarrier_ : 1; bool needsTypeBarrier_ : 1; bool guardHoles_ : 1; public: IonSetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, - Register temp, FloatRegister maybeTempDouble, - FloatRegister maybeTempFloat32, const ConstantOrRegister& id, + Register temp, const ConstantOrRegister& id, const ConstantOrRegister& rhs, bool strict, bool needsPostBarrier, bool needsTypeBarrier, bool guardHoles) : IonIC(kind), liveRegs_(liveRegs), object_(object), temp_(temp), - maybeTempDouble_(maybeTempDouble), - maybeTempFloat32_(maybeTempFloat32), id_(id), rhs_(rhs), strict_(strict), needsPostBarrier_(needsPostBarrier), needsTypeBarrier_(needsTypeBarrier), guardHoles_(guardHoles) {} LiveRegisterSet liveRegs() const { return liveRegs_; } Register object() const { return object_; } ConstantOrRegister id() const { return id_; } ConstantOrRegister rhs() const { return rhs_; } Register temp() const { return temp_; } - FloatRegister maybeTempDouble() const { return maybeTempDouble_; } - FloatRegister maybeTempFloat32() const { return maybeTempFloat32_; } bool strict() const { return strict_; } bool needsPostBarrier() const { return needsPostBarrier_; } bool needsTypeBarrier() const { return needsTypeBarrier_; } bool guardHoles() const { return guardHoles_; } static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonSetPropertyIC* ic, HandleObject obj,
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3898,29 +3898,26 @@ void LIRGenerator::visitSetPropertyCache bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol; bool useConstValue = IsNonNurseryConstant(ins->value()); // Emit an overrecursed check: this is necessary because the cache can // attach a scripted setter stub that calls this script recursively. gen->setNeedsOverrecursedCheck(); - // We need a double/float32 temp register for typed array stubs if this is - // a SETELEM or INITELEM op. + // We need a double temp register for typed array stubs if this is a SETELEM + // or INITELEM op. LDefinition tempD = LDefinition::BogusTemp(); - LDefinition tempF32 = LDefinition::BogusTemp(); if (IsElemPC(ins->resumePoint()->pc())) { - tempD = tempDouble(); - tempF32 = hasUnaliasedDouble() ? tempFloat32() : LDefinition::BogusTemp(); + tempD = tempFixed(FloatReg0); } LInstruction* lir = new (alloc()) LSetPropertyCache( useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId), - useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD, - tempF32); + useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD); add(lir, ins); assignSafepoint(lir, ins); } void LIRGenerator::visitCallSetElement(MCallSetElement* ins) { MOZ_ASSERT(ins->object()->type() == MIRType::Object); MOZ_ASSERT(ins->index()->type() == MIRType::Value); MOZ_ASSERT(ins->value()->type() == MIRType::Value);
--- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5410,46 +5410,39 @@ class LCallDeleteElement : public LCallI setBoxOperand(Value, value); setBoxOperand(Index, index); } MDeleteElement* mir() const { return mir_->toDeleteElement(); } }; // Patchable jump to stubs generated for a SetProperty cache. -class LSetPropertyCache : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 3> { +class LSetPropertyCache : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 2> { public: LIR_HEADER(SetPropertyCache) + // Takes an additional temp: this is intendend to be FloatReg0 to allow the + // actual cache code to safely clobber that value without save and restore. LSetPropertyCache(const LAllocation& object, const LBoxAllocation& id, const LBoxAllocation& value, const LDefinition& temp, - const LDefinition& tempDouble, - const LDefinition& tempFloat32) + const LDefinition& tempDouble) : LInstructionHelper(classOpcode) { setOperand(0, object); setBoxOperand(Id, id); setBoxOperand(Value, value); setTemp(0, temp); setTemp(1, tempDouble); - setTemp(2, tempFloat32); } static const size_t Id = 1; static const size_t Value = 1 + BOX_PIECES; const MSetPropertyCache* mir() const { return mir_->toSetPropertyCache(); } const LDefinition* temp() { return getTemp(0); } - const LDefinition* tempDouble() { return getTemp(1); } - const LDefinition* tempFloat32() { - if (hasUnaliasedDouble()) { - return getTemp(2); - } - return getTemp(1); - } }; class LGetIteratorCache : public LInstructionHelper<1, BOX_PIECES, 2> { public: LIR_HEADER(GetIteratorCache) static const size_t Value = 0;