diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index eb553bd244e..4108635cc5d 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -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)); +} diff --git a/js/src/ion/AsmJSModule.h b/js/src/ion/AsmJSModule.h index 72bf651c5c6..69e81cc813f 100644 --- a/js/src/ion/AsmJSModule.h +++ b/js/src/ion/AsmJSModule.h @@ -305,6 +305,7 @@ class AsmJSModule #if defined(JS_CPU_ARM) typedef Vector BoundsCheckVector; #endif + typedef Vector 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 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); diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index cb55a5cb825..dcacb933fc2 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -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(); @@ -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; } diff --git a/js/src/ion/CodeGenerator.h b/js/src/ion/CodeGenerator.h index 17a2b12f706..175fe24e27c 100644 --- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -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 diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index a3ed445bd70..bc379ea23f8 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -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(); + 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 *) diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 2e766548111..699c49968e5 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -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(); } } diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index f0ec5c580cb..66f6d4a1c7e 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -632,6 +632,15 @@ js_Disassemble1(JSContext *cx, JS::Handle script, jsbytecode *pc, uns void js_DumpPCCounts(JSContext *cx, JS::Handle 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___ */