mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 08:18:41 +09:00
Bug 903519 - Strings in the nursery: JIT
Bug 903519 - Strings in the nursery: JIT, majority of it was not done before due CodeGenerator.cpp
This commit is contained in:
parent
166a98559f
commit
2c7a142dc6
16 changed files with 286 additions and 48 deletions
|
|
@ -157,14 +157,17 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitMonitorTypes(LMonitorTypes* lir);
|
||||
void emitPostWriteBarrier(const LAllocation* obj);
|
||||
void emitPostWriteBarrier(Register objreg);
|
||||
template <class LPostBarrierType>
|
||||
void visitPostWriteBarrierCommonO(LPostBarrierType* lir, OutOfLineCode* ool);
|
||||
void emitPostWriteBarrierS(Address address, Register prev, Register next);
|
||||
template <class LPostBarrierType, MIRType nurseryType>
|
||||
void visitPostWriteBarrierCommon(LPostBarrierType* lir, OutOfLineCode* ool);
|
||||
template <class LPostBarrierType>
|
||||
void visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool);
|
||||
void visitPostWriteBarrierO(LPostWriteBarrierO* lir);
|
||||
void visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir);
|
||||
void visitPostWriteBarrierV(LPostWriteBarrierV* lir);
|
||||
void visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir);
|
||||
void visitPostWriteBarrierS(LPostWriteBarrierS* lir) override;
|
||||
void visitPostWriteElementBarrierS(LPostWriteElementBarrierS* lir) override;
|
||||
void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
|
||||
void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
|
||||
void visitCallNative(LCallNative* call);
|
||||
|
|
|
|||
|
|
@ -450,14 +450,7 @@ JitCompartment::initialize(JSContext* cx)
|
|||
return false;
|
||||
}
|
||||
|
||||
cacheIRStubCodes_ = cx->new_<CacheIRStubCodeMap>(cx->runtime());
|
||||
if (!cacheIRStubCodes_)
|
||||
return false;
|
||||
|
||||
if (!cacheIRStubCodes_->init()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
stringsCanBeInNursery = cx->nursery().canAllocateStrings();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9094,7 +9094,11 @@ jit::NeedsPostBarrier(MDefinition* value)
|
|||
{
|
||||
if (!GetJitContext()->runtime->gcNursery().exists())
|
||||
return false;
|
||||
return value->mightBeType(MIRType::Object);
|
||||
if (value->mightBeType(MIRType::Object))
|
||||
return true;
|
||||
if (value->mightBeType(MIRType::String) && runtime->canNurseryAllocateStrings())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -665,6 +665,8 @@ class JitCompartment
|
|||
}
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
bool stringsCanBeInNursery;
|
||||
};
|
||||
|
||||
// Called from JSCompartment::discardJitCode().
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ TryToUseImplicitInterruptCheck(MIRGraph& graph, MBasicBlock* backedge)
|
|||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(iter->isPostWriteBarrierO() || iter->isPostWriteBarrierV(),
|
||||
MOZ_ASSERT_IF(iter->isPostWriteBarrierO() || iter->isPostWriteBarrierV() || iter->isPostWriteBarrierS(),
|
||||
iter->safepoint());
|
||||
|
||||
if (iter->safepoint())
|
||||
|
|
@ -2761,6 +2761,17 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins)
|
|||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
}
|
||||
case MIRType::String: {
|
||||
LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
|
||||
LPostWriteBarrierS* lir =
|
||||
new(alloc()) LPostWriteBarrierS(useConstantObject
|
||||
? useOrConstant(ins->object())
|
||||
: useRegister(ins->object()),
|
||||
useRegister(ins->value()), tmp);
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
}
|
||||
case MIRType::Value: {
|
||||
LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
|
||||
|
|
@ -2810,6 +2821,19 @@ LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
}
|
||||
case MIRType::String: {
|
||||
LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
|
||||
LPostWriteElementBarrierS* lir =
|
||||
new(alloc()) LPostWriteElementBarrierS(useConstantObject
|
||||
? useOrConstant(ins->object())
|
||||
: useRegister(ins->object()),
|
||||
useRegister(ins->value()),
|
||||
useRegister(ins->index()),
|
||||
tmp);
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
}
|
||||
case MIRType::Value: {
|
||||
LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
|
||||
LPostWriteElementBarrierV* lir =
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ class MIRGenerator
|
|||
return isProfilerInstrumentationEnabled() && !info().isAnalysis();
|
||||
}
|
||||
|
||||
bool stringsCanBeInNursery() const {
|
||||
return stringsCanBeInNursery_;
|
||||
}
|
||||
|
||||
bool safeForMinorGC() const {
|
||||
return safeForMinorGC_;
|
||||
}
|
||||
|
|
@ -194,6 +198,7 @@ class MIRGenerator
|
|||
bool instrumentedProfiling_;
|
||||
bool instrumentedProfilingIsCached_;
|
||||
bool safeForMinorGC_;
|
||||
bool stringsCanBeInNursery_;
|
||||
|
||||
void addAbortedPreliminaryGroup(ObjectGroup* group);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
|
|||
instrumentedProfiling_(false),
|
||||
instrumentedProfilingIsCached_(false),
|
||||
safeForMinorGC_(true),
|
||||
stringsCanBeInNursery_(GetJitContext()->runtime()->canNurseryAllocateStrings() : false),
|
||||
minWasmHeapLength_(0),
|
||||
options(options),
|
||||
gs_(alloc)
|
||||
|
|
|
|||
|
|
@ -693,11 +693,10 @@ MacroAssembler::shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap i
|
|||
// Inline version of Nursery::allocateObject. If the object has dynamic slots,
|
||||
// this fills in the slots_ pointer.
|
||||
void
|
||||
MacroAssembler::nurseryAllocate(Register result, Register temp, gc::AllocKind allocKind,
|
||||
size_t nDynamicSlots, gc::InitialHeap initialHeap, Label* fail)
|
||||
MacroAssembler::nurseryAllocateObject(Register result, Register temp, gc::AllocKind allocKind,
|
||||
size_t nDynamicSlots, Label* fail)
|
||||
{
|
||||
MOZ_ASSERT(IsNurseryAllocable(allocKind));
|
||||
MOZ_ASSERT(initialHeap != gc::TenuredHeap);
|
||||
|
||||
// We still need to allocate in the nursery, per the comment in
|
||||
// shouldNurseryAllocate; however, we need to insert into the
|
||||
|
|
@ -807,8 +806,10 @@ MacroAssembler::allocateObject(Register result, Register temp, gc::AllocKind all
|
|||
|
||||
checkAllocatorState(fail);
|
||||
|
||||
if (shouldNurseryAllocate(allocKind, initialHeap))
|
||||
return nurseryAllocate(result, temp, allocKind, nDynamicSlots, initialHeap, fail);
|
||||
if (shouldNurseryAllocate(allocKind, initialHeap)) {
|
||||
MOZ_ASSERT(initialHeap == gc::DefaultHeap);
|
||||
return nurseryAllocateObject(result, temp, allocKind, nDynamicSlots, fail);
|
||||
}
|
||||
|
||||
if (!nDynamicSlots)
|
||||
return freeListAllocate(result, temp, allocKind, fail);
|
||||
|
|
@ -869,15 +870,78 @@ MacroAssembler::allocateNonObject(Register result, Register temp, gc::AllocKind
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::newGCString(Register result, Register temp, Label* fail)
|
||||
MacroAssembler::nurseryAllocateString(Register result, Register temp, gc::AllocKind allocKind,
|
||||
Label* fail)
|
||||
{
|
||||
allocateNonObject(result, temp, js::gc::AllocKind::STRING, fail);
|
||||
MOZ_ASSERT(IsNurseryAllocable(allocKind));
|
||||
|
||||
// No explicit check for nursery.isEnabled() is needed, as the comparison
|
||||
// with the nursery's end will always fail in such cases.
|
||||
|
||||
CompileZone* zone = GetJitContext()->compartment->zone();
|
||||
int thingSize = int(gc::Arena::thingSize(allocKind));
|
||||
int totalSize = js::Nursery::stringHeaderSize() + thingSize;
|
||||
MOZ_ASSERT(totalSize % gc::CellAlignBytes == 0);
|
||||
|
||||
// The nursery position (allocation pointer) and the nursery end are stored
|
||||
// very close to each other. In practice, the zone will probably be close
|
||||
// (within 32 bits) as well. If so, use relative offsets between them, to
|
||||
// avoid multiple 64-bit immediate loads.
|
||||
auto nurseryPosAddr = intptr_t(zone->addressOfNurseryPosition());
|
||||
auto nurseryEndAddr = intptr_t(zone->addressOfNurseryCurrentEnd());
|
||||
auto zoneAddr = intptr_t(zone);
|
||||
|
||||
intptr_t maxOffset = std::max(std::abs(nurseryPosAddr - zoneAddr),
|
||||
std::abs(nurseryEndAddr - zoneAddr));
|
||||
if (maxOffset < (1 << 31)) {
|
||||
movePtr(ImmPtr(zone), temp); // temp holds the Zone pointer from here on.
|
||||
loadPtr(Address(temp, nurseryPosAddr - zoneAddr), result);
|
||||
addPtr(Imm32(totalSize), result); // result points past this allocation.
|
||||
branchPtr(Assembler::Below, Address(temp, nurseryEndAddr - zoneAddr), result, fail);
|
||||
storePtr(result, Address(temp, nurseryPosAddr - zoneAddr)); // Update position.
|
||||
subPtr(Imm32(thingSize), result); // Point result at Cell data.
|
||||
storePtr(temp, Address(result, -js::Nursery::stringHeaderSize())); // Store Zone*
|
||||
} else {
|
||||
// Otherwise, the zone is far from the nursery pointers. But the
|
||||
// nursery pos/end pointers are still near each other.
|
||||
movePtr(ImmPtr(zone->addressOfNurseryPosition()), temp);
|
||||
loadPtr(Address(temp, 0), result);
|
||||
addPtr(Imm32(totalSize), result);
|
||||
branchPtr(Assembler::Below, Address(temp, nurseryEndAddr - nurseryPosAddr), result, fail);
|
||||
storePtr(result, Address(temp, 0));
|
||||
subPtr(Imm32(thingSize), result);
|
||||
storePtr(ImmPtr(zone), Address(result, -js::Nursery::stringHeaderSize()));
|
||||
}
|
||||
}
|
||||
|
||||
// Inlined equivalent of gc::AllocateString, jumping to fail if nursery
|
||||
// allocation requested but unsuccessful.
|
||||
void
|
||||
MacroAssembler::allocateString(Register result, Register temp, gc::AllocKind allocKind,
|
||||
gc::InitialHeap initialHeap, Label* fail)
|
||||
{
|
||||
MOZ_ASSERT(allocKind == gc::AllocKind::STRING || allocKind == gc::AllocKind::FAT_INLINE_STRING);
|
||||
|
||||
checkAllocatorState(fail);
|
||||
|
||||
if (shouldNurseryAllocate(allocKind, initialHeap)) {
|
||||
MOZ_ASSERT(initialHeap == gc::DefaultHeap);
|
||||
return nurseryAllocateString(result, temp, allocKind, fail);
|
||||
}
|
||||
|
||||
freeListAllocate(result, temp, allocKind, fail);
|
||||
}
|
||||
MacroAssembler::newGCString(Register result, Register temp, Label* fail, bool attemptNursery)
|
||||
{
|
||||
allocateString(result, temp, js::gc::AllocKind::STRING,
|
||||
attemptNursery ? gc::DefaultHeap : gc::TenuredHeap, fail);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::newGCFatInlineString(Register result, Register temp, Label* fail)
|
||||
MacroAssembler::newGCFatInlineString(Register result, Register temp, Label* fail, bool attemptNursery)
|
||||
{
|
||||
allocateNonObject(result, temp, js::gc::AllocKind::FAT_INLINE_STRING, fail);
|
||||
allocateString(result, temp, js::gc::AllocKind::FAT_INLINE_STRING,
|
||||
attemptNursery ? gc::DefaultHeap : gc::TenuredHeap, fail);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1259,6 +1323,16 @@ MacroAssembler::initUnboxedObjectContents(Register object, UnboxedPlainObject* t
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::leaNewDependentStringBase(Register str, Register dest)
|
||||
{
|
||||
MOZ_ASSERT(str != dest);
|
||||
|
||||
// Spectre-safe because this is a newly allocated dependent string, thus we
|
||||
// are certain of its type and the type of its base field.
|
||||
computeEffectiveAddress(Address(str, JSDependentString::offsetOfBase()), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result,
|
||||
Label* fail)
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
|
||||
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
|
||||
|
||||
// Given a pointer to a GC Cell, retrieve the StoreBuffer pointer from its
|
||||
// chunk trailer, or nullptr if it is in the tenured heap.
|
||||
void loadStoreBuffer(Register ptr, Register buffer) PER_ARCH;
|
||||
|
||||
template <typename T>
|
||||
inline CodeOffsetJump branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH;
|
||||
template <typename T>
|
||||
|
|
@ -1030,8 +1034,9 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
|
||||
void branchPtrInNurseryChunk(Condition cond, const Address& address, Register temp, Label* label)
|
||||
DEFINED_ON(x86);
|
||||
void branchValueIsNurseryObject(Condition cond, const Address& address, Register temp, Label* label) PER_ARCH;
|
||||
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) PER_ARCH;
|
||||
void branchValueIsNurseryCell(Condition cond, const Address& address, Register temp, Label* label) PER_ARCH;
|
||||
void branchValueIsNurseryCell(Condition cond, ValueOperand value, Register temp, Label* label) PER_ARCH;
|
||||
|
||||
// This function compares a Value (lhs) which is having a private pointer
|
||||
// boxed inside a js::Value, with a raw pointer (rhs).
|
||||
|
|
@ -1253,7 +1258,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
void branchPtrInNurseryChunkImpl(Condition cond, Register ptr, Label* label)
|
||||
DEFINED_ON(x86);
|
||||
template <typename T>
|
||||
void branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp, Label* label)
|
||||
void branchValueIsNurseryCellImpl(Condition cond, const T& value, Register temp, Label* label)
|
||||
DEFINED_ON(arm64, mips64, x64);
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -1492,12 +1497,13 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
void loadStringChars(Register str, Register dest);
|
||||
void loadStringChar(Register str, Register index, Register output, Label* fail);
|
||||
void leaNewDependentStringBase(Register str, Register dest);
|
||||
|
||||
void loadJSContext(Register dest);
|
||||
|
||||
void loadJSContext(Register dest) {
|
||||
movePtr(ImmPtr(GetJitContext()->runtime->getJSContext()), dest);
|
||||
}
|
||||
void loadJitActivation(Register dest) {
|
||||
loadPtr(AbsoluteAddress(GetJitContext()->runtime->addressOfActivation()), dest);
|
||||
loadJSContext(dest);
|
||||
loadPtr(Address(dest, offsetof(JSContext, activation_)), dest);
|
||||
}
|
||||
void loadWasmActivationFromTls(Register dest) {
|
||||
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
|
||||
|
|
@ -1749,11 +1755,15 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
private:
|
||||
void checkAllocatorState(Label* fail);
|
||||
bool shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap);
|
||||
void nurseryAllocate(Register result, Register temp, gc::AllocKind allocKind,
|
||||
size_t nDynamicSlots, gc::InitialHeap initialHeap, Label* fail);
|
||||
void nurseryAllocateObject(Register result, Register temp, gc::AllocKind allocKind,
|
||||
size_t nDynamicSlots, Label* fail);
|
||||
void freeListAllocate(Register result, Register temp, gc::AllocKind allocKind, Label* fail);
|
||||
void allocateObject(Register result, Register temp, gc::AllocKind allocKind,
|
||||
uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label* fail);
|
||||
void nurseryAllocateString(Register result, Register temp, gc::AllocKind allocKind,
|
||||
Label* fail);
|
||||
void allocateString(Register result, Register temp, gc::AllocKind allocKind,
|
||||
gc::InitialHeap initialHeap, Label* fail);
|
||||
void allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label* fail);
|
||||
void copySlotsFromTemplate(Register obj, const NativeObject* templateObj,
|
||||
uint32_t start, uint32_t end);
|
||||
|
|
@ -1779,8 +1789,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject);
|
||||
|
||||
void newGCString(Register result, Register temp, Label* fail);
|
||||
void newGCFatInlineString(Register result, Register temp, Label* fail);
|
||||
void newGCString(Register result, Register temp, Label* fail, bool attemptNursery);
|
||||
void newGCFatInlineString(Register result, Register temp, Label* fail, bool attemptNursery);
|
||||
|
||||
// Compares two strings for equality based on the JSOP.
|
||||
// This checks for identical pointers, atoms and length and fails for everything else.
|
||||
|
|
|
|||
|
|
@ -1161,7 +1161,8 @@ AssertValidObjectPtr(JSContext* cx, JSObject* obj)
|
|||
// Check what we can, so that we'll hopefully assert/crash if we get a
|
||||
// bogus object (pointer).
|
||||
MOZ_ASSERT(obj->compartment() == cx->compartment());
|
||||
MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
|
||||
MOZ_ASSERT(obj->zoneFromAnyThread() == cx->zone());
|
||||
MOZ_ASSERT(obj->runtimeFromActiveCooperatingThread() == cx->runtime());
|
||||
|
||||
MOZ_ASSERT_IF(!obj->hasLazyGroup() && obj->maybeShape(),
|
||||
obj->group()->clasp() == obj->maybeShape()->getObjectClass());
|
||||
|
|
@ -1170,7 +1171,6 @@ AssertValidObjectPtr(JSContext* cx, JSObject* obj)
|
|||
MOZ_ASSERT(obj->isAligned());
|
||||
gc::AllocKind kind = obj->asTenured().getAllocKind();
|
||||
MOZ_ASSERT(gc::IsObjectAllocKind(kind));
|
||||
MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6954,6 +6954,33 @@ class LPostWriteBarrierO : public LInstructionHelper<0, 2, 1>
|
|||
}
|
||||
};
|
||||
|
||||
// Generational write barrier used when writing a string to an object.
|
||||
class LPostWriteBarrierS : public LInstructionHelper<0, 2, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(PostWriteBarrierS)
|
||||
|
||||
LPostWriteBarrierS(const LAllocation& obj, const LAllocation& value,
|
||||
const LDefinition& temp) {
|
||||
setOperand(0, obj);
|
||||
setOperand(1, value);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const MPostWriteBarrier* mir() const {
|
||||
return mir_->toPostWriteBarrier();
|
||||
}
|
||||
const LAllocation* object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* value() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Generational write barrier used when writing a value to another object.
|
||||
class LPostWriteBarrierV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
|
||||
{
|
||||
|
|
@ -7016,6 +7043,42 @@ class LPostWriteElementBarrierO : public LInstructionHelper<0, 3, 1>
|
|||
}
|
||||
};
|
||||
|
||||
// Generational write barrier used when writing a string to an object's
|
||||
// elements.
|
||||
class LPostWriteElementBarrierS : public LInstructionHelper<0, 3, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(PostWriteElementBarrierS)
|
||||
|
||||
LPostWriteElementBarrierS(const LAllocation& obj, const LAllocation& value,
|
||||
const LAllocation& index, const LDefinition& temp) {
|
||||
setOperand(0, obj);
|
||||
setOperand(1, value);
|
||||
setOperand(2, index);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const MPostWriteElementBarrier* mir() const {
|
||||
return mir_->toPostWriteElementBarrier();
|
||||
}
|
||||
|
||||
const LAllocation* object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
const LAllocation* value() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Generational write barrier used when writing a value to another object's
|
||||
// elements.
|
||||
class LPostWriteElementBarrierV : public LInstructionHelper<0, 2 + BOX_PIECES, 1>
|
||||
|
|
|
|||
|
|
@ -223,8 +223,10 @@
|
|||
_(TypeBarrierO) \
|
||||
_(MonitorTypes) \
|
||||
_(PostWriteBarrierO) \
|
||||
_(PostWriteBarrierS) \
|
||||
_(PostWriteBarrierV) \
|
||||
_(PostWriteElementBarrierO) \
|
||||
_(PostWriteElementBarrierS) \
|
||||
_(PostWriteElementBarrierV) \
|
||||
_(InitializedLength) \
|
||||
_(SetInitializedLength) \
|
||||
|
|
|
|||
|
|
@ -558,6 +558,15 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
|||
// ===============================================================
|
||||
// Branch functions
|
||||
|
||||
void
|
||||
MacroAssembler::loadStoreBuffer(Register ptr, Register buffer)
|
||||
{
|
||||
if (ptr != buffer)
|
||||
movePtr(ptr, buffer);
|
||||
orPtr(Imm32(gc::ChunkMask), buffer);
|
||||
loadPtr(Address(buffer, gc::ChunkStoreBufferOffsetFromLastByte), buffer);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchPtrInNurseryChunk(Condition cond, Register ptr, Register temp, Label* label)
|
||||
{
|
||||
|
|
@ -573,24 +582,9 @@ MacroAssembler::branchPtrInNurseryChunk(Condition cond, Register ptr, Register t
|
|||
Imm32(int32_t(gc::ChunkLocation::Nursery)), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
branchValueIsNurseryObjectImpl(cond, address, temp, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
branchValueIsNurseryObjectImpl(cond, value, temp, label);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
MOZ_ASSERT(temp != InvalidReg);
|
||||
|
|
@ -606,6 +600,48 @@ MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, R
|
|||
bind(&done);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryCellImpl(Condition cond, const T& value, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
MOZ_ASSERT(temp != InvalidReg);
|
||||
Label done, checkAddress, checkObjectAddress;
|
||||
|
||||
Register tag = temp;
|
||||
splitTag(value, tag);
|
||||
branchTestObject(Assembler::Equal, tag, &checkObjectAddress);
|
||||
branchTestString(Assembler::NotEqual, tag, cond == Assembler::Equal ? &done : label);
|
||||
|
||||
unboxString(value, temp);
|
||||
jump(&checkAddress);
|
||||
|
||||
bind(&checkObjectAddress);
|
||||
unboxObject(value, temp);
|
||||
|
||||
bind(&checkAddress);
|
||||
orPtr(Imm32(gc::ChunkMask), temp);
|
||||
branch32(cond, Address(temp, gc::ChunkLocationOffsetFromLastByte),
|
||||
Imm32(int32_t(gc::ChunkLocation::Nursery)), label);
|
||||
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryCell(Condition cond, const Address& address, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
branchValueIsNurseryCellImpl(cond, address, temp, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchValueIsNurseryCell(Condition cond, ValueOperand value, Register temp,
|
||||
Label* label)
|
||||
{
|
||||
branchValueIsNurseryCellImpl(cond, value, temp, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs,
|
||||
const Value& rhs, Label* label)
|
||||
|
|
|
|||
|
|
@ -596,6 +596,17 @@ class JSString : public js::gc::Cell
|
|||
js::gc::TenuredCell::writeBarrierPre(&thing->asTenured());
|
||||
}
|
||||
|
||||
static void addCellAddressToStoreBuffer(js::gc::StoreBuffer* buffer, js::gc::Cell** cellp)
|
||||
{
|
||||
buffer->putCell(cellp);
|
||||
}
|
||||
|
||||
static void removeCellAddressFromStoreBuffer(js::gc::StoreBuffer* buffer, js::gc::Cell** cellp)
|
||||
{
|
||||
buffer->unputCell(cellp);
|
||||
}
|
||||
|
||||
|
||||
static void writeBarrierPost(void* cellp, JSString* prev, JSString* next) {
|
||||
// See JSObject::writeBarrierPost for a description of the logic here.
|
||||
MOZ_ASSERT(cellp);
|
||||
|
|
|
|||
|
|
@ -136,13 +136,23 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
|
|||
Label postBarrier;
|
||||
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||
const UnboxedLayout::Property& property = layout.properties()[i];
|
||||
if (!UnboxedTypeNeedsPostBarrier(property.type))
|
||||
continue;
|
||||
|
||||
Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
|
||||
if (property.type == JSVAL_TYPE_OBJECT) {
|
||||
Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
|
||||
Label notObject;
|
||||
masm.branchTestObject(Assembler::NotEqual, valueAddress, ¬Object);
|
||||
Register valueObject = masm.extractObject(valueAddress, scratch1);
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, &postBarrier);
|
||||
masm.bind(¬Object);
|
||||
} else {
|
||||
MOZ_ASSERT(property.type == JSVAL_TYPE_STRING);
|
||||
Label notString;
|
||||
masm.branchTestString(Assembler::NotEqual, valueAddress, ¬String);
|
||||
masm.unboxString(valueAddress, scratch1);
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, scratch1, scratch2, &postBarrier);
|
||||
masm.bind(¬String);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ UnboxedTypeNeedsPreBarrier(JSValueType type)
|
|||
static inline bool
|
||||
UnboxedTypeNeedsPostBarrier(JSValueType type)
|
||||
{
|
||||
return type == JSVAL_TYPE_OBJECT;
|
||||
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
// Class tracking information specific to unboxed objects.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue