Bug 1716529 - Don't create allocation sites until baseline r=jandem

This stops creating allocation sites for IC stubs when running in the baseline
interpreter. When a script is compiled in baseline proper this scans the IC
chain for ops that could potentially reference allocation sites, and allocates
them where necessary.

This should result in fewer sites being created and less overhead for code that
doesn't reach baseline.

Differential Revision: https://phabricator.services.mozilla.com/D117920
This commit is contained in:
Jon Coppeard 2021-06-17 08:57:55 +00:00
Родитель d8f25eb345
Коммит 5997bc1e3d
5 изменённых файлов: 96 добавлений и 14 удалений

Просмотреть файл

@ -11,6 +11,7 @@
#include "jit/ABIFunctions.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/CacheIRCompiler.h"
#include "jit/CalleeToken.h"
#include "jit/FixedList.h"
#include "jit/IonAnalysis.h"
@ -541,6 +542,58 @@ bool BaselineCodeGen<Handler>::emitOutOfLinePostBarrierSlot() {
return true;
}
// Scan the a cache IR stub's fields and create an allocation site for any that
// refer to the catch-all unknown allocation site. This will be the case for
// stubs created when running in the interpreter. This happens on transition to
// baseline.
static bool CreateAllocSitesForCacheIRStub(JSScript* script,
ICCacheIRStub* stub) {
const CacheIRStubInfo* stubInfo = stub->stubInfo();
uint8_t* stubData = stub->stubDataStart();
uint32_t field = 0;
size_t offset = 0;
while (true) {
StubField::Type fieldType = stubInfo->fieldType(field);
if (fieldType == StubField::Type::Limit) {
break;
}
if (fieldType == StubField::Type::AllocSite) {
gc::AllocSite* site =
stubInfo->getPtrStubField<ICCacheIRStub, gc::AllocSite>(stub, offset);
if (site->kind() == gc::AllocSite::Kind::Unknown) {
gc::AllocSite* newSite = script->createAllocSite();
if (!newSite) {
return false;
}
stubInfo->replaceStubRawWord(stubData, offset, uintptr_t(site),
uintptr_t(newSite));
}
}
field++;
offset += StubField::sizeInBytes(fieldType);
}
return true;
}
static void CreateAllocSitesForICChain(JSScript* script, uint32_t entryIndex) {
JitScript* jitScript = script->jitScript();
ICStub* stub = jitScript->icEntry(entryIndex).firstStub();
while (!stub->isFallback()) {
if (!CreateAllocSitesForCacheIRStub(script, stub->toCacheIRStub())) {
// This is an optimization and safe to skip if we hit OOM or per-zone
// limit.
return;
}
stub = stub->toCacheIRStub()->next();
}
}
template <>
bool BaselineCompilerCodeGen::emitNextIC() {
// Emit a call to an IC stored in JitScript. Calls to this must match the
@ -563,6 +616,10 @@ bool BaselineCompilerCodeGen::emitNextIC() {
MOZ_ASSERT(stub->pcOffset() == pcOffset);
MOZ_ASSERT(BytecodeOpHasIC(JSOp(*handler.pc())));
if (BytecodeOpCanHaveAllocSite(JSOp(*handler.pc()))) {
CreateAllocSitesForICChain(script, entryIndex);
}
// Load stub pointer into ICStubReg.
masm.loadPtr(frame.addressOfICScript(), ICStubReg);
size_t firstStubOffset = ICScript::offsetOfFirstStub(entryIndex);

Просмотреть файл

@ -2384,9 +2384,8 @@ bool DoNewArrayFallback(JSContext* cx, BaselineFrame* frame,
return false;
}
JSScript* outerScript = frame->outerScript();
TryAttachStub<NewArrayIRGenerator>("NewArray", cx, frame, stub, JSOp(*pc),
array, outerScript);
array, frame);
res.setObject(*array);
return true;
@ -2420,9 +2419,8 @@ bool DoNewObjectFallback(JSContext* cx, BaselineFrame* frame,
return false;
}
JSScript* outerScript = frame->outerScript();
TryAttachStub<NewObjectIRGenerator>("NewObject", cx, frame, stub, JSOp(*pc),
obj, outerScript);
obj, frame);
res.setObject(*obj);
return true;

Просмотреть файл

@ -16,6 +16,7 @@
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
#include "jit/BaselineCacheIRCompiler.h"
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/CacheIRSpewer.h"
#include "jit/InlinableNatives.h"
@ -11008,13 +11009,13 @@ AttachDecision BinaryArithIRGenerator::tryAttachStringInt32Arith() {
NewArrayIRGenerator::NewArrayIRGenerator(JSContext* cx, HandleScript script,
jsbytecode* pc, ICState state, JSOp op,
HandleObject templateObj,
JSScript* outerScript)
BaselineFrame* frame)
: IRGenerator(cx, script, pc, CacheKind::NewArray, state),
#ifdef JS_CACHEIR_SPEW
op_(op),
#endif
templateObject_(templateObj),
outerScript_(outerScript) {
frame_(frame) {
MOZ_ASSERT(templateObject_);
}
@ -11026,6 +11027,24 @@ void NewArrayIRGenerator::trackAttached(const char* name) {
#endif
}
// Allocation sites are usually created during baseline compilation, but we also
// need to created them when an IC stub is added to a baseline compiled script
// and when trial inlining.
static gc::AllocSite* MaybeCreateAllocSite(jsbytecode* pc,
BaselineFrame* frame) {
MOZ_ASSERT(BytecodeOpCanHaveAllocSite(JSOp(*pc)));
JSScript* outerScript = frame->outerScript();
bool inInterpreter = frame->runningInInterpreter();
bool isInlined = frame->icScript()->isInlined();
if (inInterpreter && !isInlined) {
return outerScript->zone()->unknownAllocSite();
}
return outerScript->createAllocSite();
}
AttachDecision NewArrayIRGenerator::tryAttachArrayObject() {
ArrayObject* arrayObj = &templateObject_->as<ArrayObject>();
@ -11047,7 +11066,7 @@ AttachDecision NewArrayIRGenerator::tryAttachArrayObject() {
writer.guardNoAllocationMetadataBuilder(
cx_->realm()->addressOfMetadataBuilder());
gc::AllocSite* site = outerScript_->createAllocSite();
gc::AllocSite* site = MaybeCreateAllocSite(pc_, frame_);
if (!site) {
return AttachDecision::NoAction;
}
@ -11075,13 +11094,13 @@ AttachDecision NewArrayIRGenerator::tryAttachStub() {
NewObjectIRGenerator::NewObjectIRGenerator(JSContext* cx, HandleScript script,
jsbytecode* pc, ICState state,
JSOp op, HandleObject templateObj,
JSScript* outerScript)
BaselineFrame* frame)
: IRGenerator(cx, script, pc, CacheKind::NewObject, state),
#ifdef JS_CACHEIR_SPEW
op_(op),
#endif
templateObject_(templateObj),
outerScript_(outerScript) {
frame_(frame) {
MOZ_ASSERT(templateObject_);
}
@ -11114,7 +11133,7 @@ AttachDecision NewObjectIRGenerator::tryAttachPlainObject() {
MOZ_ASSERT(!nativeObj->hasDynamicElements());
MOZ_ASSERT(!nativeObj->isSharedMemory());
gc::AllocSite* site = outerScript_->createAllocSite();
gc::AllocSite* site = MaybeCreateAllocSite(pc_, frame_);
if (!site) {
return AttachDecision::NoAction;
}

Просмотреть файл

@ -37,6 +37,7 @@ namespace jit {
enum class BaselineCacheIRStubKind;
enum class InlinableNative : uint16_t;
class BaselineFrame;
class ICCacheIRStub;
class ICScript;
class ICStubSpace;
@ -1923,14 +1924,14 @@ class MOZ_RAII NewArrayIRGenerator : public IRGenerator {
JSOp op_;
#endif
HandleObject templateObject_;
JSScript* outerScript_;
BaselineFrame* frame_;
void trackAttached(const char* name);
public:
NewArrayIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState state, JSOp op, HandleObject templateObj,
JSScript* outerScript);
BaselineFrame* frame);
AttachDecision tryAttachStub();
AttachDecision tryAttachArrayObject();
@ -1941,19 +1942,23 @@ class MOZ_RAII NewObjectIRGenerator : public IRGenerator {
JSOp op_;
#endif
HandleObject templateObject_;
JSScript* outerScript_;
BaselineFrame* frame_;
void trackAttached(const char* name);
public:
NewObjectIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState state, JSOp op, HandleObject templateObj,
JSScript* outerScript);
BaselineFrame* frame);
AttachDecision tryAttachStub();
AttachDecision tryAttachPlainObject();
};
inline bool BytecodeOpCanHaveAllocSite(JSOp op) {
return op == JSOp::NewArray || op == JSOp::NewObject || op == JSOp::NewInit;
}
// Retrieve Xray JIT info set by the embedder.
extern JS::XrayJitInfo* GetXrayJitInfo();

Просмотреть файл

@ -1117,6 +1117,9 @@ T* CacheIRStubInfo::getPtrStubField(Stub* stub, uint32_t offset) const {
return *reinterpret_cast<T**>(stubData + offset);
}
template gc::AllocSite* CacheIRStubInfo::getPtrStubField(ICCacheIRStub* stub,
uint32_t offset) const;
template <typename T, typename V>
static void InitGCPtr(uintptr_t* ptr, V val) {
AsGCPtr<T>(ptr)->init(mozilla::BitwiseCast<T>(val));