зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1018290 - Add back IonScriptCounts to Asm.js modules, allow IonScriptCounts to be generated with off thread compilation, r=luke.
This commit is contained in:
Родитель
0fbf27d590
Коммит
e815ccd8c6
|
@ -1446,6 +1446,10 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||
}
|
||||
#endif
|
||||
|
||||
bool addFunctionCounts(IonScriptCounts *counts) {
|
||||
return module_->addFunctionCounts(counts);
|
||||
}
|
||||
|
||||
void finishFunctionBodies() {
|
||||
JS_ASSERT(!finishedFunctionBodies_);
|
||||
masm_.align(AsmJSPageSize);
|
||||
|
@ -5481,6 +5485,12 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L
|
|||
if (!codegen || !codegen->generateAsmJS(&m.stackOverflowLabel()))
|
||||
return m.fail(nullptr, "internal codegen failure (probably out of memory)");
|
||||
|
||||
jit::IonScriptCounts *counts = codegen->extractScriptCounts();
|
||||
if (counts && !m.addFunctionCounts(counts)) {
|
||||
js_delete(counts);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
// Profiling might not be active now, but it may be activated later (perhaps
|
||||
// after the module has been cached and reloaded from the cache). Function
|
||||
|
|
|
@ -374,6 +374,9 @@ AsmJSModule::~AsmJSModule()
|
|||
|
||||
DeallocateExecutableMemory(code_, pod.totalBytes_);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numFunctionCounts(); i++)
|
||||
js_delete(functionCounts(i));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -394,6 +397,7 @@ AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModu
|
|||
#if defined(JS_ION_PERF)
|
||||
perfProfiledBlocksFunctions_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
#endif
|
||||
functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
staticLinkData_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
|
|
|
@ -465,6 +465,8 @@ class AsmJSModule
|
|||
|
||||
ScriptSource * scriptSource_;
|
||||
|
||||
FunctionCountsVector functionCounts_;
|
||||
|
||||
// This field is accessed concurrently when requesting an interrupt.
|
||||
// Access must be synchronized via the runtime's interrupt lock.
|
||||
mutable bool codeIsProtected_;
|
||||
|
@ -603,6 +605,9 @@ class AsmJSModule
|
|||
*exitIndex = unsigned(exits_.length());
|
||||
return exits_.append(Exit(ffiIndex, globalDataOffset));
|
||||
}
|
||||
bool addFunctionCounts(jit::IonScriptCounts *counts) {
|
||||
return functionCounts_.append(counts);
|
||||
}
|
||||
|
||||
bool addExportedFunction(PropertyName *name, uint32_t srcStart, uint32_t srcEnd,
|
||||
PropertyName *maybeFieldName,
|
||||
|
@ -701,6 +706,12 @@ class AsmJSModule
|
|||
JS_ASSERT(exit.ionCodeOffset_);
|
||||
return code_ + exit.ionCodeOffset_;
|
||||
}
|
||||
unsigned numFunctionCounts() const {
|
||||
return functionCounts_.length();
|
||||
}
|
||||
jit::IonScriptCounts *functionCounts(unsigned i) {
|
||||
return functionCounts_[i];
|
||||
}
|
||||
|
||||
// An Exit holds bookkeeping information about an exit; the ExitDatum
|
||||
// struct overlays the actual runtime data stored in the global data
|
||||
|
|
|
@ -152,12 +152,14 @@ MNewStringObject::templateObj() const {
|
|||
CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
|
||||
: CodeGeneratorSpecific(gen, graph, masm)
|
||||
, ionScriptLabels_(gen->alloc())
|
||||
, scriptCounts_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CodeGenerator::~CodeGenerator()
|
||||
{
|
||||
JS_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
|
||||
js_delete(scriptCounts_);
|
||||
}
|
||||
|
||||
typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
|
||||
|
@ -3157,21 +3159,18 @@ CodeGenerator::visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool)
|
|||
IonScriptCounts *
|
||||
CodeGenerator::maybeCreateScriptCounts()
|
||||
{
|
||||
// If scripts are being profiled, create a new IonScriptCounts and attach
|
||||
// it to the script. This must be done on the main thread.
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
if (!cx || !cx->runtime()->profilingScripts)
|
||||
// If scripts are being profiled, create a new IonScriptCounts for the
|
||||
// profiling data, which will be attached to the associated JSScript or
|
||||
// AsmJS module after code generation finishes.
|
||||
if (!GetIonContext()->runtime->profilingScripts())
|
||||
return nullptr;
|
||||
|
||||
IonScriptCounts *counts = nullptr;
|
||||
|
||||
CompileInfo *outerInfo = &gen->info();
|
||||
JSScript *script = outerInfo->script();
|
||||
if (!script)
|
||||
return nullptr;
|
||||
|
||||
if (!script->hasScriptCounts() && !script->initScriptCounts(cx))
|
||||
return nullptr;
|
||||
|
||||
IonScriptCounts *counts = js_new<IonScriptCounts>();
|
||||
counts = js_new<IonScriptCounts>();
|
||||
if (!counts || !counts->init(graph.numBlocks())) {
|
||||
js_delete(counts);
|
||||
return nullptr;
|
||||
|
@ -3180,24 +3179,26 @@ CodeGenerator::maybeCreateScriptCounts()
|
|||
for (size_t i = 0; i < graph.numBlocks(); i++) {
|
||||
MBasicBlock *block = graph.getBlock(i)->mir();
|
||||
|
||||
// Find a PC offset in the outermost script to use. If this block
|
||||
// is from an inlined script, find a location in the outer script
|
||||
// to associate information about the inlining with.
|
||||
MResumePoint *resume = block->entryResumePoint();
|
||||
while (resume->caller())
|
||||
resume = resume->caller();
|
||||
uint32_t offset = 0;
|
||||
if (script) {
|
||||
// Find a PC offset in the outermost script to use. If this block
|
||||
// is from an inlined script, find a location in the outer script
|
||||
// to associate information about the inlining with.
|
||||
MResumePoint *resume = block->entryResumePoint();
|
||||
while (resume->caller())
|
||||
resume = resume->caller();
|
||||
offset = script->pcToOffset(resume->pc());
|
||||
}
|
||||
|
||||
uint32_t offset = script->pcToOffset(resume->pc());
|
||||
if (!counts->block(i).init(block->id(), offset, block->numSuccessors())) {
|
||||
js_delete(counts);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < block->numSuccessors(); j++)
|
||||
counts->block(i).setSuccessor(j, block->getSuccessor(j)->id());
|
||||
}
|
||||
|
||||
script->addIonCounts(counts);
|
||||
scriptCounts_ = counts;
|
||||
return counts;
|
||||
}
|
||||
|
||||
|
@ -6702,6 +6703,9 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
}
|
||||
}
|
||||
|
||||
if (scriptCounts_ && !script->hasScriptCounts() && !script->initScriptCounts(cx))
|
||||
return false;
|
||||
|
||||
// Check to make sure we didn't have a mid-build invalidation. If so, we
|
||||
// will trickle to jit::Compile() and return Method_Skipped.
|
||||
types::RecompileInfo recompileInfo;
|
||||
|
@ -6879,6 +6883,10 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
MOZ_ASSUME_UNREACHABLE("No such execution mode");
|
||||
}
|
||||
|
||||
// Attach any generated script counts to the script.
|
||||
if (IonScriptCounts *counts = extractScriptCounts())
|
||||
script->addIonCounts(counts);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,6 +354,12 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitInterruptCheck(LInterruptCheck *lir);
|
||||
bool visitRecompileCheck(LRecompileCheck *ins);
|
||||
|
||||
IonScriptCounts *extractScriptCounts() {
|
||||
IonScriptCounts *counts = scriptCounts_;
|
||||
scriptCounts_ = nullptr; // prevent delete in dtor
|
||||
return counts;
|
||||
}
|
||||
|
||||
private:
|
||||
bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
|
||||
PropertyName *name, TypedOrValueRegister output,
|
||||
|
@ -459,6 +465,9 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool emitValueResultChecks(LInstruction *lir, MDefinition *mir);
|
||||
#endif
|
||||
|
||||
// Script counts created during code generation.
|
||||
IonScriptCounts *scriptCounts_;
|
||||
|
||||
#if defined(JS_ION_PERF)
|
||||
PerfSpewer perfSpewer_;
|
||||
#endif
|
||||
|
|
|
@ -122,6 +122,12 @@ CompileRuntime::hadOutOfMemory()
|
|||
return runtime()->hadOutOfMemory;
|
||||
}
|
||||
|
||||
bool
|
||||
CompileRuntime::profilingScripts()
|
||||
{
|
||||
return runtime()->profilingScripts;
|
||||
}
|
||||
|
||||
const JSAtomState &
|
||||
CompileRuntime::names()
|
||||
{
|
||||
|
|
|
@ -68,6 +68,7 @@ class CompileRuntime
|
|||
bool signalHandlersInstalled();
|
||||
bool jitSupportsFloatingPoint();
|
||||
bool hadOutOfMemory();
|
||||
bool profilingScripts();
|
||||
|
||||
const JSAtomState &names();
|
||||
const StaticStrings &staticStrings();
|
||||
|
|
|
@ -1746,14 +1746,9 @@ OffThreadCompilationAvailable(JSContext *cx)
|
|||
//
|
||||
// Require cpuCount > 1 so that Ion compilation jobs and main-thread
|
||||
// execution are not competing for the same resources.
|
||||
//
|
||||
// Skip off thread compilation if PC count profiling is enabled, as
|
||||
// CodeGenerator::maybeCreateScriptCounts will not attach script profiles
|
||||
// when running off thread.
|
||||
return cx->runtime()->canUseParallelIonCompilation()
|
||||
&& HelperThreadState().cpuCount > 1
|
||||
&& cx->runtime()->gc.incrementalState == gc::NO_INCREMENTAL
|
||||
&& !cx->runtime()->profilingScripts;
|
||||
&& cx->runtime()->gc.incrementalState == gc::NO_INCREMENTAL;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -1988,10 +1983,9 @@ CheckScriptSize(JSContext *cx, JSScript* script)
|
|||
if (cx->runtime()->canUseParallelIonCompilation() && cpuCount > 1) {
|
||||
// Even if off thread compilation is enabled, there are cases where
|
||||
// compilation must still occur on the main thread. Don't compile
|
||||
// in these cases (except when profiling scripts, as compilations
|
||||
// occurring with profiling should reflect those without), but do
|
||||
// not forbid compilation so that the script may be compiled later.
|
||||
if (!OffThreadCompilationAvailable(cx) && !cx->runtime()->profilingScripts) {
|
||||
// in these cases, but do not forbid compilation so that the script
|
||||
// may be compiled later.
|
||||
if (!OffThreadCompilationAvailable(cx)) {
|
||||
IonSpew(IonSpew_Abort,
|
||||
"Script too large for main thread, skipping (%u bytes) (%u locals/args)",
|
||||
script->length(), numLocalsAndArgs);
|
||||
|
|
|
@ -843,6 +843,34 @@ JS_DumpCompartmentPCCounts(JSContext *cx)
|
|||
if (script->hasScriptCounts())
|
||||
JS_DumpPCCounts(cx, script);
|
||||
}
|
||||
|
||||
#if defined(JS_ION)
|
||||
for (unsigned thingKind = FINALIZE_OBJECT0; thingKind < FINALIZE_OBJECT_LIMIT; thingKind++) {
|
||||
for (ZoneCellIter i(cx->zone(), (AllocKind) thingKind); !i.done(); i.next()) {
|
||||
JSObject *obj = i.get<JSObject>();
|
||||
if (obj->compartment() != cx->compartment())
|
||||
continue;
|
||||
|
||||
if (obj->is<AsmJSModuleObject>()) {
|
||||
AsmJSModule &module = obj->as<AsmJSModuleObject>().module();
|
||||
|
||||
Sprinter sprinter(cx);
|
||||
if (!sprinter.init())
|
||||
return;
|
||||
|
||||
fprintf(stdout, "--- Asm.js Module ---\n");
|
||||
|
||||
for (size_t i = 0; i < module.numFunctionCounts(); i++) {
|
||||
jit::IonScriptCounts *counts = module.functionCounts(i);
|
||||
DumpIonScriptCounts(&sprinter, counts);
|
||||
}
|
||||
|
||||
fputs(sprinter.string(), stdout);
|
||||
fprintf(stdout, "--- END Asm.js Module ---\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
|
|
Загрузка…
Ссылка в новой задаче