author | Luke Wagner <luke@mozilla.com> |
Mon, 23 Jun 2014 14:55:56 -0500 | |
changeset 190321 | 69b3709b24e1ffbbc87e7f4e9c36f79bb5c9cfd1 |
parent 190320 | 6daeae05aeb83aac24a6a6781c5880ced411858f |
child 190322 | c3abd7cfc498286c176aae2f00cf75f8326ba62d |
push id | 27004 |
push user | emorley@mozilla.com |
push date | Tue, 24 Jun 2014 15:52:34 +0000 |
treeherder | mozilla-central@7b174d47f3cc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bbouvier |
bugs | 1027885 |
milestone | 33.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -826,23 +826,28 @@ class MOZ_STACK_CLASS ModuleCompiler public: Func(PropertyName *name, Signature &&sig, Label *code) : name_(name), defined_(false), srcOffset_(0), endOffset_(0), sig_(Move(sig)), code_(code), compileTime_(0) {} PropertyName *name() const { return name_; } - bool defined() const { return defined_; } - void finish(uint32_t start, uint32_t end) { + + void define(ModuleCompiler &m, ParseNode *fn) { JS_ASSERT(!defined_); defined_ = true; - srcOffset_ = start; - endOffset_ = end; + + // The begin/end char range is relative to the beginning of the module. + // hence the assertions. + JS_ASSERT(fn->pn_pos.begin > m.moduleStart()); + JS_ASSERT(fn->pn_pos.begin <= fn->pn_pos.end); + srcOffset_ = fn->pn_pos.begin - m.moduleStart(); + endOffset_ = fn->pn_pos.end - m.moduleStart(); } uint32_t srcOffset() const { JS_ASSERT(defined_); return srcOffset_; } uint32_t endOffset() const { JS_ASSERT(defined_); return endOffset_; } Signature &sig() { return sig_; } const Signature &sig() const { return sig_; } Label *code() const { return code_; } unsigned compileTime() const { return compileTime_; } @@ -1415,43 +1420,64 @@ class MOZ_STACK_CLASS ModuleCompiler } uint32_t minHeapLength() const { return module_->minHeapLength(); } LifoAlloc &lifo() { return moduleLifo_; } -#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) - bool addProfiledFunction(const Func &func, unsigned endCodeOffset) { - unsigned lineno = 0U, columnIndex = 0U; - tokenStream().srcCoords.lineNumAndColumnIndex(func.srcOffset(), &lineno, &columnIndex); - unsigned startCodeOffset = func.code()->offset(); - return module_->addProfiledFunction(func.name(), startCodeOffset, endCodeOffset, - lineno, columnIndex); - } -#endif - -#ifdef JS_ION_PERF - bool addPerfProfiledBlocks(AsmJSPerfSpewer &perfSpewer, const Func &func, unsigned endCodeOffset) { - unsigned startCodeOffset = func.code()->offset(); - perfSpewer.noteBlocksOffsets(); - unsigned endInlineCodeOffset = perfSpewer.endInlineCode.offset(); - return module_->addPerfProfiledBlocks(func.name(), startCodeOffset, endInlineCodeOffset, - endCodeOffset, perfSpewer.basicBlocks()); - } -#endif - - bool addFunctionCounts(IonScriptCounts *counts) { - return module_->addFunctionCounts(counts); - } - void startFunctionBodies() { module_->startFunctionBodies(); } + + void startGeneratingFunction(Func &func, MIRGenerator &mir) { + // 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 + // after each function is compiled. This method is responsible for cleaning + // out any dangling pointers that the MacroAssembler may have kept. + masm_.resetForNewCodeGenerator(mir.alloc()); + masm_.align(CodeAlignment); + masm_.bind(func.code()); + } + + bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) { + JS_ASSERT(func.defined() && func.code()->bound()); + + jit::IonScriptCounts *counts = codegen.extractScriptCounts(); + if (counts && !module_->addFunctionCounts(counts)) { + js_delete(counts); + return false; + } + +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) + unsigned line = 0, column = 0; + tokenStream().srcCoords.lineNumAndColumnIndex(func.srcOffset(), &line, &column); + unsigned startCodeOffset = func.code()->offset(); + unsigned endCodeOffset = masm_.currentOffset(); + if (!module_->addProfiledFunction(func.name(), startCodeOffset, endCodeOffset, line, column)) + return false; +# ifdef JS_ION_PERF + if (PerfBlockEnabled()) { + // Per-block profiling info uses significantly more memory so only + // store this information if it is actively requested. + mir.perfSpewer().noteBlocksOffsets(); + unsigned endInlineCodeOffset = mir.perfSpewer().endInlineCode.offset(); + if (!module_->addPerfProfiledBlocks(func.name(), startCodeOffset, endInlineCodeOffset, + endCodeOffset, mir.perfSpewer().basicBlocks())) + { + return false; + } + } +# endif +#endif + return true; + } + void finishFunctionBodies() { JS_ASSERT(!finishedFunctionBodies_); masm_.align(AsmJSPageSize); finishedFunctionBodies_ = true; module_->finishFunctionBodies(masm_.currentOffset()); } void setInterpExitOffset(unsigned exitIndex) { @@ -5321,26 +5347,17 @@ CheckFunction(ModuleCompiler &m, LifoAll Signature sig(Move(argTypes), retType); ModuleCompiler::Func *func = nullptr; if (!CheckFunctionSignature(m, fn, Move(sig), FunctionName(fn), &func)) return false; if (func->defined()) return m.failName(fn, "function '%s' already defined", FunctionName(fn)); - uint32_t funcBegin = fn->pn_pos.begin; - uint32_t funcEnd = fn->pn_pos.end; - // The begin/end char range is relative to the beginning of the module, - // hence the assertions. - JS_ASSERT(funcBegin > m.moduleStart()); - JS_ASSERT(funcEnd > m.moduleStart()); - funcBegin -= m.moduleStart(); - funcEnd -= m.moduleStart(); - func->finish(funcBegin, funcEnd); - + func->define(m, fn); func->accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC); m.parser().release(mark); // Copy the cumulative minimum heap size constraint to the MIR for use in analysis. The length // is also constrained to particular lengths, so firstly round up - a larger 'heap required // length' can help range analysis to prove that bounds checks are not needed. uint32_t len = js::RoundUpToNextValidAsmJSHeapLength(m.minHeapLength()); @@ -5352,64 +5369,33 @@ CheckFunction(ModuleCompiler &m, LifoAll return true; } static bool GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, LIRGraph &lir) { int64_t before = PRMJ_Now(); - // 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 - // after each function is compiled. This method is responsible for cleaning - // out any dangling pointers that the MacroAssembler may have kept. - m.masm().resetForNewCodeGenerator(mir.alloc()); - - m.masm().bind(func.code()); + m.startGeneratingFunction(func, mir); ScopedJSDeletePtr<CodeGenerator> codegen(js_new<CodeGenerator>(&mir, &lir, &m.masm())); 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 - // profiling info isn't huge, so store it always (in --enable-profiling - // builds, which is only Nightly builds, but default). - if (!m.addProfiledFunction(func, m.masm().currentOffset())) - return false; -#endif - -#ifdef JS_ION_PERF - // Per-block profiling info uses significantly more memory so only store - // this information if it is actively requested. - if (PerfBlockEnabled()) { - if (!m.addPerfProfiledBlocks(mir.perfSpewer(), func, m.masm().currentOffset())) - return false; - } -#endif - - // Align internal function headers. - m.masm().align(CodeAlignment); + if (!m.finishGeneratingFunction(func, mir, *codegen)) + return false; func.accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC); if (!m.maybeReportCompileTime(func)) return false; // Unlike regular IonMonkey which links and generates a new JitCode for // every function, we accumulate all the functions in the module in a // single MacroAssembler and link at end. Linking asm.js doesn't require a - // CodeGenerator so we can destroy it now. + // CodeGenerator so we can destroy it now (via ScopedJSDeletePtr). return true; } static bool CheckAllFunctionsDefined(ModuleCompiler &m) { for (unsigned i = 0; i < m.numFunctions(); i++) { if (!m.function(i).code()->bound())