diff --git a/js/src/devtools/rootAnalysis/loadCallgraph.js b/js/src/devtools/rootAnalysis/loadCallgraph.js index 9ee8d76281..9723be5fc7 100644 --- a/js/src/devtools/rootAnalysis/loadCallgraph.js +++ b/js/src/devtools/rootAnalysis/loadCallgraph.js @@ -132,6 +132,12 @@ function loadCallgraph(file) addGCFunction(func, "annotation"); } + // mess up the id <-> name correspondence. Also, we need to know if the + // functions even exist in the first place.) + for (var func of extraGCFunctions()) { + addGCFunction(func, "annotation"); + } + // Initialize suppressedFunctions to the set of all functions, and the // worklist to all toplevel callers. var worklist = []; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 6382c220ac..a1ab09f019 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -1020,7 +1020,7 @@ class MOZ_STACK_CLASS TokenStream return true; } - void skipChars(uint8_t n) { + void skipChars(uint32_t n) { while (n-- > 0) { MOZ_ASSERT(userbuf.hasRawChars()); mozilla::DebugOnly c = getCharIgnoreEOL(); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 282cdeaf9b..7673af7d5d 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -35,6 +35,7 @@ #include "jit/MacroAssembler-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" +#include "vm/TypeInference-inl.h" using namespace js; using namespace js::jit; @@ -97,7 +98,8 @@ BaselineCompiler::compile() AutoTraceLog logScript(logger, scriptEvent); AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation); - if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx)) + AutoKeepTypeScripts keepTypes(cx); + if (!script->ensureHasTypes(cx, keepTypes) || !script->ensureHasAnalyzedArgsUsage(cx)) return Method_Error; // When code coverage is only enabled for optimizations, or when a Debugger diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index aeb182c8e0..6614fb6709 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -16,6 +16,7 @@ #include "jit/JitFrames-inl.h" #include "jit/MacroAssembler-inl.h" #include "vm/Stack-inl.h" +#include "vm/TypeInference-inl.h" using namespace js; using namespace js::jit; @@ -670,6 +671,7 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script, JitSpew(JitSpew_BaselineDebugModeOSR, "Recompiling (%s:%" PRIuSIZE ") for %s", script->filename(), script->lineno(), observing ? "DEBUGGING" : "NORMAL EXECUTION"); + AutoKeepTypeScripts keepTypes(cx); script->setBaselineScript(cx->runtime(), nullptr); MethodStatus status = BaselineCompile(cx, script, /* forceDebugMode = */ observing); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 0e511e07d0..004cf10775 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4180,7 +4180,8 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg) if (script->length() > MAX_SCRIPT_SIZE) return true; - if (!script->ensureHasTypes(cx)) + AutoKeepTypeScripts keepTypes(cx); + if (!script->ensureHasTypes(cx, keepTypes)) return false; TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index 15cf7c6b0f..9a5ced2dbd 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -1226,9 +1226,9 @@ IonCacheIRCompiler::emitCallStringSplitResult() static bool GroupHasPropertyTypes(ObjectGroup* group, jsid* id, Value* v) { - if (group->unknownProperties()) + if (group->unknownPropertiesDontCheckGeneration()) return true; - HeapTypeSet* propTypes = group->maybeGetProperty(*id); + HeapTypeSet* propTypes = group->maybeGetPropertyDontCheckGeneration(*id); if (!propTypes) return true; if (!propTypes->nonConstantProperty()) diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 68e4eb30e4..812c9792a1 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -544,7 +544,8 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa RootedFunction fun(cx, &callee->as()); if (fun->isInterpreted() && fun->isConstructor()) { JSScript* script = JSFunction::getOrCreateScript(cx, fun); - if (!script || !script->ensureHasTypes(cx)) + AutoKeepTypeScripts keepTypes(cx); + if (!script || !script->ensureHasTypes(cx, keepTypes)) return false; if (fun->isBoundFunction() || script->isDerivedClassConstructor()) { rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL)); diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index c7e9d86576..a61634bc2f 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -863,7 +863,7 @@ template static void TraceOneDataRelocation(JSTracer* trc, Iter* iter) { - Instruction* ins = iter->cur(); + Iter iterCopy(*iter); Register dest; Assembler::RelocStyle rs; const void* prior = Assembler::GetPtr32Target(iter, &dest, &rs); @@ -874,12 +874,12 @@ TraceOneDataRelocation(JSTracer* trc, Iter* iter) "ion-masm-ptr"); if (ptr != prior) { - MacroAssemblerARM::ma_mov_patch(Imm32(int32_t(ptr)), dest, Assembler::Always, rs, ins); + MacroAssemblerARM::ma_mov_patch(Imm32(int32_t(ptr)), dest, Assembler::Always, rs, iterCopy); // L_LDR won't cause any instructions to be updated. if (rs != Assembler::L_LDR) { - AutoFlushICache::flush(uintptr_t(ins), 4); - AutoFlushICache::flush(uintptr_t(ins->next()), 4); + AutoFlushICache::flush(uintptr_t(iter->cur()), 4); + AutoFlushICache::flush(uintptr_t(iter->next()), 4); } } } @@ -899,7 +899,7 @@ TraceDataRelocations(JSTracer* trc, ARMBuffer* buffer, CompactBufferReader& read { while (reader.more()) { BufferOffset offset(reader.readUnsigned()); - ARMBuffer::AssemblerBufferInstIterator iter(offset, buffer); + BufferInstructionIterator iter(offset, buffer); TraceOneDataRelocation(trc, &iter); } } @@ -3161,14 +3161,15 @@ Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newVal PatchedImmPtr expectedValue) { Instruction* ptr = reinterpret_cast(label.raw()); - InstructionIterator iter(ptr); Register dest; Assembler::RelocStyle rs; + InstructionIterator iter(ptr); DebugOnly val = GetPtr32Target(&iter, &dest, &rs); MOZ_ASSERT(uint32_t((const uint32_t*)val) == uint32_t(expectedValue.value)); - MacroAssembler::ma_mov_patch(Imm32(int32_t(newValue.value)), dest, Always, rs, ptr); + iter = InstructionIterator(ptr); + MacroAssembler::ma_mov_patch(Imm32(int32_t(newValue.value)), dest, Always, rs, iter); // L_LDR won't cause any instructions to be updated. if (rs != L_LDR) { @@ -3221,6 +3222,20 @@ InstIsGuard(Instruction* inst, const PoolHeader** ph) return *ph != nullptr; } +static bool +InstIsGuard(BufferInstructionIterator& iter, const PoolHeader** ph) +{ + Instruction* inst = iter.cur(); + Assembler::Condition c = inst->extractCond(); + if (c != Assembler::Always) + return false; + if (!(inst->is() || inst->is())) + return false; + // See if the next instruction is a pool header. + *ph = iter.peek()->as(); + return *ph != nullptr; +} + static bool InstIsBNop(Instruction* inst) { @@ -3266,6 +3281,28 @@ Instruction::skipPool() return this; } +void +BufferInstructionIterator::skipPool() +{ + // If this is a guard, and the next instruction is a header, always work + // around the pool. If it isn't a guard, then start looking ahead. + + const PoolHeader* ph; + if (InstIsGuard(*this, &ph)) { + // Don't skip a natural guard. + if (ph->isNatural()) + return; + advance(sizeof(Instruction) * (1 + ph->size())); + skipPool(); + return; + } + + if (InstIsBNop(cur())) { + next(); + skipPool(); + } +} + // Cases to be handled: // 1) no pools or branches in sight => return this+1 // 2) branch to next instruction => return this+2, because a nop needed to be inserted into the stream. @@ -3409,13 +3446,6 @@ Assembler::BailoutTableStart(uint8_t* code) return (uint8_t*) inst; } -InstructionIterator::InstructionIterator(Instruction* i_) - : i(i_) -{ - // Work around pools with an artificial pool guard and around nop-fill. - i = i->skipPool(); -} - uint32_t Assembler::NopFill = 0; uint32_t diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 98d26131c9..04e5e1f129 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -2246,20 +2246,35 @@ class InstMOV : public InstALU class InstructionIterator { private: - Instruction* i; + Instruction* inst_; public: - explicit InstructionIterator(Instruction* i_); + explicit InstructionIterator(Instruction* inst) : inst_(inst) { + skipPool(); + } + void skipPool() { + inst_ = inst_->skipPool(); + } Instruction* next() { - i = i->next(); + inst_ = inst_->next(); return cur(); } Instruction* cur() const { - return i; + return inst_; } }; +class BufferInstructionIterator : public ARMBuffer::AssemblerBufferInstIterator +{ + public: + BufferInstructionIterator(BufferOffset bo, ARMBuffer* buffer) + : ARMBuffer::AssemblerBufferInstIterator(bo, buffer) + {} + void skipPool(); +}; + + static const uint32_t NumIntArgRegs = 4; // There are 16 *float* registers available for arguments diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 3fc07e0de5..33fcb01392 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -308,6 +308,25 @@ MacroAssembler::add64(Imm64 imm, Register64 dest) ma_adc(imm.hi(), dest.high, scratch, LeaveCC); } +CodeOffset +MacroAssembler::add32ToPtrWithPatch(Register src, Register dest) +{ + ScratchRegisterScope scratch(*this); + CodeOffset offs = CodeOffset(currentOffset()); + ma_movPatchable(Imm32(0), scratch, Always); + ma_add(src, scratch, dest); + return offs; +} + +void +MacroAssembler::patchAdd32ToPtr(CodeOffset offset, Imm32 imm) +{ + ScratchRegisterScope scratch(*this); + BufferInstructionIterator iter(BufferOffset(offset.offset()), &m_buffer); + iter.maybeSkipAutomaticInstructions(); + ma_mov_patch(imm, scratch, Always, HasMOVWT() ? L_MOVWT : L_LDR, iter); +} + void MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 7b91f6527f..3741b273c6 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -345,35 +345,36 @@ MacroAssemblerARM::ma_movPatchable(ImmPtr imm, Register dest, Assembler::Conditi ma_movPatchable(Imm32(int32_t(imm.value)), dest, c); } -/* static */ void -MacroAssemblerARM::ma_mov_patch(Imm32 imm_, Register dest, Assembler::Condition c, - RelocStyle rs, Instruction* i) +/* static */ +template +void +MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest, Assembler::Condition c, + RelocStyle rs, Iter iter) { - MOZ_ASSERT(i); - int32_t imm = imm_.value; + MOZ_ASSERT(iter.cur()); // Make sure the current instruction is not an artificial guard inserted // by the assembler buffer. - i = i->skipPool(); + iter.skipPool(); + + int32_t imm = imm32.value; switch(rs) { case L_MOVWT: - Assembler::as_movw_patch(dest, Imm16(imm & 0xffff), c, i); - i = i->next(); - Assembler::as_movt_patch(dest, Imm16(imm >> 16 & 0xffff), c, i); + Assembler::as_movw_patch(dest, Imm16(imm & 0xffff), c, iter.cur()); + Assembler::as_movt_patch(dest, Imm16(imm >> 16 & 0xffff), c, iter.next()); break; case L_LDR: - Assembler::WritePoolEntry(i, c, imm); + Assembler::WritePoolEntry(iter.cur(), c, imm); break; } } - -/* static */ void -MacroAssemblerARM::ma_mov_patch(ImmPtr imm, Register dest, Assembler::Condition c, - RelocStyle rs, Instruction* i) -{ - ma_mov_patch(Imm32(int32_t(imm.value)), dest, c, rs, i); -} +template void +MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest, Assembler::Condition c, + RelocStyle rs, InstructionIterator iter); +template void +MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest, Assembler::Condition c, + RelocStyle rs, BufferInstructionIterator iter); void MacroAssemblerARM::ma_mov(Register src, Register dest, SBit s, Assembler::Condition c) diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 218939c2a4..99640e445b 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -124,10 +124,10 @@ class MacroAssemblerARM : public Assembler void ma_movPatchable(Imm32 imm, Register dest, Assembler::Condition c); void ma_movPatchable(ImmPtr imm, Register dest, Assembler::Condition c); + // To be used with Iter := InstructionIterator or BufferInstructionIterator. + template static void ma_mov_patch(Imm32 imm, Register dest, Assembler::Condition c, - RelocStyle rs, Instruction* i); - static void ma_mov_patch(ImmPtr imm, Register dest, Assembler::Condition c, - RelocStyle rs, Instruction* i); + RelocStyle rs, Iter iter); // ALU based ops // mov diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index b6af126bc8..4365561fbf 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -141,7 +141,6 @@ class AssemblerBuffer { protected: typedef BufferSlice Slice; - typedef AssemblerBuffer AssemblerBuffer_; // Doubly-linked list of BufferSlices, with the most recent in tail position. Slice* head; @@ -388,24 +387,32 @@ class AssemblerBuffer return BufferOffset(bufferSize); } + typedef AssemblerBuffer ThisClass; + class AssemblerBufferInstIterator { - BufferOffset bo; - AssemblerBuffer_* m_buffer; + BufferOffset bo_; + ThisClass* buffer_; public: - explicit AssemblerBufferInstIterator(BufferOffset off, AssemblerBuffer_* buffer) - : bo(off), m_buffer(buffer) + explicit AssemblerBufferInstIterator(BufferOffset bo, ThisClass* buffer) + : bo_(bo), buffer_(buffer) { } + void advance(int offset) { + bo_ = BufferOffset(bo_.getOffset() + offset); + } + Inst* next() { - Inst* i = m_buffer->getInst(bo); - bo = BufferOffset(bo.getOffset() + i->size()); + advance(cur()->size()); return cur(); } - Inst* cur() { - return m_buffer->getInst(bo); + Inst* peek() { + return buffer_->getInst(BufferOffset(bo_.getOffset() + cur()->size())); + } + Inst* cur() const { + return buffer_->getInst(bo_); } }; }; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 9cfebe68cb..2d761d0e88 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1689,7 +1689,7 @@ class JSScript : public js::gc::TenuredCell bool isTopLevel() { return code() && !functionNonDelazifying(); } /* Ensure the script has a TypeScript. */ - inline bool ensureHasTypes(JSContext* cx); + inline bool ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&); inline js::TypeScript* types(); diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 5ea7971e0e..0ec095b70a 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -28,6 +28,7 @@ #include "jsscriptinlines.h" #include "vm/Stack-inl.h" +#include "vm/TypeInference-inl.h" using namespace js; using namespace js::gc; @@ -1466,7 +1467,8 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler CallObject& callobj = env->as(); RootedFunction fun(cx, &callobj.callee()); RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); - if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx)) + AutoKeepTypeScripts keepTypes(cx); + if (!script->ensureHasTypes(cx, keepTypes) || !script->ensureHasAnalyzedArgsUsage(cx)) return false; BindingIter bi(script); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 298178f020..fd273af0f4 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -383,7 +383,8 @@ class ObjectGroup : public gc::TenuredCell inline HeapTypeSet* getProperty(ExclusiveContext* cx, JSObject* obj, jsid id); /* Get a property only if it already exists. */ - inline HeapTypeSet* maybeGetProperty(jsid id); + MOZ_ALWAYS_INLINE HeapTypeSet* maybeGetProperty(jsid id); + MOZ_ALWAYS_INLINE HeapTypeSet* maybeGetPropertyDontCheckGeneration(jsid id); /* * Iterate through the group's properties. getPropertyCount overapproximates @@ -461,6 +462,7 @@ class ObjectGroup : public gc::TenuredCell } inline uint32_t basePropertyCount(); + inline uint32_t basePropertyCountDontCheckGeneration(); private: inline void setBasePropertyCount(uint32_t count); diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index 8c9b179223..ba5004a282 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -367,10 +367,10 @@ TypeMonitorCall(JSContext* cx, const js::CallArgs& args, bool constructing) inline bool TrackPropertyTypes(ExclusiveContext* cx, JSObject* obj, jsid id) { - if (obj->hasLazyGroup() || obj->group()->unknownProperties()) + if (obj->hasLazyGroup() || obj->group()->unknownPropertiesDontCheckGeneration()) return false; - if (obj->isSingleton() && !obj->group()->maybeGetProperty(id)) + if (obj->isSingleton() && !obj->group()->maybeGetPropertyDontCheckGeneration(id)) return false; return true; @@ -405,7 +405,15 @@ PropertyHasBeenMarkedNonConstant(JSObject* obj, jsid id) inline bool HasTypePropertyId(JSObject* obj, jsid id, TypeSet::Type type) { - if (obj->hasLazyGroup()) + MOZ_ASSERT(id == IdToTypeId(id)); + MOZ_ASSERT(TrackPropertyTypes(obj, id)); + + if (HeapTypeSet* types = obj->group()->maybeGetPropertyDontCheckGeneration(id)) { + if (!types->hasType(type)) + return false; + // Non-constant properties are only relevant for singleton objects. + if (obj->isSingleton() && !types->nonConstantProperty()) + return false; return true; if (obj->group()->unknownProperties()) @@ -657,6 +665,21 @@ TypeScript::SetArgument(JSContext* cx, JSScript* script, unsigned arg, const js: SetArgument(cx, script, arg, TypeSet::GetValueType(value)); } +inline +AutoKeepTypeScripts::AutoKeepTypeScripts(JSContext* cx) + : zone_(cx->zone()->types), + prev_(zone_.keepTypeScripts) +{ + zone_.keepTypeScripts = true; +} + +inline +AutoKeepTypeScripts::~AutoKeepTypeScripts() +{ + MOZ_ASSERT(zone_.keepTypeScripts); + zone_.keepTypeScripts = prev_; +} + ///////////////////////////////////////////////////////////////////// // TypeHashSet ///////////////////////////////////////////////////////////////////// @@ -1024,10 +1047,18 @@ TypeSet::getObjectClass(unsigned i) const // ObjectGroup ///////////////////////////////////////////////////////////////////// +inline uint32_t +ObjectGroup::basePropertyCountDontCheckGeneration() +{ + uint32_t flags = flagsDontCheckGeneration(); + return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT; +} + inline uint32_t ObjectGroup::basePropertyCount() { - return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT; + maybeSweep(nullptr); + return basePropertyCountDontCheckGeneration(); } inline void @@ -1083,18 +1114,25 @@ ObjectGroup::getProperty(ExclusiveContext* cx, JSObject* obj, jsid id) } inline HeapTypeSet* -ObjectGroup::maybeGetProperty(jsid id) +ObjectGroup::maybeGetPropertyDontCheckGeneration(jsid id) { MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id)); MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); - MOZ_ASSERT(!unknownProperties()); + MOZ_ASSERT(!unknownPropertiesDontCheckGeneration()); Property* prop = TypeHashSet::Lookup - (propertySet, basePropertyCount(), id); + (propertySet, basePropertyCountDontCheckGeneration(), id); return prop ? &prop->types : nullptr; } +inline HeapTypeSet* +ObjectGroup::maybeGetProperty(jsid id) +{ + maybeSweep(nullptr); + return maybeGetPropertyDontCheckGeneration(id); +} + inline unsigned ObjectGroup::getPropertyCount() { @@ -1125,7 +1163,7 @@ JSScript::types() } inline bool -JSScript::ensureHasTypes(JSContext* cx) +JSScript::ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&) { return types() || makeTypes(cx); } diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 31fd9af6e3..d086b556e8 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -4436,6 +4436,7 @@ JSScript::maybeSweepTypes(AutoClearTypeInferenceStateOnOOM* oom) // only do this if nothing has been compiled for the script, which will be // the case unless the script has been compiled since we started sweeping. if (types.sweepReleaseTypes && + !types.keepTypeScripts && !hasBaselineScript() && !hasIonScript()) { @@ -4492,20 +4493,24 @@ Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, TypeZone::TypeZone(Zone* zone) : zone_(zone), - typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - generation(0), - compilerOutputs(nullptr), - sweepTypeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - sweepCompilerOutputs(nullptr), - sweepReleaseTypes(false), - activeAnalysis(nullptr) + typeLifoAlloc(zone->group(), (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), + generation(zone->group(), 0), + compilerOutputs(zone->group(), nullptr), + sweepTypeLifoAlloc(zone->group(), (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), + sweepCompilerOutputs(zone->group(), nullptr), + sweepReleaseTypes(zone->group(), false), + sweepingTypes(zone->group(), false), + keepTypeScripts(zone->group(), false), + activeAnalysis(zone->group(), nullptr) { } TypeZone::~TypeZone() { - js_delete(compilerOutputs); - js_delete(sweepCompilerOutputs); + js_delete(compilerOutputs.ref()); + js_delete(sweepCompilerOutputs.ref()); + MOZ_RELEASE_ASSERT(!sweepingTypes); + MOZ_ASSERT(!keepTypeScripts); } void diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index ae593a4e73..4f823b95b8 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -1255,6 +1255,19 @@ class TypeScript #endif }; +// Ensures no TypeScripts are purged in the current zone. +class MOZ_RAII AutoKeepTypeScripts +{ + TypeZone& zone_; + bool prev_; + + AutoKeepTypeScripts(const AutoKeepTypeScripts&) = delete; + void operator=(const AutoKeepTypeScripts&) = delete; + + public: + explicit inline AutoKeepTypeScripts(JSContext* cx); + inline ~AutoKeepTypeScripts(); +}; void FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap); @@ -1325,6 +1338,9 @@ struct TypeZone static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024; LifoAlloc typeLifoAlloc; + TypeZone(const TypeZone&) = delete; + void operator=(const TypeZone&) = delete; + // Current generation for sweeping. uint32_t generation : 1; @@ -1348,6 +1364,7 @@ struct TypeZone // information attached to scripts. bool sweepReleaseTypes; + ZoneGroupData keepTypeScripts; // The topmost AutoEnterAnalysis on the stack, if there is one. AutoEnterAnalysis* activeAnalysis; diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 2ed89e32e4..07e78d8a6d 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -362,7 +362,7 @@ UnboxedPlainObject::ensureExpando(JSContext* cx, Handle obj bool UnboxedPlainObject::containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const { - if (layout().lookup(id)) + if (layoutDontCheckGeneration().lookup(id)) return true; if (maybeExpando() && maybeExpando()->containsShapeOrElement(cx, id))