Bug 1234985 - Odin: make names optional and supplied at the end (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Thu, 21 Jan 2016 20:48:58 -0600
changeset 318143 aa507ac36cf64c1b23fb2d3fda860568407e8e1a
parent 318142 46f66d456838db3523478b1b0132a0a3f0476917
child 318144 9c9ae4b5caccfe9216d31aa28b460b38ad1af701
push id1079
push userjlund@mozilla.com
push dateFri, 15 Apr 2016 21:02:33 +0000
treeherdermozilla-release@575fbf6786d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1234985
milestone46.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
Bug 1234985 - Odin: make names optional and supplied at the end (r=bbouvier)
js/src/asmjs/AsmJS.cpp
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmFrameIterator.cpp
js/src/asmjs/WasmGenerator.cpp
js/src/asmjs/WasmGenerator.h
js/src/asmjs/WasmModule.cpp
js/src/asmjs/WasmModule.h
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -2269,27 +2269,34 @@ class MOZ_STACK_CLASS ModuleValidator
 
         CacheableChars filename;
         if (parser_.ss->filename()) {
             filename = DuplicateString(parser_.ss->filename());
             if (!filename)
                 return false;
         }
 
+        CacheableCharsVector funcNames;
+        for (const Func* func : functions_) {
+            CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name());
+            if (!funcName || !funcNames.emplaceBack(Move(funcName)))
+                return false;
+        }
+
         uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
         module_->srcLength = endBeforeCurly - module_->srcStart;
 
         TokenPos pos;
         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
         uint32_t endAfterCurly = pos.end;
         module_->srcLengthWithRightBrace = endAfterCurly - module_->srcStart;
 
         UniqueModuleData base;
         UniqueStaticLinkData link;
-        if (!mg_.finish(heap, Move(filename), &base, &link, slowFuncs))
+        if (!mg_.finish(heap, Move(filename), Move(funcNames), &base, &link, slowFuncs))
             return false;
 
         moduleObj.set(WasmModuleObject::create(cx_));
         if (!moduleObj)
             return false;
 
         return moduleObj->init(cx_->new_<AsmJSModule>(Move(base), Move(link), Move(module_)));
     }
@@ -2628,21 +2635,21 @@ class MOZ_STACK_CLASS FunctionValidator
         labels_(m.cx()),
         hasAlreadyReturned_(false)
     {}
 
     ModuleValidator& m() const        { return m_; }
     ExclusiveContext* cx() const      { return m_.cx(); }
     ParseNode* fn() const             { return fn_; }
 
-    bool init(PropertyName* name, unsigned line, unsigned column) {
+    bool init(PropertyName* name, unsigned line) {
         if (!locals_.init() || !labels_.init())
             return false;
 
-        if (!m_.mg().startFuncDef(name, line, column, &fg_))
+        if (!m_.mg().startFuncDef(line, &fg_))
             return false;
 
         encoder_.emplace(fg_.bytecode());
         return true;
     }
 
     bool finish(uint32_t funcIndex, unsigned generateTime) {
         return m_.mg().finishFuncDef(funcIndex, generateTime, &fg_);
@@ -6701,22 +6708,22 @@ CheckStatement(FunctionValidator& f, Par
                                                           Expr::Continue, Expr::ContinueLabel);
       default:;
     }
 
     return f.fail(stmt, "unexpected statement kind");
 }
 
 static bool
-ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line, unsigned* column)
+ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
 {
     TokenStream& tokenStream = m.tokenStream();
 
     tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
-    tokenStream.srcCoords.lineNumAndColumnIndex(tokenStream.currentToken().pos.end, line, column);
+    *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
 
     RootedPropertyName name(m.cx());
 
     TokenKind tk;
     if (!tokenStream.getToken(&tk, TokenStream::Operand))
         return false;
     if (tk == TOK_NAME) {
         name = tokenStream.currentName();
@@ -6773,25 +6780,25 @@ CheckFunction(ModuleValidator& m)
 {
     // asm.js modules can be quite large when represented as parse trees so pop
     // the backing LifoAlloc after parsing/compiling each function.
     AsmJSParser::Mark mark = m.parser().mark();
 
     int64_t before = PRMJ_Now();
 
     ParseNode* fn = nullptr;
-    unsigned line = 0, column = 0;
-    if (!ParseFunction(m, &fn, &line, &column))
+    unsigned line = 0;
+    if (!ParseFunction(m, &fn, &line))
         return false;
 
     if (!CheckFunctionHead(m, fn))
         return false;
 
     FunctionValidator f(m, fn);
-    if (!f.init(FunctionName(fn), line, column))
+    if (!f.init(FunctionName(fn), line))
         return m.fail(fn, "internal compiler failure (probably out of memory)");
 
     ParseNode* stmtIter = ListHead(FunctionStatementList(fn));
 
     if (!CheckProcessingDirectives(m, &stmtIter))
         return false;
 
     ValTypeVector args;
@@ -8274,22 +8281,21 @@ BuildConsoleMessage(ExclusiveContext* cx
     UniqueChars slowText;
     if (!slowFuncs.empty()) {
         slowText.reset(JS_smprintf("; %d functions compiled slowly: ", slowFuncs.length()));
         if (!slowText)
             return nullptr;
 
         for (unsigned i = 0; i < slowFuncs.length(); i++) {
             const SlowFunction& func = slowFuncs[i];
-            JSAutoByteString name;
-            if (!AtomToPrintableString(cx, func.name, &name))
-                return nullptr;
-
-            slowText.reset(JS_smprintf("%s%s:%u:%u (%ums)%s", slowText.get(),
-                                       name.ptr(), func.line, func.column, func.ms,
+            slowText.reset(JS_smprintf("%s%s:%u (%ums)%s",
+                                       slowText.get(),
+                                       module.prettyFuncName(func.index),
+                                       func.lineOrBytecode,
+                                       func.ms,
                                        i+1 < slowFuncs.length() ? ", " : ""));
             if (!slowText)
                 return nullptr;
         }
     }
 
     const char* cacheString = "";
     switch (cacheResult) {
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -598,58 +598,47 @@ struct SourceCoords {
 typedef Vector<SourceCoords, 0, SystemAllocPolicy> SourceCoordsVector;
 
 // The FuncBytecode class contains the intermediate representation of a
 // parsed/decoded and validated asm.js/WebAssembly function. The FuncBytecode
 // lives only until it is fully compiled.
 class FuncBytecode
 {
     // Function metadata
-    SourceCoordsVector callSourceCoords_;
     const DeclaredSig& sig_;
     ValTypeVector locals_;
-
-    // Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
-    // asm.js compilation.
-    PropertyName* name_;
-    unsigned line_;
-    unsigned column_;
+    uint32_t lineOrBytecode_;
+    SourceCoordsVector callSourceCoords_;
 
     // Compilation bookkeeping
     uint32_t index_;
     unsigned generateTime_;
 
     UniqueBytecode bytecode_;
 
   public:
-    FuncBytecode(PropertyName* name,
-                 unsigned line,
-                 unsigned column,
-                 SourceCoordsVector&& sourceCoords,
-                 uint32_t index,
+    FuncBytecode(uint32_t index,
                  const DeclaredSig& sig,
                  UniqueBytecode bytecode,
                  ValTypeVector&& locals,
+                 uint32_t lineOrBytecode,
+                 SourceCoordsVector&& sourceCoords,
                  unsigned generateTime)
-      : callSourceCoords_(Move(sourceCoords)),
-        sig_(sig),
+      : sig_(sig),
         locals_(Move(locals)),
-        name_(name),
-        line_(line),
-        column_(column),
+        lineOrBytecode_(lineOrBytecode),
+        callSourceCoords_(Move(sourceCoords)),
         index_(index),
         generateTime_(generateTime),
         bytecode_(Move(bytecode))
     {}
 
     UniqueBytecode recycleBytecode() { return Move(bytecode_); }
 
-    PropertyName* name() const { return name_; }
-    unsigned line() const { return line_; }
-    unsigned column() const { return column_; }
+    uint32_t lineOrBytecode() const { return lineOrBytecode_; }
     const SourceCoords& sourceCoords(size_t i) const { return callSourceCoords_[i]; }
 
     uint32_t index() const { return index_; }
     const DeclaredSig& sig() const { return sig_; }
     const Bytecode& bytecode() const { return *bytecode_; }
 
     size_t numLocals() const { return locals_.length(); }
     ValType localType(size_t i) const { return locals_[i]; }
--- a/js/src/asmjs/WasmFrameIterator.cpp
+++ b/js/src/asmjs/WasmFrameIterator.cpp
@@ -101,17 +101,23 @@ FrameIterator::settle()
     }
 }
 
 JSAtom*
 FrameIterator::functionDisplayAtom() const
 {
     MOZ_ASSERT(!done());
 
-    const char* chars = module_->functionName(codeRange_->funcNameIndex());
+    UniqueChars owner;
+    const char* chars = module_->getFuncName(cx_, codeRange_->funcIndex(), &owner);
+    if (!chars) {
+        cx_->clearPendingException();
+        return cx_->names().empty;
+    }
+
     JSAtom* atom = AtomizeUTF8Chars(cx_, chars, strlen(chars));
     if (!atom) {
         cx_->clearPendingException();
         return cx_->names().empty;
     }
 
     return atom;
 }
@@ -688,17 +694,17 @@ ProfilingFrameIterator::label() const
         return importJitDescription;
       case ExitReason::ImportInterp:
         return importInterpDescription;
       case ExitReason::Native:
         return nativeDescription;
     }
 
     switch (codeRange_->kind()) {
-      case CodeRange::Function:         return module_->profilingLabel(codeRange_->funcNameIndex());
+      case CodeRange::Function:         return module_->profilingLabel(codeRange_->funcIndex());
       case CodeRange::Entry:            return "entry trampoline (in asm.js)";
       case CodeRange::ImportJitExit:    return importJitDescription;
       case CodeRange::ImportInterpExit: return importInterpDescription;
       case CodeRange::Interrupt:        return nativeDescription;
       case CodeRange::Inline:           return "inline stub (in asm.js)";
     }
 
     MOZ_CRASH("bad code range kind");
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -33,17 +33,16 @@ using namespace js::wasm;
 static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
 static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
 
 ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
   : cx_(cx),
     jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
     slowFuncs_(cx),
     numSigs_(0),
-    numFuncSigs_(0),
     lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
     alloc_(&lifo_),
     masm_(MacroAssembler::AsmJSToken(), alloc_),
     funcIndexToExport_(cx),
     parallel_(false),
     outstanding_(0),
     tasks_(cx),
     freeTasks_(cx),
@@ -120,17 +119,17 @@ ModuleGenerator::init(UniqueModuleGenera
 
     // For asm.js, the Vectors in ModuleGeneratorData are max-sized reservations
     // and will be initialized in a linear order via init* functions as the
     // module is generated. For wasm, the Vectors are correctly-sized and
     // already initialized.
     shared_ = Move(shared);
     if (kind == ModuleKind::Wasm) {
         numSigs_ = shared_->sigs.length();
-        numFuncSigs_ = shared_->funcSigs.length();
+        module_->numFuncs = shared_->funcSigs.length();
         for (uint32_t i = 0; i < shared_->imports.length(); i++) {
             if (!addImport(*shared_->imports[i].sig, shared_->imports[i].globalDataOffset))
                 return false;
         }
     }
 
     return true;
 }
@@ -184,29 +183,23 @@ ModuleGenerator::finishTask(IonCompileTa
 
     // Merge the compiled results into the whole-module masm.
     DebugOnly<size_t> sizeBefore = masm_.size();
     if (!masm_.asmMergeWith(results.masm()))
         return false;
     MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
 
     // Add the CodeRange for this function.
-    CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func.name());
-    if (!funcName)
-        return false;
-    uint32_t nameIndex = module_->funcNames.length();
-    if (!module_->funcNames.emplaceBack(Move(funcName)))
-        return false;
-    if (!module_->codeRanges.emplaceBack(nameIndex, func.line(), results.offsets()))
+    if (!module_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
         return false;
 
     // Keep a record of slow functions for printing in the final console message.
     unsigned totalTime = func.generateTime() + results.compileTime();
     if (totalTime >= SlowFunction::msThreshold) {
-        if (!slowFuncs_.emplaceBack(func.name(), totalTime, func.line(), func.column()))
+        if (!slowFuncs_.emplaceBack(func.index(), totalTime, func.lineOrBytecode()))
             return false;
     }
 
     freeTasks_.infallibleAppend(task);
     return true;
 }
 
 bool
@@ -282,20 +275,20 @@ ModuleGenerator::sig(uint32_t index) con
     MOZ_ASSERT(index < numSigs_);
     return shared_->sigs[index];
 }
 
 bool
 ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex)
 {
     MOZ_ASSERT(module_->kind == ModuleKind::AsmJS);
-    MOZ_ASSERT(funcIndex == numFuncSigs_);
+    MOZ_ASSERT(funcIndex == module_->numFuncs);
     MOZ_ASSERT(!shared_->funcSigs[funcIndex]);
 
-    numFuncSigs_++;
+    module_->numFuncs++;
     shared_->funcSigs[funcIndex] = &shared_->sigs[sigIndex];
     return true;
 }
 
 const DeclaredSig&
 ModuleGenerator::funcSig(uint32_t funcIndex) const
 {
     MOZ_ASSERT(shared_->funcSigs[funcIndex]);
@@ -425,18 +418,17 @@ ModuleGenerator::startFuncDefs()
     for (size_t i = 0; i < numTasks; i++)
         freeTasks_.infallibleAppend(&tasks_[i]);
 
     MOZ_ASSERT(startedFuncDefs());
     return true;
 }
 
 bool
-ModuleGenerator::startFuncDef(PropertyName* name, unsigned line, unsigned column,
-                              FunctionGenerator* fg)
+ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
 {
     MOZ_ASSERT(startedFuncDefs());
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(!finishedFuncs_);
 
     if (freeTasks_.empty() && !finishOutstandingTask())
         return false;
 
@@ -446,39 +438,35 @@ ModuleGenerator::startFuncDef(PropertyNa
     if (fg->bytecode_) {
         fg->bytecode_->clear();
     } else {
         fg->bytecode_ = MakeUnique<Bytecode>();
         if (!fg->bytecode_)
             return false;
     }
 
-    fg->name_= name;
-    fg->line_ = line;
-    fg->column_ = column;
+    fg->lineOrBytecode_ = lineOrBytecode;
     fg->m_ = this;
     fg->task_ = task;
     activeFunc_ = fg;
     return true;
 }
 
 bool
 ModuleGenerator::finishFuncDef(uint32_t funcIndex, unsigned generateTime, FunctionGenerator* fg)
 {
     MOZ_ASSERT(activeFunc_ == fg);
 
     UniqueFuncBytecode func =
-        js::MakeUnique<FuncBytecode>(fg->name_,
-                                     fg->line_,
-                                     fg->column_,
-                                     Move(fg->callSourceCoords_),
-                                     funcIndex,
+        js::MakeUnique<FuncBytecode>(funcIndex,
                                      funcSig(funcIndex),
                                      Move(fg->bytecode_),
                                      Move(fg->localVars_),
+                                     fg->lineOrBytecode_,
+                                     Move(fg->callSourceCoords_),
                                      generateTime);
     if (!func)
         return false;
 
     fg->task_->init(Move(func));
 
     if (parallel_) {
         if (!StartOffThreadWasmCompile(cx_, fg->task_))
@@ -602,25 +590,27 @@ ModuleGenerator::defineOutOfBoundsStub(O
     MOZ_ASSERT(finishedFuncs_);
     link_->pod.outOfBoundsOffset = offsets.begin;
     return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
 }
 
 bool
 ModuleGenerator::finish(HeapUsage heapUsage,
                         CacheableChars filename,
+                        CacheableCharsVector&& prettyFuncNames,
                         UniqueModuleData* module,
                         UniqueStaticLinkData* linkData,
                         SlowFunctionVector* slowFuncs)
 {
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(finishedFuncs_);
 
     module_->heapUsage = heapUsage;
     module_->filename = Move(filename);
+    module_->prettyFuncNames = Move(prettyFuncNames);
 
     if (!GenerateStubs(*this, UsesHeap(heapUsage)))
         return false;
 
     masm_.finish();
     if (masm_.oom())
         return false;
 
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -30,26 +30,25 @@ namespace wasm {
 class FunctionGenerator;
 typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
 
 // A slow function describes a function that took longer than msThreshold to
 // validate and compile.
 
 struct SlowFunction
 {
-    SlowFunction(PropertyName* name, unsigned ms, unsigned line, unsigned column)
-     : name(name), ms(ms), line(line), column(column)
+    SlowFunction(uint32_t index, unsigned ms, unsigned lineOrBytecode)
+     : index(index), ms(ms), lineOrBytecode(lineOrBytecode)
     {}
 
     static const unsigned msThreshold = 250;
 
-    PropertyName* name;
+    uint32_t index;
     unsigned ms;
-    unsigned line;
-    unsigned column;
+    unsigned lineOrBytecode;
 };
 typedef Vector<SlowFunction> SlowFunctionVector;
 
 // The ModuleGeneratorData holds all the state shared between the
 // ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData is
 // encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
 // present a race-free interface to the code in each thread assuming any given
 // element is initialized by the ModuleGenerator thread before an index to that
@@ -133,17 +132,16 @@ class MOZ_STACK_CLASS ModuleGenerator
     // Data handed back to the caller in finish()
     UniqueModuleData                module_;
     UniqueStaticLinkData            link_;
     SlowFunctionVector              slowFuncs_;
 
     // Data scoped to the ModuleGenerator's lifetime
     UniqueModuleGeneratorData       shared_;
     uint32_t                        numSigs_;
-    uint32_t                        numFuncSigs_;
     LifoAlloc                       lifo_;
     jit::TempAllocator              alloc_;
     jit::MacroAssembler             masm_;
     Uint32Vector                    funcEntryOffsets_;
     Uint32Vector                    exportFuncIndices_;
     FuncIndexMap                    funcIndexToExport_;
 
     // Parallel compilation
@@ -155,16 +153,17 @@ class MOZ_STACK_CLASS ModuleGenerator
 
     // Assertions
     DebugOnly<FunctionGenerator*>   activeFunc_;
     DebugOnly<bool>                 finishedFuncs_;
 
     bool finishOutstandingTask();
     bool finishTask(IonCompileTask* task);
     bool addImport(const Sig& sig, uint32_t globalDataOffset);
+    bool startedFuncDefs() const { return !!threadView_; }
 
   public:
     explicit ModuleGenerator(ExclusiveContext* cx);
     ~ModuleGenerator();
 
     bool init(UniqueModuleGeneratorData shared, ModuleKind = ModuleKind::Wasm);
 
     CompileArgs args() const { return module_->compileArgs; }
@@ -178,17 +177,17 @@ class MOZ_STACK_CLASS ModuleGenerator
 
     // Signatures:
     void initSig(uint32_t sigIndex, Sig&& sig);
     uint32_t numSigs() const { return numSigs_; }
     const DeclaredSig& sig(uint32_t sigIndex) const;
 
     // Function declarations:
     bool initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
-    uint32_t numFuncSigs() const { return numFuncSigs_; }
+    uint32_t numFuncSigs() const { return module_->numFuncs; }
     const DeclaredSig& funcSig(uint32_t funcIndex) const;
 
     // Imports:
     bool initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset);
     uint32_t numImports() const;
     const ModuleImportGeneratorData& import(uint32_t index) const;
     bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
 
@@ -196,18 +195,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool declareExport(uint32_t funcIndex, uint32_t* exportIndex);
     uint32_t numExports() const;
     uint32_t exportFuncIndex(uint32_t index) const;
     const Sig& exportSig(uint32_t index) const;
     bool defineExport(uint32_t index, Offsets offsets);
 
     // Function definitions:
     bool startFuncDefs();
-    bool startedFuncDefs() const { return !!threadView_; }
-    bool startFuncDef(PropertyName* name, unsigned line, unsigned column, FunctionGenerator* fg);
+    bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     bool finishFuncDef(uint32_t funcIndex, unsigned generateTime, FunctionGenerator* fg);
     bool finishFuncDefs();
 
     // Function-pointer tables:
     bool declareFuncPtrTable(uint32_t numElems, uint32_t* index);
     uint32_t funcPtrTableGlobalDataOffset(uint32_t index) const;
     void defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elemFuncIndices);
 
@@ -217,16 +215,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool defineAsyncInterruptStub(Offsets offsets);
     bool defineOutOfBoundsStub(Offsets offsets);
 
     // Return a ModuleData object which may be used to construct a Module, the
     // StaticLinkData required to call Module::staticallyLink, and the list of
     // functions that took a long time to compile.
     bool finish(HeapUsage heapUsage,
                 CacheableChars filename,
+                CacheableCharsVector&& prettyFuncNames,
                 UniqueModuleData* module,
                 UniqueStaticLinkData* staticLinkData,
                 SlowFunctionVector* slowFuncs);
 };
 
 // A FunctionGenerator encapsulates the generation of a single function body.
 // ModuleGenerator::startFunc must be called after construction and before doing
 // anything else. After the body is complete, ModuleGenerator::finishFunc must
@@ -241,29 +240,21 @@ class MOZ_STACK_CLASS FunctionGenerator
     IonCompileTask*    task_;
 
     // Data created during function generation, then handed over to the
     // FuncBytecode in ModuleGenerator::finishFunc().
     UniqueBytecode     bytecode_;
     SourceCoordsVector callSourceCoords_;
     ValTypeVector      localVars_;
 
-    // Note: this unrooted field assumes AutoKeepAtoms via TokenStream via
-    // asm.js compilation.
-    PropertyName* name_;
-    unsigned line_;
-    unsigned column_;
+    uint32_t lineOrBytecode_;
 
   public:
     FunctionGenerator()
-      : m_(nullptr),
-        task_(nullptr),
-        name_(nullptr),
-        line_(0),
-        column_(0)
+      : m_(nullptr), task_(nullptr), lineOrBytecode_(0)
     {}
 
     Bytecode& bytecode() const {
         return *bytecode_;
     }
     bool addSourceCoords(size_t byteOffset, uint32_t line, uint32_t column) {
         SourceCoords sc = { byteOffset, line, column };
         return callSourceCoords_.append(sc);
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -346,47 +346,47 @@ Import::clone(JSContext* cx, Import* out
 
 size_t
 Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return SizeOfSigExcludingThis(sig_, mallocSizeOf);
 }
 
 CodeRange::CodeRange(Kind kind, Offsets offsets)
-  : nameIndex_(0),
-    lineNumber_(0),
+  : funcIndex_(0),
+    funcLineOrBytecode_(0),
     begin_(offsets.begin),
     profilingReturn_(0),
     end_(offsets.end)
 {
     PodZero(&u);  // zero padding for Valgrind
     u.kind_ = kind;
 
     MOZ_ASSERT(begin_ <= end_);
     MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline);
 }
 
 CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets)
-  : nameIndex_(0),
-    lineNumber_(0),
+  : funcIndex_(0),
+    funcLineOrBytecode_(0),
     begin_(offsets.begin),
     profilingReturn_(offsets.profilingReturn),
     end_(offsets.end)
 {
     PodZero(&u);  // zero padding for Valgrind
     u.kind_ = kind;
 
     MOZ_ASSERT(begin_ < profilingReturn_);
     MOZ_ASSERT(profilingReturn_ < end_);
     MOZ_ASSERT(u.kind_ == ImportJitExit || u.kind_ == ImportInterpExit || u.kind_ == Interrupt);
 }
 
-CodeRange::CodeRange(uint32_t nameIndex, uint32_t lineNumber, FuncOffsets offsets)
-  : nameIndex_(nameIndex),
-    lineNumber_(lineNumber)
+CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets)
+  : funcIndex_(funcIndex),
+    funcLineOrBytecode_(funcLineOrBytecode)
 {
     PodZero(&u);  // zero padding for Valgrind
     u.kind_ = Function;
 
     MOZ_ASSERT(offsets.nonProfilingEntry - offsets.begin <= UINT8_MAX);
     begin_ = offsets.begin;
     u.func.beginToEntry_ = offsets.nonProfilingEntry - begin_;
 
@@ -504,31 +504,31 @@ ModuleData::serializedSize() const
 {
     return sizeof(pod()) +
            codeBytes +
            SerializedVectorSize(imports) +
            SerializedVectorSize(exports) +
            SerializedPodVectorSize(heapAccesses) +
            SerializedPodVectorSize(codeRanges) +
            SerializedPodVectorSize(callSites) +
-           SerializedVectorSize(funcNames) +
+           SerializedVectorSize(prettyFuncNames) +
            filename.serializedSize();
 }
 
 uint8_t*
 ModuleData::serialize(uint8_t* cursor) const
 {
     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     cursor = WriteBytes(cursor, code.get(), codeBytes);
     cursor = SerializeVector(cursor, imports);
     cursor = SerializeVector(cursor, exports);
     cursor = SerializePodVector(cursor, heapAccesses);
     cursor = SerializePodVector(cursor, codeRanges);
     cursor = SerializePodVector(cursor, callSites);
-    cursor = SerializeVector(cursor, funcNames);
+    cursor = SerializeVector(cursor, prettyFuncNames);
     cursor = filename.serialize(cursor);
     return cursor;
 }
 
 /* static */ const uint8_t*
 ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
 {
     cursor = ReadBytes(cursor, &pod(), sizeof(pod()));
@@ -538,17 +538,17 @@ ModuleData::deserialize(ExclusiveContext
         return nullptr;
     cursor = ReadBytes(cursor, code.get(), codeBytes);
 
     (cursor = DeserializeVector(cx, cursor, &imports)) &&
     (cursor = DeserializeVector(cx, cursor, &exports)) &&
     (cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
     (cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
     (cursor = DeserializePodVector(cx, cursor, &callSites)) &&
-    (cursor = DeserializeVector(cx, cursor, &funcNames)) &&
+    (cursor = DeserializeVector(cx, cursor, &prettyFuncNames)) &&
     (cursor = filename.deserialize(cx, cursor));
     return cursor;
 }
 
 bool
 ModuleData::clone(JSContext* cx, ModuleData* out) const
 {
     out->pod() = pod();
@@ -558,30 +558,30 @@ ModuleData::clone(JSContext* cx, ModuleD
         return false;
     memcpy(out->code.get(), code.get(), codeBytes);
 
     return CloneVector(cx, imports, &out->imports) &&
            CloneVector(cx, exports, &out->exports) &&
            ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
            ClonePodVector(cx, codeRanges, &out->codeRanges) &&
            ClonePodVector(cx, callSites, &out->callSites) &&
-           CloneVector(cx, funcNames, &out->funcNames) &&
+           CloneVector(cx, prettyFuncNames, &out->prettyFuncNames) &&
            filename.clone(cx, &out->filename);
 }
 
 size_t
 ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     // Module::addSizeOfMisc takes care of code and global memory.
     return SizeOfVectorExcludingThis(imports, mallocSizeOf) +
            SizeOfVectorExcludingThis(exports, mallocSizeOf) +
            heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
            callSites.sizeOfExcludingThis(mallocSizeOf) +
-           funcNames.sizeOfExcludingThis(mallocSizeOf) +
+           prettyFuncNames.sizeOfExcludingThis(mallocSizeOf) +
            filename.sizeOfExcludingThis(mallocSizeOf);
 }
 
 uint8_t*
 Module::rawHeapPtr() const
 {
     return const_cast<Module*>(this)->rawHeapPtr();
 }
@@ -675,96 +675,115 @@ Module::despecializeFromHeap(ArrayBuffer
             X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
     }
 #endif
 
     heap_ = nullptr;
     rawHeapPtr() = nullptr;
 }
 
-void
+bool
 Module::sendCodeRangesToProfiler(JSContext* cx)
 {
+    bool enabled = false;
 #ifdef JS_ION_PERF
-    if (PerfFuncEnabled()) {
-        for (const CodeRange& codeRange : module_->codeRanges) {
-            if (!codeRange.isFunction())
-                continue;
+    enabled |= PerfFuncEnabled();
+#endif
+#ifdef MOZ_VTUNE
+    enabled |= IsVTuneProfilingActive();
+#endif
+    if (!enabled)
+        return true;
+
+    for (const CodeRange& codeRange : module_->codeRanges) {
+        if (!codeRange.isFunction())
+            continue;
 
-            uintptr_t start = uintptr_t(code() + codeRange.begin());
-            uintptr_t end = uintptr_t(code() + codeRange.end());
-            uintptr_t size = end - start;
+        uintptr_t start = uintptr_t(code() + codeRange.begin());
+        uintptr_t end = uintptr_t(code() + codeRange.end());
+        uintptr_t size = end - start;
+
+        UniqueChars owner;
+        const char* name = getFuncName(cx, codeRange.funcIndex(), &owner);
+        if (!name)
+            return false;
+
+        // Avoid "unused" warnings
+        (void)start;
+        (void)size;
+        (void)name;
+
+#ifdef JS_ION_PERF
+        if (PerfFuncEnabled()) {
             const char* file = module_->filename.get();
-            unsigned line = codeRange.funcLineNumber();
+            unsigned line = codeRange.funcLineOrBytecode();
             unsigned column = 0;
-            const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
-
             writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name);
         }
-    }
 #endif
 #ifdef MOZ_VTUNE
-    if (IsVTuneProfilingActive()) {
-        for (const CodeRange& codeRange : module_->codeRanges) {
-            if (!codeRange.isFunction())
-                continue;
-
-            uintptr_t start = uintptr_t(code() + codeRange.begin());
-            uintptr_t end = uintptr_t(code() + codeRange.end());
-            uintptr_t size = end - start;
-            const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
-
+        if (IsVTuneProfilingActive()) {
             unsigned method_id = iJIT_GetNewMethodID();
             if (method_id == 0)
-                return;
+                return true;
             iJIT_Method_Load method;
             method.method_id = method_id;
             method.method_name = const_cast<char*>(name);
             method.method_load_address = (void*)start;
             method.method_size = size;
             method.line_number_size = 0;
             method.line_number_table = nullptr;
             method.class_id = 0;
             method.class_file_name = nullptr;
             method.source_file_name = nullptr;
             iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&method);
         }
+#endif
     }
-#endif
+
+    return true;
 }
 
 bool
 Module::setProfilingEnabled(JSContext* cx, bool enabled)
 {
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(!activation());
 
     if (profilingEnabled_ == enabled)
         return true;
 
     // When enabled, generate profiling labels for every name in funcNames_
     // that is the name of some Function CodeRange. This involves malloc() so
     // do it now since, once we start sampling, we'll be in a signal-handing
     // context where we cannot malloc.
     if (enabled) {
-        if (!funcLabels_.resize(module_->funcNames.length())) {
+        if (!funcLabels_.resize(module_->numFuncs)) {
             ReportOutOfMemory(cx);
             return false;
         }
         for (const CodeRange& codeRange : module_->codeRanges) {
             if (!codeRange.isFunction())
                 continue;
-            unsigned lineno = codeRange.funcLineNumber();
-            const char* name = module_->funcNames[codeRange.funcNameIndex()].get();
-            UniqueChars label(JS_smprintf("%s (%s:%u)", name, module_->filename.get(), lineno));
+
+            UniqueChars owner;
+            const char* funcName = getFuncName(cx, codeRange.funcIndex(), &owner);
+            if (!funcName)
+                return false;
+
+            UniqueChars label(JS_smprintf("%s (%s:%u)",
+                                          funcName,
+                                          module_->filename.get(),
+                                          codeRange.funcLineOrBytecode()));
             if (!label) {
                 ReportOutOfMemory(cx);
                 return false;
             }
-            funcLabels_[codeRange.funcNameIndex()] = Move(label);
+
+            funcLabels_[codeRange.funcIndex()] = Move(label);
         }
     } else {
         funcLabels_.clear();
     }
 
     // Patch callsites and returns to execute profiling prologues/epilogues.
     {
         AutoWritableJitCode awjc(cx->runtime(), code(), codeBytes());
@@ -1077,18 +1096,17 @@ Module::dynamicallyLink(JSContext* cx, H
         specializeToHeap(heap);
 
     // See AllocateCode comment above.
     if (!ExecutableAllocator::makeExecutable(code(), codeBytes())) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    sendCodeRangesToProfiler(cx);
-    return true;
+    return sendCodeRangesToProfiler(cx);
 }
 
 static bool
 WasmCall(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedFunction callee(cx, &args.callee().as<JSFunction>());
 
@@ -1404,16 +1422,38 @@ Module::callImport(JSContext* cx, uint32
         return false;
 
     exit.code = jitExitCode;
     exit.baselineScript = script->baselineScript();
     return true;
 }
 
 const char*
+Module::prettyFuncName(uint32_t funcIndex) const
+{
+    return module_->prettyFuncNames[funcIndex].get();
+}
+
+const char*
+Module::getFuncName(JSContext* cx, uint32_t funcIndex, UniqueChars* owner) const
+{
+    if (!module_->prettyFuncNames.empty())
+        return prettyFuncName(funcIndex);
+
+    char* chars = JS_smprintf("wasm-function[%u]", funcIndex);
+    if (!chars) {
+        ReportOutOfMemory(cx);
+        return nullptr;
+    }
+
+    owner->reset(chars);
+    return chars;
+}
+
+const char*
 Module::profilingLabel(uint32_t funcIndex) const
 {
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(profilingEnabled_);
     return funcLabels_[funcIndex].get();
 }
 
 const Class WasmModuleObject::class_ = {
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -192,18 +192,18 @@ typedef Vector<Import, 0, SystemAllocPol
 
 // A CodeRange describes a single contiguous range of code within a wasm
 // module's code segment. A CodeRange describes what the code does and, for
 // function bodies, the name and source coordinates of the function.
 
 class CodeRange
 {
     // All fields are treated as cacheable POD:
-    uint32_t nameIndex_;
-    uint32_t lineNumber_;
+    uint32_t funcIndex_;
+    uint32_t funcLineOrBytecode_;
     uint32_t begin_;
     uint32_t profilingReturn_;
     uint32_t end_;
     union {
         struct {
             uint8_t kind_;
             uint8_t beginToEntry_;
             uint8_t profilingJumpToProfilingReturn_;
@@ -215,17 +215,17 @@ class CodeRange
     void assertValid();
 
   public:
     enum Kind { Function, Entry, ImportJitExit, ImportInterpExit, Interrupt, Inline };
 
     CodeRange() = default;
     CodeRange(Kind kind, Offsets offsets);
     CodeRange(Kind kind, ProfilingOffsets offsets);
-    CodeRange(uint32_t nameIndex, uint32_t lineNumber, FuncOffsets offsets);
+    CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets);
 
     // All CodeRanges have a begin and end.
 
     uint32_t begin() const {
         return begin_;
     }
     uint32_t end() const {
         return end_;
@@ -260,23 +260,23 @@ class CodeRange
     uint32_t functionProfilingJump() const {
         MOZ_ASSERT(isFunction());
         return profilingReturn_ - u.func.profilingJumpToProfilingReturn_;
     }
     uint32_t funcProfilingEpilogue() const {
         MOZ_ASSERT(isFunction());
         return profilingReturn_ - u.func.profilingEpilogueToProfilingReturn_;
     }
-    uint32_t funcNameIndex() const {
+    uint32_t funcIndex() const {
         MOZ_ASSERT(isFunction());
-        return nameIndex_;
+        return funcIndex_;
     }
-    uint32_t funcLineNumber() const {
+    uint32_t funcLineOrBytecode() const {
         MOZ_ASSERT(isFunction());
-        return lineNumber_;
+        return funcLineOrBytecode_;
     }
 
     // A sorted array of CodeRanges can be looked up via BinarySearch and PC.
 
     struct PC {
         size_t offset;
         explicit PC(size_t offset) : offset(offset) {}
         bool operator==(const CodeRange& rhs) const {
@@ -361,16 +361,17 @@ enum ModuleKind
 // ModuleCacheablePod holds the trivially-memcpy()able serializable portion of
 // ModuleData.
 
 struct ModuleCacheablePod
 {
     uint32_t              functionBytes;
     uint32_t              codeBytes;
     uint32_t              globalBytes;
+    uint32_t              numFuncs;
     ModuleKind            kind;
     HeapUsage             heapUsage;
     CompileArgs           compileArgs;
 
     uint32_t totalBytes() const { return codeBytes + globalBytes; }
 };
 
 // ModuleData holds the guts of a Module. ModuleData is mutably built up by
@@ -384,17 +385,17 @@ struct ModuleData : ModuleCacheablePod
     const ModuleCacheablePod& pod() const { return *this; }
 
     UniqueCodePtr         code;
     ImportVector          imports;
     ExportVector          exports;
     HeapAccessVector      heapAccesses;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
-    CacheableCharsVector  funcNames;
+    CacheableCharsVector  prettyFuncNames;
     CacheableChars        filename;
     bool                  loadedFromCache;
 
     WASM_DECLARE_SERIALIZABLE(ModuleData);
 };
 
 typedef UniquePtr<ModuleData> UniqueModuleData;
 
@@ -461,17 +462,17 @@ class Module
     bool                         profilingEnabled_;
     FuncLabelVector              funcLabels_;
 
     uint8_t* rawHeapPtr() const;
     uint8_t*& rawHeapPtr();
     WasmActivation*& activation();
     void specializeToHeap(ArrayBufferObjectMaybeShared* heap);
     void despecializeFromHeap(ArrayBufferObjectMaybeShared* heap);
-    void sendCodeRangesToProfiler(JSContext* cx);
+    bool sendCodeRangesToProfiler(JSContext* cx);
     MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled);
     ImportExit& importToExit(const Import& import);
 
     friend class js::WasmActivation;
 
   protected:
     const ModuleData& base() const { return *module_; }
     bool clone(JSContext* cx, const StaticLinkData& link, Module* clone) const;
@@ -491,17 +492,16 @@ class Module
     uint8_t* globalData() const { return code() + module_->codeBytes; }
     uint32_t globalBytes() const { return module_->globalBytes; }
     HeapUsage heapUsage() const { return module_->heapUsage; }
     bool usesHeap() const { return UsesHeap(module_->heapUsage); }
     bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
     CompileArgs compileArgs() const { return module_->compileArgs; }
     const ImportVector& imports() const { return module_->imports; }
     const ExportVector& exports() const { return module_->exports; }
-    const char* functionName(uint32_t i) const { return module_->funcNames[i].get(); }
     const char* filename() const { return module_->filename.get(); }
     bool loadedFromCache() const { return module_->loadedFromCache; }
     bool staticallyLinked() const { return staticallyLinked_; }
     bool dynamicallyLinked() const { return dynamicallyLinked_; }
 
     // Some wasm::Module's have the most-derived type AsmJSModule. The
     // AsmJSModule stores the extra metadata necessary to implement asm.js (JS)
     // semantics. The asAsmJS() member may be used as a checked downcast when
@@ -568,16 +568,23 @@ class Module
 
     // At runtime, when $pc is in wasm function code (containsFunctionPC($pc)),
     // $pc may be moved abruptly to interrupt() or outOfBounds() by a signal
     // handler or SetContext() from another thread.
 
     uint8_t* interrupt() const { MOZ_ASSERT(staticallyLinked_); return interrupt_; }
     uint8_t* outOfBounds() const { MOZ_ASSERT(staticallyLinked_); return outOfBounds_; }
 
+    // Every function has an associated display atom which is either the pretty
+    // name given by the asm.js function name or wasm symbols or something
+    // generated from the function index.
+
+    const char* prettyFuncName(uint32_t funcIndex) const;
+    const char* getFuncName(JSContext* cx, uint32_t funcIndex, UniqueChars* owner) const;
+
     // Each Module has a profilingEnabled state which is updated to match
     // SPSProfiler::enabled() on the next Module::callExport when there are no
     // frames from the Module on the stack. The ProfilingFrameIterator only
     // shows frames for Module activations that have profilingEnabled.
 
     bool profilingEnabled() const { return profilingEnabled_; }
     const char* profilingLabel(uint32_t funcIndex) const;
 };