Bug 864216 - Allow generating IonScriptCounts for asm.js compiled functions, r=luke.

This commit is contained in:
Brian Hackett 2013-04-23 13:31:03 -06:00
parent 75a7f384d9
commit c82520f2a0
7 changed files with 135 additions and 29 deletions

View File

@ -1321,7 +1321,9 @@ class ModuleCompiler
return false;
return exits_.add(p, Move(exitDescriptor), *exitIndex);
}
bool addFunctionCounts(IonScriptCounts *counts) {
return module_->addFunctionCounts(counts);
}
void setSecondPassComplete() {
JS_ASSERT(currentPass_ == 2);
@ -2311,6 +2313,12 @@ js::AsmJSModuleObjectToModule(JSObject *obj)
return *(AsmJSModule *)obj->getReservedSlot(ASM_CODE_RESERVED_SLOT).toPrivate();
}
bool
js::IsAsmJSModuleObject(JSObject *obj)
{
return obj->getClass() == &AsmJSModuleClass;
}
static const unsigned ASM_MODULE_FUNCTION_MODULE_OBJECT_SLOT = 0;
JSObject &
@ -4431,6 +4439,12 @@ GenerateAsmJSCode(ModuleCompiler &m, ModuleCompiler::Func &func,
if (!m.collectAccesses(mirGen))
return false;
ion::IonScriptCounts *counts = codegen->extractUnassociatedScriptCounts();
if (counts && !m.addFunctionCounts(counts)) {
js_delete(counts);
return false;
}
// A single MacroAssembler is reused for all function compilations so
// that there is a single linear code segment for each module. To avoid
// spiking memory, a LifoAllocScope in the caller frees all MIR/LIR
@ -5564,3 +5578,8 @@ js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp)
return true;
}
AsmJSModule::~AsmJSModule()
{
for (size_t i = 0; i < numFunctionCounts(); i++)
js_delete(functionCounts(i));
}

View File

@ -305,6 +305,7 @@ class AsmJSModule
#if defined(JS_CPU_ARM)
typedef Vector<ion::AsmJSBoundsCheck, 0, SystemAllocPolicy> BoundsCheckVector;
#endif
typedef Vector<ion::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
GlobalVector globals_;
ExitVector exits_;
@ -334,6 +335,8 @@ class AsmJSModule
PostLinkFailureInfo postLinkFailureInfo_;
FunctionCountsVector functionCounts_;
public:
explicit AsmJSModule(JSContext *cx)
: numGlobalVars_(0),
@ -350,6 +353,8 @@ class AsmJSModule
postLinkFailureInfo_(cx)
{}
~AsmJSModule();
void trace(JSTracer *trc) {
for (unsigned i = 0; i < globals_.length(); i++)
globals_[i].trace(trc);
@ -425,6 +430,9 @@ class AsmJSModule
*exitIndex = unsigned(exits_.length());
return exits_.append(Exit(ffiIndex));
}
bool addFunctionCounts(ion::IonScriptCounts *counts) {
return functionCounts_.append(counts);
}
bool addExportedFunction(RawFunction fun, PropertyName *maybeFieldName,
MoveRef<ArgCoercionVector> argCoercions, ReturnType returnType)
@ -468,6 +476,12 @@ class AsmJSModule
const Exit &exit(unsigned i) const {
return exits_[i];
}
unsigned numFunctionCounts() const {
return functionCounts_.length();
}
ion::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
@ -661,6 +675,9 @@ class AsmJSModule
extern AsmJSModule &
AsmJSModuleObjectToModule(JSObject *obj);
extern bool
IsAsmJSModuleObject(JSObject *obj);
extern JSObject &
AsmJSModuleObject(JSFunction *moduleFun);

View File

@ -127,10 +127,16 @@ MNewStringObject::templateObj() const {
}
CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
: CodeGeneratorSpecific(gen, graph, masm)
: CodeGeneratorSpecific(gen, graph, masm),
unassociatedScriptCounts_(NULL)
{
}
CodeGenerator::~CodeGenerator()
{
js_delete(unassociatedScriptCounts_);
}
bool
CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
{
@ -2093,15 +2099,12 @@ CodeGenerator::maybeCreateScriptCounts()
CompileInfo *outerInfo = &gen->info();
RawScript script = outerInfo->script();
if (!script)
return NULL;
if (cx->runtime->profilingScripts && !script->hasScriptCounts) {
if (!script->initScriptCounts(cx))
if (cx->runtime->profilingScripts) {
if (script && !script->hasScriptCounts && !script->initScriptCounts(cx))
return NULL;
}
if (!script->hasScriptCounts)
if (script && !script->hasScriptCounts)
return NULL;
counts = js_new<IonScriptCounts>();
@ -2110,19 +2113,23 @@ CodeGenerator::maybeCreateScriptCounts()
return NULL;
}
script->addIonCounts(counts);
if (script)
script->addIonCounts(counts);
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 inling with.
MResumePoint *resume = block->entryResumePoint();
while (resume->caller())
resume = resume->caller();
uint32_t offset = resume->pc() - script->code;
JS_ASSERT(offset < script->length);
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();
uint32_t offset = resume->pc() - script->code;
JS_ASSERT(offset < script->length);
}
if (!counts->block(i).init(block->id(), offset, block->numSuccessors()))
return NULL;
@ -2130,6 +2137,12 @@ CodeGenerator::maybeCreateScriptCounts()
counts->block(i).setSuccessor(j, block->getSuccessor(j)->id());
}
if (!script) {
// Compiling code for Asm.js. Leave the counts on the CodeGenerator to
// be picked up by the AsmJSModule after generation finishes.
unassociatedScriptCounts_ = counts;
}
return counts;
}

View File

@ -41,6 +41,7 @@ class CodeGenerator : public CodeGeneratorSpecific
public:
CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm = NULL);
~CodeGenerator();
public:
bool generate();
@ -260,6 +261,12 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic);
bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, CallsiteCloneIC *ic);
IonScriptCounts *extractUnassociatedScriptCounts() {
IonScriptCounts *counts = unassociatedScriptCounts_;
unassociatedScriptCounts_ = NULL; // prevent delete in dtor
return counts;
}
private:
bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
PropertyName *name, TypedOrValueRegister output,
@ -301,6 +308,9 @@ class CodeGenerator : public CodeGeneratorSpecific
// Bailout if an element about to be written to is a hole.
bool emitStoreHoleCheck(Register elements, const LAllocation *index, LSnapshot *snapshot);
// Script counts created when compiling code with no associated JSScript.
IonScriptCounts *unassociatedScriptCounts_;
};
} // namespace ion

View File

@ -36,6 +36,10 @@
#include "vm/Debugger.h"
#include "vm/Shape.h"
#ifdef JS_ASMJS
#include "ion/AsmJSModule.h"
#endif
#include "jsatominlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
@ -917,6 +921,34 @@ JS_DumpCompartmentPCCounts(JSContext *cx)
if (script->hasScriptCounts && script->enclosingScriptsCompiledSuccessfully())
JS_DumpPCCounts(cx, script);
}
#if defined(JS_ASMJS) && defined(DEBUG)
for (unsigned thingKind = FINALIZE_OBJECT0; thingKind < FINALIZE_OBJECT_LIMIT; thingKind++) {
for (CellIter i(cx->zone(), (AllocKind) thingKind); !i.done(); i.next()) {
JSObject *obj = i.get<JSObject>();
if (obj->compartment() != cx->compartment)
continue;
if (IsAsmJSModuleObject(obj)) {
AsmJSModule &module = AsmJSModuleObjectToModule(obj);
Sprinter sprinter(cx);
if (!sprinter.init())
return;
fprintf(stdout, "--- Asm.js Module ---\n");
for (size_t i = 0; i < module.numFunctionCounts(); i++) {
ion::IonScriptCounts *counts = module.functionCounts(i);
DumpIonScriptCounts(&sprinter, counts);
}
fputs(sprinter.string(), stdout);
fprintf(stdout, "--- END Asm.js Module ---\n");
}
}
}
#endif
}
JS_PUBLIC_API(JSObject *)

View File

@ -268,6 +268,23 @@ PCCounts::countName(JSOp op, size_t which)
#ifdef DEBUG
void
js::DumpIonScriptCounts(Sprinter *sp, ion::IonScriptCounts *ionCounts)
{
Sprint(sp, "IonScript [%lu blocks]:\n", ionCounts->numBlocks());
for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
const ion::IonBlockCounts &block = ionCounts->block(i);
if (block.hitCount() < 10)
continue;
Sprint(sp, "BB #%lu [%05u]", block.id(), block.offset());
for (size_t j = 0; j < block.numSuccessors(); j++)
Sprint(sp, " -> #%lu", block.successor(j));
Sprint(sp, " :: %llu hits %u instruction bytes %u spill bytes\n",
block.hitCount(), block.instructionBytes(), block.spillBytes());
Sprint(sp, "%s\n", block.code());
}
}
void
js_DumpPCCounts(JSContext *cx, HandleScript script, js::Sprinter *sp)
{
@ -305,18 +322,7 @@ js_DumpPCCounts(JSContext *cx, HandleScript script, js::Sprinter *sp)
ion::IonScriptCounts *ionCounts = script->getIonCounts();
while (ionCounts) {
Sprint(sp, "IonScript [%lu blocks]:\n", ionCounts->numBlocks());
for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
const ion::IonBlockCounts &block = ionCounts->block(i);
if (block.hitCount() < 10)
continue;
Sprint(sp, "BB #%lu [%05u]", block.id(), block.offset());
for (size_t j = 0; j < block.numSuccessors(); j++)
Sprint(sp, " -> #%lu", block.successor(j));
Sprint(sp, " :: %llu hits %u instruction bytes %u spill bytes\n",
block.hitCount(), block.instructionBytes(), block.spillBytes());
Sprint(sp, "%s\n", block.code());
}
DumpIonScriptCounts(sp, ionCounts);
ionCounts = ionCounts->previous();
}
}

View File

@ -632,6 +632,15 @@ js_Disassemble1(JSContext *cx, JS::Handle<JSScript*> script, jsbytecode *pc, uns
void
js_DumpPCCounts(JSContext *cx, JS::Handle<JSScript*> script, js::Sprinter *sp);
#ifdef JS_ION
namespace js {
namespace ion { struct IonScriptCounts; }
void
DumpIonScriptCounts(js::Sprinter *sp, ion::IonScriptCounts *ionCounts);
}
#endif
#endif
#endif /* jsopcode_h___ */