mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Enable nursery strings fixes from 67. Still crashes.
Enable nursery strings fixes from 67. Still crashes.
This commit is contained in:
parent
58e3dd88fa
commit
6acf628a7b
13 changed files with 94 additions and 66 deletions
|
|
@ -1159,15 +1159,15 @@ NewRope(JSContext* cx, unsigned argc, Value* vp)
|
|||
heap = js::gc::TenuredHeap;
|
||||
}
|
||||
|
||||
JSString* left = args[0].toString();
|
||||
JSString* right = args[1].toString();
|
||||
RootedString left(cx, args[0].toString());
|
||||
RootedString right(cx, args[1].toString());
|
||||
size_t length = JS_GetStringLength(left) + JS_GetStringLength(right);
|
||||
if (length > JSString::MAX_LENGTH) {
|
||||
JS_ReportErrorASCII(cx, "rope length exceeds maximum string length");
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<JSRope*> str(cx, JSRope::new_<NoGC>(cx, left, right, length, heap));
|
||||
Rooted<JSRope*> str(cx, JSRope::new_<CanGC>(cx, left, right, length, heap));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -147,8 +147,9 @@ GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind)
|
|||
if (allowGC && !cx->suppressGC) {
|
||||
cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
|
||||
|
||||
// Exceeding gcMaxBytes while tenuring can disable the Nursery.
|
||||
if (cx->nursery().isEnabled())
|
||||
// Exceeding gcMaxBytes while tenuring can disable the Nursery, and
|
||||
// other heuristics can disable nursery strings for this zone.
|
||||
if (cx->nursery().isEnabled() && cx->zone()->allocNurseryStrings)
|
||||
return static_cast<JSString*>(cx->nursery().allocateString(cx, cx->zone(), thingSize, kind));
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -2053,7 +2053,6 @@ inline JSRope*
|
|||
MarkStack::TaggedPtr::asTempRope() const
|
||||
{
|
||||
MOZ_ASSERT(tag() == TempRopeTag);
|
||||
MOZ_ASSERT(ptr()->isTenured());
|
||||
MOZ_ASSERT(ptr()->is<JSString>());
|
||||
return static_cast<JSRope*>(ptr());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -683,8 +683,10 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
|
|||
|
||||
TenureCountCache tenureCounts;
|
||||
previousGC.reason = JS::gcreason::NO_REASON;
|
||||
mozilla::Maybe<AutoTraceSession> session;
|
||||
if (!isEmpty()) {
|
||||
doCollection(reason, tenureCounts);
|
||||
session.emplace(rt, JS::HeapState::MinorCollecting);
|
||||
doCollection(reason, session.ref(), tenureCounts);
|
||||
} else {
|
||||
previousGC.nurseryUsedBytes = 0;
|
||||
previousGC.nurseryCapacity = spaceToEnd(maxChunkCount());
|
||||
|
|
@ -721,6 +723,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
|
|||
}
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
|
||||
MOZ_ASSERT(session.isSome(), "discarding JIT code must be in an AutoTraceSession");
|
||||
JSRuntime::AutoProhibitActiveContextChange apacc(rt);
|
||||
CancelOffThreadIonCompile(zone);
|
||||
bool preserving = zone->isPreservingCode();
|
||||
|
|
@ -730,7 +733,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
|
|||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
||||
if (jit::JitCompartment* jitComp = c->jitCompartment()) {
|
||||
jitComp->discardStubs();
|
||||
jitComp->stringsCanBeInNursery = false;
|
||||
jitComp->setStringsCanBeInNursery(false);
|
||||
}
|
||||
}
|
||||
zone->allocNurseryStrings = false;
|
||||
|
|
@ -751,6 +754,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
|
|||
disable();
|
||||
|
||||
endProfile(ProfileKey::Total);
|
||||
session.reset(); // End the minor GC session, if running one.
|
||||
minorGcCount_++;
|
||||
|
||||
int64_t totalTime = profileTimes_[ProfileKey::Total];
|
||||
|
|
@ -785,9 +789,10 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason)
|
|||
|
||||
void
|
||||
js::Nursery::doCollection(JS::gcreason::Reason reason,
|
||||
AutoTraceSession& session,
|
||||
TenureCountCache& tenureCounts)
|
||||
{
|
||||
AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
|
||||
JSRuntime* rt = runtime();
|
||||
AutoSetThreadIsPerformingGC performingGC;
|
||||
AutoDisableProxyCheck disableStrictProxyChecking(rt);
|
||||
mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class HeapSlot;
|
|||
|
||||
namespace gc {
|
||||
class AutoMaybeStartBackgroundAllocation;
|
||||
class AutoTraceSession;
|
||||
struct Cell;
|
||||
class MinorCollectionTracer;
|
||||
class RelocationOverlay;
|
||||
|
|
@ -509,6 +510,7 @@ class Nursery
|
|||
void* allocate(size_t size);
|
||||
|
||||
void doCollection(JS::gcreason::Reason reason,
|
||||
gc::AutoTraceSession& sesssion,
|
||||
gc::TenureCountCache& tenureCounts);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1079,14 +1079,8 @@ EmitPostWriteBarrierS(MacroAssembler& masm,
|
|||
masm.bind(&exit);
|
||||
}
|
||||
|
||||
enum class FieldToBarrier {
|
||||
REGEXP_PENDING_INPUT,
|
||||
REGEXP_MATCHES_INPUT,
|
||||
DEPENDENT_STRING_BASE
|
||||
};
|
||||
|
||||
static void
|
||||
EmitStoreBufferMutation(MacroAssembler& masm, Register holder, FieldToBarrier field,
|
||||
EmitStoreBufferMutation(MacroAssembler& masm, Register holder, size_t offset,
|
||||
Register buffer,
|
||||
LiveGeneralRegisterSet& liveVolatiles,
|
||||
void (*fun)(js::gc::StoreBuffer*, js::gc::Cell**))
|
||||
|
|
@ -1105,19 +1099,7 @@ EmitStoreBufferMutation(MacroAssembler& masm, Register holder, FieldToBarrier fi
|
|||
regs.takeUnchecked(holder);
|
||||
Register addrReg = regs.takeAny();
|
||||
|
||||
switch (field) {
|
||||
case FieldToBarrier::REGEXP_PENDING_INPUT:
|
||||
masm.computeEffectiveAddress(Address(holder, RegExpStatics::offsetOfPendingInput()), addrReg);
|
||||
break;
|
||||
|
||||
case FieldToBarrier::REGEXP_MATCHES_INPUT:
|
||||
masm.computeEffectiveAddress(Address(holder, RegExpStatics::offsetOfMatchesInput()), addrReg);
|
||||
break;
|
||||
|
||||
case FieldToBarrier::DEPENDENT_STRING_BASE:
|
||||
masm.leaNewDependentStringBase(holder, addrReg);
|
||||
break;
|
||||
}
|
||||
masm.computeEffectiveAddress(Address(holder, offset), addrReg);
|
||||
|
||||
bool needExtraReg = !regs.empty();
|
||||
if (needExtraReg) {
|
||||
|
|
@ -1140,7 +1122,7 @@ EmitStoreBufferMutation(MacroAssembler& masm, Register holder, FieldToBarrier fi
|
|||
// Warning: this function modifies prev and next.
|
||||
static void
|
||||
EmitPostWriteBarrierS(MacroAssembler& masm,
|
||||
Register string, FieldToBarrier field,
|
||||
Register holder, size_t offset,
|
||||
Register prev, Register next,
|
||||
LiveGeneralRegisterSet& liveVolatiles)
|
||||
{
|
||||
|
|
@ -1160,7 +1142,7 @@ EmitPostWriteBarrierS(MacroAssembler& masm,
|
|||
|
||||
// buffer->putCell(cellp)
|
||||
masm.bind(&putCell);
|
||||
EmitStoreBufferMutation(masm, string, field, storebuffer, liveVolatiles,
|
||||
EmitStoreBufferMutation(masm, holder, offset, storebuffer, liveVolatiles,
|
||||
JSString::addCellAddressToStoreBuffer);
|
||||
masm.jump(&exit);
|
||||
|
||||
|
|
@ -1169,7 +1151,7 @@ EmitPostWriteBarrierS(MacroAssembler& masm,
|
|||
masm.branchPtr(Assembler::Equal, prev, ImmWord(0), &exit);
|
||||
masm.loadStoreBuffer(prev, storebuffer);
|
||||
masm.branchPtr(Assembler::Equal, storebuffer, ImmWord(0), &exit);
|
||||
EmitStoreBufferMutation(masm, string, field, storebuffer, liveVolatiles,
|
||||
EmitStoreBufferMutation(masm, holder, offset, storebuffer, liveVolatiles,
|
||||
JSString::removeCellAddressFromStoreBuffer);
|
||||
|
||||
masm.bind(&exit);
|
||||
|
|
@ -1216,6 +1198,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re
|
|||
Register temp1, Register temp2, Register temp3,
|
||||
size_t inputOutputDataStartOffset,
|
||||
RegExpShared::CompilationMode mode,
|
||||
bool stringsCanBeInNursery,
|
||||
Label* notFound, Label* failure)
|
||||
{
|
||||
size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
|
||||
|
|
@ -1393,22 +1376,26 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re
|
|||
masm.patchableCallPreBarrier(matchesInputAddress, MIRType::String);
|
||||
masm.patchableCallPreBarrier(lazySourceAddress, MIRType::String);
|
||||
|
||||
if (stringsCanBeInNursery) {
|
||||
// Writing into RegExpStatics tenured memory; must post-barrier.
|
||||
if (temp1.volatile_())
|
||||
volatileRegs.add(temp1);
|
||||
|
||||
if (temp1.volatile_())
|
||||
volatileRegs.add(temp1);
|
||||
masm.loadPtr(pendingInputAddress, temp2);
|
||||
masm.storePtr(input, pendingInputAddress);
|
||||
masm.movePtr(input, temp3);
|
||||
EmitPostWriteBarrierS(masm, temp1, RegExpStatics::offsetOfPendingInput(),
|
||||
temp2 /* prev */, temp3 /* next */, volatileRegs);
|
||||
|
||||
// Writing into RegExpStatics tenured memory; must post-barrier.
|
||||
masm.loadPtr(pendingInputAddress, temp2);
|
||||
masm.storePtr(input, pendingInputAddress);
|
||||
masm.movePtr(input, temp3);
|
||||
EmitPostWriteBarrierS(masm, temp1, FieldToBarrier::REGEXP_PENDING_INPUT,
|
||||
temp2 /* prev */, temp3 /* next */, volatileRegs);
|
||||
|
||||
masm.loadPtr(matchesInputAddress, temp2);
|
||||
masm.storePtr(input, matchesInputAddress);
|
||||
masm.movePtr(input, temp3);
|
||||
EmitPostWriteBarrierS(masm, temp1, FieldToBarrier::REGEXP_MATCHES_INPUT,
|
||||
temp2 /* prev */, temp3 /* next */, volatileRegs);
|
||||
masm.loadPtr(matchesInputAddress, temp2);
|
||||
masm.storePtr(input, matchesInputAddress);
|
||||
masm.movePtr(input, temp3);
|
||||
EmitPostWriteBarrierS(masm, temp1, RegExpStatics::offsetOfMatchesInput(),
|
||||
temp2 /* prev */, temp3 /* next */, volatileRegs);
|
||||
} else {
|
||||
masm.storePtr(input, pendingInputAddress);
|
||||
masm.storePtr(input, matchesInputAddress);
|
||||
}
|
||||
|
||||
masm.storePtr(lastIndex, Address(temp1, RegExpStatics::offsetOfLazyIndex()));
|
||||
masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
|
||||
|
|
@ -1449,6 +1436,7 @@ public:
|
|||
// Caller should call generateFallback after masm.ret(), to generate
|
||||
// fallback path.
|
||||
void generate(MacroAssembler& masm, const JSAtomState& names,
|
||||
CompileRuntime* runtime,
|
||||
bool latin1, Register string,
|
||||
Register base, Register temp1, Register temp2,
|
||||
BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
|
||||
|
|
@ -1461,6 +1449,7 @@ public:
|
|||
|
||||
void
|
||||
CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
|
||||
CompileRuntime* runtime,
|
||||
bool latin1, Register string,
|
||||
Register base, Register temp1, Register temp2,
|
||||
BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
|
||||
|
|
@ -1715,7 +1704,7 @@ JitCompartment::generateRegExpMatcherStub(JSContext* cx)
|
|||
Label notFound, oolEntry;
|
||||
if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
|
||||
temp1, temp2, temp5, inputOutputDataStartOffset,
|
||||
RegExpShared::Normal, ¬Found, &oolEntry))
|
||||
RegExpShared::Normal, stringsCanBeInNursery, ¬Found, &oolEntry))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1813,7 +1802,9 @@ JitCompartment::generateRegExpMatcherStub(JSContext* cx)
|
|||
Label isUndefined, storeDone;
|
||||
masm.branch32(Assembler::LessThan, stringIndexAddress, Imm32(0), &isUndefined);
|
||||
|
||||
depStr[isLatin].generate(masm, cx->names(), isLatin, temp3, input, temp4, temp5,
|
||||
depStr[isLatin].generate(masm, cx->names(),
|
||||
CompileRuntime::get(cx->runtime()),
|
||||
isLatin, temp3, input, temp4, temp5,
|
||||
stringIndexAddress, stringLimitAddress, stringsCanBeInNursery, failure);
|
||||
|
||||
masm.storeValue(JSVAL_TYPE_STRING, temp3, stringAddress);
|
||||
|
|
@ -2030,7 +2021,8 @@ JitCompartment::generateRegExpSearcherStub(JSContext* cx)
|
|||
Label notFound, oolEntry;
|
||||
if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
|
||||
temp1, temp2, temp3, inputOutputDataStartOffset,
|
||||
RegExpShared::Normal, ¬Found, &oolEntry))
|
||||
RegExpShared::Normal, stringsCanBeInNursery,
|
||||
¬Found, &oolEntry))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -2181,7 +2173,8 @@ JitCompartment::generateRegExpTesterStub(JSContext* cx)
|
|||
Label notFound, oolEntry;
|
||||
if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
|
||||
temp1, temp2, temp3, 0,
|
||||
RegExpShared::MatchOnly, ¬Found, &oolEntry))
|
||||
RegExpShared::MatchOnly, stringsCanBeInNursery,
|
||||
¬Found, &oolEntry))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -3768,11 +3761,13 @@ EmitPostWriteBarrier(MacroAssembler& masm, Register objreg, JSObject* maybeConst
|
|||
Register runtimereg = regs.takeAny();
|
||||
masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
|
||||
|
||||
void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
|
||||
masm.setupUnalignedABICall(regs.takeAny());
|
||||
masm.passABIArg(runtimereg);
|
||||
masm.passABIArg(objreg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
|
||||
if (isGlobal)
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostGlobalWriteBarrier));
|
||||
else
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
|
||||
|
||||
masm.bind(&exit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ JitCompartment::~JitCompartment()
|
|||
}
|
||||
|
||||
bool
|
||||
JitCompartment::initialize(JSContext* cx)
|
||||
JitCompartment::initialize(JSContext* cx, bool zoneHasNurseryStrings)
|
||||
{
|
||||
stubCodes_ = cx->new_<ICStubCodeMap>(cx->runtime());
|
||||
if (!stubCodes_)
|
||||
|
|
@ -450,7 +450,7 @@ JitCompartment::initialize(JSContext* cx)
|
|||
return false;
|
||||
}
|
||||
|
||||
stringsCanBeInNursery = cx->nursery().canAllocateStrings();
|
||||
setStringsCanBeInNursery(zoneHasNurseryStrings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -552,6 +552,8 @@ class JitCompartment
|
|||
JitCode* regExpSearcherStub_;
|
||||
JitCode* regExpTesterStub_;
|
||||
|
||||
bool stringsCanBeInNursery;
|
||||
|
||||
JitCode* generateStringConcatStub(JSContext* cx);
|
||||
JitCode* generateRegExpMatcherStub(JSContext* cx);
|
||||
JitCode* generateRegExpSearcherStub(JSContext* cx);
|
||||
|
|
@ -619,7 +621,7 @@ class JitCompartment
|
|||
JitCompartment();
|
||||
~JitCompartment();
|
||||
|
||||
MOZ_MUST_USE bool initialize(JSContext* cx);
|
||||
[[nodiscard]] bool initialize(JSContext* cx, bool zoneHasNurseryStrings);
|
||||
|
||||
// Initialize code stubs only used by Ion, not Baseline.
|
||||
MOZ_MUST_USE bool ensureIonStubsExist(JSContext* cx);
|
||||
|
|
@ -638,6 +640,24 @@ class JitCompartment
|
|||
regExpTesterStub_ = nullptr;
|
||||
}
|
||||
|
||||
bool hasStubs() const {
|
||||
// Check each stub individually
|
||||
if (stringConcatStub_)
|
||||
return true;
|
||||
if (regExpMatcherStub_)
|
||||
return true;
|
||||
if (regExpSearcherStub_)
|
||||
return true;
|
||||
if (regExpTesterStub_)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void setStringsCanBeInNursery(bool allow) {
|
||||
MOZ_ASSERT(!hasStubs());
|
||||
stringsCanBeInNursery = allow;
|
||||
}
|
||||
|
||||
JitCode* regExpMatcherStubNoBarrier() const {
|
||||
return regExpMatcherStub_;
|
||||
}
|
||||
|
|
@ -672,8 +692,6 @@ class JitCompartment
|
|||
}
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
bool stringsCanBeInNursery;
|
||||
};
|
||||
|
||||
// Called from JSCompartment::discardJitCode().
|
||||
|
|
|
|||
|
|
@ -596,10 +596,11 @@ GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
|
|||
}
|
||||
|
||||
void
|
||||
PostWriteBarrier(JSRuntime* rt, JSObject* obj)
|
||||
PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell)
|
||||
{
|
||||
MOZ_ASSERT(!IsInsideNursery(obj));
|
||||
rt->gc.storeBuffer.putWholeCell(obj);
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(!IsInsideNursery(cell));
|
||||
rt->gc.storeBuffer().putWholeCell(cell);
|
||||
}
|
||||
|
||||
static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ class InlineTypedObject;
|
|||
class GeneratorObject;
|
||||
class TypedArrayObject;
|
||||
|
||||
namespace gc {
|
||||
|
||||
struct Cell;
|
||||
|
||||
}
|
||||
|
||||
namespace jit {
|
||||
|
||||
enum DataType {
|
||||
|
|
@ -653,8 +659,7 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa
|
|||
|
||||
void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
|
||||
|
||||
void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index);
|
||||
void PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell);
|
||||
void PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj);
|
||||
|
||||
uint32_t GetIndexFromString(JSString* str);
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ JSCompartment::ensureJitCompartmentExists(JSContext* cx)
|
|||
if (!jitCompartment_)
|
||||
return false;
|
||||
|
||||
if (!jitCompartment_->initialize(cx)) {
|
||||
if (!jitCompartment_->initialize(cx, zone()->allocNurseryStrings)) {
|
||||
js_delete(jitCompartment_);
|
||||
jitCompartment_ = nullptr;
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ CompiledScriptMatches(CompilationSelector selector, JSScript* target)
|
|||
|
||||
bool match(JSScript* script) { return script == builder_->script(); }
|
||||
bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); }
|
||||
bool match(Zone* zone) { return zone == builder_->script()->zone(); }
|
||||
bool match(Zone* zone) { return zone == builder_->script()->zoneFromAnyThread(); }
|
||||
bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); }
|
||||
bool match(AllCompilations all) { return true; }
|
||||
bool match(ZonesInState zbs) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "gc/GCInternals.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Nursery.h"
|
||||
#include "js/UbiNode.h"
|
||||
|
|
@ -198,6 +199,7 @@ JSString::dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) c
|
|||
if (flags & HAS_BASE_BIT) fputs(" HAS_BASE", fp);
|
||||
if (flags & INLINE_CHARS_BIT) fputs(" INLINE_CHARS", fp);
|
||||
if (flags & NON_ATOM_BIT) fputs(" NON_ATOM", fp);
|
||||
else fputs(" (ATOM)", fp);
|
||||
if (isPermanentAtom()) fputs(" PERMANENT", fp);
|
||||
if (flags & LATIN1_CHARS_BIT) fputs(" LATIN1", fp);
|
||||
if (!isTenured()) fputs(" NURSERY", fp);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue