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:
Brian Hackett 2014-06-02 09:35:11 -06:00
Родитель 0fbf27d590
Коммит e815ccd8c6
9 изменённых файлов: 100 добавлений и 29 удалений

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

@ -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)