Bug 1284155 - Baldr: refactor/rename exports to be more symmetric with imports (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Wed, 13 Jul 2016 12:34:44 -0500
changeset 344961 9111bfb505326cbd1a861719519ac1521de8d883
parent 344960 4957d2668f55f0a7bb4dafb4b3be4e8fadee4197
child 344962 81e2f8a3193ecb767569178e6c332356cb756809
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1284155
milestone50.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 1284155 - Baldr: refactor/rename exports to be more symmetric with imports (r=bbouvier) MozReview-Commit-ID: F5VNVHiXwtY
js/src/asmjs/AsmJS.cpp
js/src/asmjs/WasmCode.cpp
js/src/asmjs/WasmCode.h
js/src/asmjs/WasmCompile.cpp
js/src/asmjs/WasmGenerator.cpp
js/src/asmjs/WasmGenerator.h
js/src/asmjs/WasmInstance.cpp
js/src/asmjs/WasmInstance.h
js/src/asmjs/WasmModule.cpp
js/src/asmjs/WasmModule.h
js/src/asmjs/WasmStubs.cpp
js/src/asmjs/WasmStubs.h
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -2051,25 +2051,25 @@ class MOZ_STACK_CLASS ModuleValidator
         if (maybeField)
             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
         else
             fieldChars = DuplicateString("");
         if (!fieldChars)
             return false;
 
         // Declare which function is exported which gives us an index into the
-        // module ExportVector.
-        uint32_t exportIndex;
-        if (!mg_.declareExport(Move(fieldChars), func.index(), &exportIndex))
+        // module FuncExportVector.
+        uint32_t funcExportIndex;
+        if (!mg_.declareFuncExport(Move(fieldChars), func.index(), &funcExportIndex))
             return false;
 
         // The exported function might have already been exported in which case
         // the index will refer into the range of AsmJSExports.
-        MOZ_ASSERT(exportIndex <= asmJSMetadata_->asmJSExports.length());
-        return exportIndex < asmJSMetadata_->asmJSExports.length() ||
+        MOZ_ASSERT(funcExportIndex <= asmJSMetadata_->asmJSExports.length());
+        return funcExportIndex < asmJSMetadata_->asmJSExports.length() ||
                asmJSMetadata_->asmJSExports.emplaceBack(func.srcBegin() - asmJSMetadata_->srcStart,
                                                         func.srcEnd() - asmJSMetadata_->srcStart);
     }
     bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
         uint32_t sigIndex;
         if (!declareSig(Move(sig), &sigIndex))
             return false;
         uint32_t funcIndex = numFunctions();
--- a/js/src/asmjs/WasmCode.cpp
+++ b/js/src/asmjs/WasmCode.cpp
@@ -279,40 +279,40 @@ DeserializeSig(const uint8_t* cursor, Si
 
 static size_t
 SizeOfSigExcludingThis(const Sig& sig, MallocSizeOf mallocSizeOf)
 {
     return sig.args().sizeOfExcludingThis(mallocSizeOf);
 }
 
 size_t
-Export::serializedSize() const
+FuncExport::serializedSize() const
 {
     return SerializedSigSize(sig_) +
            sizeof(pod);
 }
 
 uint8_t*
-Export::serialize(uint8_t* cursor) const
+FuncExport::serialize(uint8_t* cursor) const
 {
     cursor = SerializeSig(cursor, sig_);
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     return cursor;
 }
 
 const uint8_t*
-Export::deserialize(const uint8_t* cursor)
+FuncExport::deserialize(const uint8_t* cursor)
 {
     (cursor = DeserializeSig(cursor, &sig_)) &&
     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 
 size_t
-Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+FuncExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return SizeOfSigExcludingThis(sig_, mallocSizeOf);
 }
 
 size_t
 FuncImport::serializedSize() const
 {
     return SerializedSigSize(sig_) +
@@ -444,34 +444,34 @@ CacheableChars::sizeOfExcludingThis(Mall
     return mallocSizeOf(get());
 }
 
 size_t
 Metadata::serializedSize() const
 {
     return sizeof(pod()) +
            SerializedVectorSize(funcImports) +
-           SerializedVectorSize(exports) +
+           SerializedVectorSize(funcExports) +
            SerializedPodVectorSize(tables) +
            SerializedPodVectorSize(memoryAccesses) +
            SerializedPodVectorSize(boundsChecks) +
            SerializedPodVectorSize(codeRanges) +
            SerializedPodVectorSize(callSites) +
            SerializedPodVectorSize(callThunks) +
            SerializedPodVectorSize(funcNames) +
            filename.serializedSize() +
            assumptions.serializedSize();
 }
 
 uint8_t*
 Metadata::serialize(uint8_t* cursor) const
 {
     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     cursor = SerializeVector(cursor, funcImports);
-    cursor = SerializeVector(cursor, exports);
+    cursor = SerializeVector(cursor, funcExports);
     cursor = SerializePodVector(cursor, tables);
     cursor = SerializePodVector(cursor, memoryAccesses);
     cursor = SerializePodVector(cursor, boundsChecks);
     cursor = SerializePodVector(cursor, codeRanges);
     cursor = SerializePodVector(cursor, callSites);
     cursor = SerializePodVector(cursor, callThunks);
     cursor = SerializePodVector(cursor, funcNames);
     cursor = filename.serialize(cursor);
@@ -479,34 +479,34 @@ Metadata::serialize(uint8_t* cursor) con
     return cursor;
 }
 
 /* static */ const uint8_t*
 Metadata::deserialize(const uint8_t* cursor)
 {
     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
     (cursor = DeserializeVector(cursor, &funcImports)) &&
-    (cursor = DeserializeVector(cursor, &exports)) &&
+    (cursor = DeserializeVector(cursor, &funcExports)) &&
     (cursor = DeserializePodVector(cursor, &tables)) &&
     (cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
     (cursor = DeserializePodVector(cursor, &boundsChecks)) &&
     (cursor = DeserializePodVector(cursor, &codeRanges)) &&
     (cursor = DeserializePodVector(cursor, &callSites)) &&
     (cursor = DeserializePodVector(cursor, &callThunks)) &&
     (cursor = DeserializePodVector(cursor, &funcNames)) &&
     (cursor = filename.deserialize(cursor)) &&
     (cursor = assumptions.deserialize(cursor));
     return cursor;
 }
 
 size_t
 Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return SizeOfVectorExcludingThis(funcImports, mallocSizeOf) +
-           SizeOfVectorExcludingThis(exports, mallocSizeOf) +
+           SizeOfVectorExcludingThis(funcExports, mallocSizeOf) +
            tables.sizeOfExcludingThis(mallocSizeOf) +
            memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
            boundsChecks.sizeOfExcludingThis(mallocSizeOf) +
            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
            callSites.sizeOfExcludingThis(mallocSizeOf) +
            callThunks.sizeOfExcludingThis(mallocSizeOf) +
            funcNames.sizeOfExcludingThis(mallocSizeOf) +
            filename.sizeOfExcludingThis(mallocSizeOf) +
--- a/js/src/asmjs/WasmCode.h
+++ b/js/src/asmjs/WasmCode.h
@@ -112,30 +112,30 @@ struct ShareableBytes : ShareableBase<Sh
     const uint8_t* begin() const { return bytes.begin(); }
     const uint8_t* end() const { return bytes.end(); }
     bool append(const uint8_t *p, uint32_t ct) { return bytes.append(p, ct); }
 };
 
 typedef RefPtr<ShareableBytes> MutableBytes;
 typedef RefPtr<const ShareableBytes> SharedBytes;
 
-// An Export represents a single function inside a wasm Module that has been
+// A FuncExport represents a single function inside a wasm Module that has been
 // exported one or more times.
 
-class Export
+class FuncExport
 {
     Sig sig_;
     struct CacheablePod {
         uint32_t funcIndex_;
         uint32_t stubOffset_;
     } pod;
 
   public:
-    Export() = default;
-    explicit Export(Sig&& sig, uint32_t funcIndex)
+    FuncExport() = default;
+    explicit FuncExport(Sig&& sig, uint32_t funcIndex)
       : sig_(Move(sig))
     {
         pod.funcIndex_ = funcIndex;
         pod.stubOffset_ = UINT32_MAX;
     }
     void initStubOffset(uint32_t stubOffset) {
         MOZ_ASSERT(pod.stubOffset_ == UINT32_MAX);
         pod.stubOffset_ = stubOffset;
@@ -147,20 +147,20 @@ class Export
     uint32_t funcIndex() const {
         return pod.funcIndex_;
     }
     uint32_t stubOffset() const {
         MOZ_ASSERT(pod.stubOffset_ != UINT32_MAX);
         return pod.stubOffset_;
     }
 
-    WASM_DECLARE_SERIALIZABLE(Export)
+    WASM_DECLARE_SERIALIZABLE(FuncExport)
 };
 
-typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
+typedef Vector<FuncExport, 0, SystemAllocPolicy> FuncExportVector;
 
 // An FuncImport contains the runtime metadata needed to implement a call to an
 // imported function. Each function import has two call stubs: an optimized path
 // into JIT code and a slow path into the generic C++ js::Invoke and these
 // offsets of these stubs are stored so that function-import callsites can be
 // dynamically patched at runtime.
 
 class FuncImport
@@ -410,35 +410,58 @@ typedef Vector<char16_t, 64> TwoByteName
 
 // Metadata holds all the data that is needed to describe compiled wasm code
 // at runtime (as opposed to data that is only used to statically link or
 // instantiate a module).
 //
 // Metadata is built incrementally by ModuleGenerator and then shared immutably
 // between modules.
 
-struct MetadataCacheablePod
+
+class MetadataCacheablePod
 {
+    static const uint32_t NO_START_FUNCTION = UINT32_MAX;
+    static_assert(NO_START_FUNCTION > MaxFuncs, "sentinel value");
+
+    uint32_t              startFuncExportIndex_;
+
+  public:
     ModuleKind            kind;
     MemoryUsage           memoryUsage;
     uint32_t              minMemoryLength;
     uint32_t              maxMemoryLength;
 
-    MetadataCacheablePod() { mozilla::PodZero(this); }
+    MetadataCacheablePod() {
+        mozilla::PodZero(this);
+        startFuncExportIndex_ = NO_START_FUNCTION;
+    }
+
+    bool hasStartFunction() const {
+        return startFuncExportIndex_ != NO_START_FUNCTION;
+    }
+    void initStartFuncExportIndex(uint32_t i) {
+        MOZ_ASSERT(!hasStartFunction());
+        startFuncExportIndex_ = i;
+        MOZ_ASSERT(hasStartFunction());
+    }
+    uint32_t startFuncExportIndex() const {
+        MOZ_ASSERT(hasStartFunction());
+        return startFuncExportIndex_;
+    }
 };
 
 struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
 {
     virtual ~Metadata() {}
 
     MetadataCacheablePod& pod() { return *this; }
     const MetadataCacheablePod& pod() const { return *this; }
 
     FuncImportVector      funcImports;
-    ExportVector          exports;
+    FuncExportVector      funcExports;
     TableDescVector       tables;
     MemoryAccessVector    memoryAccesses;
     BoundsCheckVector     boundsChecks;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
     CallThunkVector       callThunks;
     NameInBytecodeVector  funcNames;
     CacheableChars        filename;
--- a/js/src/asmjs/WasmCompile.cpp
+++ b/js/src/asmjs/WasmCompile.cpp
@@ -948,17 +948,17 @@ DecodeExport(Decoder& d, bool newFormat,
 
         if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
             return false;
 
         UniqueChars fieldName = DecodeExportName(d, dupSet);
         if (!fieldName)
             return false;
 
-        return mg.declareExport(Move(fieldName), funcIndex);
+        return mg.declareFuncExport(Move(fieldName), funcIndex);
     }
 
     UniqueChars fieldName = DecodeExportName(d, dupSet);
     if (!fieldName)
         return false;
 
     uint32_t exportKind;
     if (!d.readVarU32(&exportKind))
@@ -971,17 +971,17 @@ DecodeExport(Decoder& d, bool newFormat,
             return Fail(d, "expected export internal index");
 
         if (funcIndex >= mg.numFuncSigs())
             return Fail(d, "export function index out of range");
 
         if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
             return false;
 
-        return mg.declareExport(Move(fieldName), funcIndex);
+        return mg.declareFuncExport(Move(fieldName), funcIndex);
       }
       case DefinitionKind::Memory: {
         uint32_t memoryIndex;
         if (!d.readVarU32(&memoryIndex))
             return Fail(d, "expected memory index");
 
         if (memoryIndex > 0 || !mg.usesMemory())
             return Fail(d, "memory index out of bounds");
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -94,17 +94,17 @@ ModuleGenerator::~ModuleGenerator()
 }
 
 bool
 ModuleGenerator::init(UniqueModuleGeneratorData shared, CompileArgs&& args,
                       Metadata* maybeAsmJSMetadata)
 {
     alwaysBaseline_ = args.alwaysBaseline;
 
-    if (!funcIndexToExport_.init())
+    if (!funcIndexToFuncExportIndex_.init())
         return false;
 
     linkData_.globalDataLength = AlignBytes(InitialGlobalDataBytes, sizeof(void*));;
 
     // asm.js passes in an AsmJSMetadata subclass to use instead.
     if (maybeAsmJSMetadata) {
         MOZ_ASSERT(shared->kind == ModuleKind::AsmJS);
         metadata_ = maybeAsmJSMetadata;
@@ -350,17 +350,17 @@ ModuleGenerator::finishCodegen()
 
     {
         TempAllocator alloc(&lifo_);
         MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc);
 
         if (!entries.resize(numExports()))
             return false;
         for (uint32_t i = 0; i < numExports(); i++)
-            entries[i] = GenerateEntry(masm, metadata_->exports[i], usesMemory());
+            entries[i] = GenerateEntry(masm, metadata_->funcExports[i], usesMemory());
 
         if (!interpExits.resize(numFuncImports()))
             return false;
         if (!jitExits.resize(numFuncImports()))
             return false;
         for (uint32_t i = 0; i < numFuncImports(); i++) {
             interpExits[i] = GenerateInterpExit(masm, metadata_->funcImports[i], i);
             jitExits[i] = GenerateJitExit(masm, metadata_->funcImports[i], usesMemory());
@@ -375,17 +375,17 @@ ModuleGenerator::finishCodegen()
             return false;
     }
 
     // Adjust each of the resulting Offsets (to account for being merged into
     // masm_) and then create code ranges for all the stubs.
 
     for (uint32_t i = 0; i < numExports(); i++) {
         entries[i].offsetBy(offsetInWhole);
-        metadata_->exports[i].initStubOffset(entries[i].begin);
+        metadata_->funcExports[i].initStubOffset(entries[i].begin);
         if (!metadata_->codeRanges.emplaceBack(CodeRange::Entry, entries[i]))
             return false;
     }
 
     for (uint32_t i = 0; i < numFuncImports(); i++) {
         interpExits[i].offsetBy(offsetInWhole);
         metadata_->funcImports[i].initInterpExitOffset(interpExits[i].begin);
         if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i]))
@@ -642,73 +642,72 @@ ModuleGenerator::numFuncImports() const
 const FuncImportGenDesc&
 ModuleGenerator::funcImport(uint32_t funcImportIndex) const
 {
     MOZ_ASSERT(shared_->funcImports[funcImportIndex].sig);
     return shared_->funcImports[funcImportIndex];
 }
 
 bool
-ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex)
+ModuleGenerator::declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
+                                   uint32_t* funcExportIndex /* = nullptr */)
 {
-    MOZ_ASSERT(!exportMap_.hasStartFunction());
+    MOZ_ASSERT(!metadata_->hasStartFunction());
 
-    if (!exportMap_.fieldNames.append(Move(fieldName)))
-        return false;
-
-    FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
+    FuncIndexMap::AddPtr p = funcIndexToFuncExportIndex_.lookupForAdd(funcIndex);
     if (p) {
-        if (exportIndex)
-            *exportIndex = p->value();
-        return exportMap_.fieldsToExports.append(p->value());
+        if (funcExportIndex)
+            *funcExportIndex = p->value();
+        return exports_.emplaceBack(Move(fieldName), p->value());
     }
 
-    uint32_t newExportIndex = metadata_->exports.length();
-    MOZ_ASSERT(newExportIndex < MaxExports);
+    uint32_t newFuncExportIndex = metadata_->funcExports.length();
+    MOZ_ASSERT(newFuncExportIndex < MaxExports);
 
-    if (exportIndex)
-        *exportIndex = newExportIndex;
+    if (funcExportIndex)
+        *funcExportIndex = newFuncExportIndex;
 
     Sig copy;
     if (!copy.clone(funcSig(funcIndex)))
         return false;
 
-    return metadata_->exports.emplaceBack(Move(copy), funcIndex) &&
-           exportMap_.fieldsToExports.append(newExportIndex) &&
-           funcIndexToExport_.add(p, funcIndex, newExportIndex);
+    return metadata_->funcExports.emplaceBack(Move(copy), funcIndex) &&
+           exports_.emplaceBack(Move(fieldName), newFuncExportIndex) &&
+           funcIndexToFuncExportIndex_.add(p, funcIndex, newFuncExportIndex);
 }
 
 uint32_t
 ModuleGenerator::numExports() const
 {
-    return metadata_->exports.length();
+    return metadata_->funcExports.length();
 }
 
 bool
 ModuleGenerator::addMemoryExport(UniqueChars fieldName)
 {
-    return exportMap_.fieldNames.append(Move(fieldName)) &&
-           exportMap_.fieldsToExports.append(MemoryExport);
+    return exports_.emplaceBack(Move(fieldName), DefinitionKind::Memory);
 }
 
 bool
 ModuleGenerator::setStartFunction(uint32_t funcIndex)
 {
-    FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
+    MOZ_ASSERT(!metadata_->hasStartFunction());
+
+    FuncIndexMap::AddPtr p = funcIndexToFuncExportIndex_.lookupForAdd(funcIndex);
     if (p) {
-        exportMap_.setStartFunction(p->value());
+        metadata_->initStartFuncExportIndex(p->value());
         return true;
     }
 
     Sig copy;
     if (!copy.clone(funcSig(funcIndex)))
         return false;
 
-    exportMap_.setStartFunction(metadata_->exports.length());
-    return metadata_->exports.emplaceBack(Move(copy), funcIndex);
+    metadata_->initStartFuncExportIndex(metadata_->funcExports.length());
+    return metadata_->funcExports.emplaceBack(Move(copy), funcIndex);
 }
 
 bool
 ModuleGenerator::startFuncDefs()
 {
     MOZ_ASSERT(!startedFuncDefs_);
     MOZ_ASSERT(!finishedFuncDefs_);
 
@@ -955,14 +954,14 @@ ModuleGenerator::finish(ImportVector&& i
     }
 
     if (!finishLinkData(code))
         return nullptr;
 
     return js::MakeUnique<Module>(Move(code),
                                   Move(linkData_),
                                   Move(imports),
-                                  Move(exportMap_),
+                                  Move(exports_),
                                   Move(dataSegments_),
                                   Move(elemSegments_),
                                   *metadata_,
                                   bytecode);
 }
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -94,30 +94,30 @@ class MOZ_STACK_CLASS ModuleGenerator
     typedef Vector<IonCompileTask*, 0, SystemAllocPolicy> IonCompileTaskPtrVector;
 
     // Constant parameters
     bool                            alwaysBaseline_;
 
     // Data that is moved into the result of finish()
     LinkData                        linkData_;
     MutableMetadata                 metadata_;
-    ExportMap                       exportMap_;
+    ExportVector                    exports_;
     DataSegmentVector               dataSegments_;
     ElemSegmentVector               elemSegments_;
 
     // Data scoped to the ModuleGenerator's lifetime
     UniqueModuleGeneratorData       shared_;
     uint32_t                        numSigs_;
     uint32_t                        numTables_;
     LifoAlloc                       lifo_;
     jit::JitContext                 jcx_;
     jit::TempAllocator              masmAlloc_;
     jit::MacroAssembler             masm_;
     Uint32Vector                    funcIndexToCodeRange_;
-    FuncIndexMap                    funcIndexToExport_;
+    FuncIndexMap                    funcIndexToFuncExportIndex_;
     uint32_t                        lastPatchedCallsite_;
     uint32_t                        startOfUnpatchedBranches_;
     JumpSiteArray                   jumpThunks_;
 
     // Parallel compilation
     bool                            parallel_;
     uint32_t                        outstanding_;
     IonCompileTaskVector            tasks_;
@@ -168,18 +168,18 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool allocateGlobal(ValType type, bool isConst, uint32_t* index);
     const GlobalDesc& global(unsigned index) const { return shared_->globals[index]; }
 
     // Imports:
     uint32_t numFuncImports() const;
     const FuncImportGenDesc& funcImport(uint32_t funcImportIndex) const;
 
     // Exports:
-    MOZ_MUST_USE bool declareExport(UniqueChars fieldName, uint32_t funcIndex,
-                                    uint32_t* exportIndex = nullptr);
+    MOZ_MUST_USE bool declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
+                                        uint32_t* funcExportIndex = nullptr);
     uint32_t numExports() const;
     MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
 
     // Function definitions:
     MOZ_MUST_USE bool startFuncDefs();
     MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDefs();
--- a/js/src/asmjs/WasmInstance.cpp
+++ b/js/src/asmjs/WasmInstance.cpp
@@ -415,19 +415,19 @@ Instance::memoryBase() const
 
 size_t
 Instance::memoryLength() const
 {
     return memory_->buffer().byteLength();
 }
 
 bool
-Instance::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
+Instance::callExport(JSContext* cx, uint32_t funcExportIndex, CallArgs args)
 {
-    const Export& exp = metadata_->exports[exportIndex];
+    const FuncExport& fe = metadata_->funcExports[funcExportIndex];
 
     // Enable/disable profiling in the Module to match the current global
     // profiling state. Don't do this if the Module is already active on the
     // stack since this would leave the Module in a state where profiling is
     // enabled but the stack isn't unwindable.
     if (profilingEnabled() != cx->runtime()->spsProfiler.enabled() && !activation()) {
         if (!toggleProfiling(cx))
             return false;
@@ -437,23 +437,23 @@ Instance::callExport(JSContext* cx, uint
     // array of 16-byte values where each value contains either a coerced int32
     // (in the low word), a double value (in the low dword) or a SIMD vector
     // value, with the coercions specified by the wasm signature. The external
     // entry point unpacks this array into the system-ABI-specified registers
     // and stack memory and then calls into the internal entry point. The return
     // value is stored in the first element of the array (which, therefore, must
     // have length >= 1).
     Vector<ExportArg, 8> exportArgs(cx);
-    if (!exportArgs.resize(Max<size_t>(1, exp.sig().args().length())))
+    if (!exportArgs.resize(Max<size_t>(1, fe.sig().args().length())))
         return false;
 
     RootedValue v(cx);
-    for (unsigned i = 0; i < exp.sig().args().length(); ++i) {
+    for (unsigned i = 0; i < fe.sig().args().length(); ++i) {
         v = i < args.length() ? args[i] : UndefinedValue();
-        switch (exp.sig().arg(i)) {
+        switch (fe.sig().arg(i)) {
           case ValType::I32:
             if (!ToInt32(cx, v, (int32_t*)&exportArgs[i]))
                 return false;
             break;
           case ValType::I64:
             MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
             if (!ReadI64Object(cx, v, (int64_t*)&exportArgs[i]))
                 return false;
@@ -528,17 +528,17 @@ Instance::callExport(JSContext* cx, uint
         // when running this module. Additionally, push a JitActivation so that
         // the optimized wasm-to-Ion FFI call path (which we want to be very
         // fast) can avoid doing so. The JitActivation is marked as inactive so
         // stack iteration will skip over it.
         WasmActivation activation(cx, *this);
         JitActivation jitActivation(cx, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
-        auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeSegment_->code() + exp.stubOffset());
+        auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeSegment_->code() + fe.stubOffset());
         if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), codeSegment_->globalData()))
             return false;
     }
 
     if (args.isConstructing()) {
         // By spec, when a function is called as a constructor and this function
         // returns a primary type, which is the case for all wasm exported
         // functions, the returned value is discarded and an empty object is
@@ -547,17 +547,17 @@ Instance::callExport(JSContext* cx, uint
         if (!obj)
             return false;
         args.rval().set(ObjectValue(*obj));
         return true;
     }
 
     void* retAddr = &exportArgs[0];
     JSObject* retObj = nullptr;
-    switch (exp.sig().ret()) {
+    switch (fe.sig().ret()) {
       case ExprType::Void:
         args.rval().set(UndefinedValue());
         break;
       case ExprType::I32:
         args.rval().set(Int32Value(*(int32_t*)retAddr));
         break;
       case ExprType::I64:
         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
--- a/js/src/asmjs/WasmInstance.h
+++ b/js/src/asmjs/WasmInstance.h
@@ -25,18 +25,16 @@
 
 namespace js {
 
 class WasmActivation;
 class WasmInstanceObject;
 
 namespace wasm {
 
-class ExportMap;
-
 // Instance represents a wasm instance and provides all the support for runtime
 // execution of code in the instance. Instances share various immutable data
 // structures with the Module from which they were instantiated and other
 // instances instantiated from the same Module. However, an Instance has no
 // direct reference to its source Module which allows a Module to be destroyed
 // while it still has live Instances.
 
 class Instance
@@ -83,17 +81,17 @@ class Instance
     const CodeSegment& codeSegment() const { return *codeSegment_; }
     const Metadata& metadata() const { return *metadata_; }
     SharedMem<uint8_t*> memoryBase() const;
     size_t memoryLength() const;
 
     // Execute the given export given the JS call arguments, storing the return
     // value in args.rval.
 
-    MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t exportIndex, CallArgs args);
+    MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcExportIndex, CallArgs args);
 
     // An instance has a profiling mode that is updated to match the runtime's
     // profiling mode when calling an instance's exports when there are no other
     // activations of the instance live on the stack. Once in profiling mode,
     // ProfilingFrameIterator can be used to asynchronously walk the stack.
     // Otherwise, the ProfilingFrameIterator will skip any activations of this
     // instance.
 
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -153,47 +153,64 @@ Import::deserialize(const uint8_t* curso
 
 size_t
 Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return module.sizeOfExcludingThis(mallocSizeOf) +
            func.sizeOfExcludingThis(mallocSizeOf);
 }
 
-size_t
-ExportMap::serializedSize() const
+Export::Export(UniqueChars fieldName, uint32_t funcExportIndex)
+  : fieldName_(Move(fieldName))
+{
+    pod.kind_ = DefinitionKind::Function;
+    pod.funcExportIndex_ = funcExportIndex;
+}
+
+Export::Export(UniqueChars fieldName, DefinitionKind kind)
+  : fieldName_(Move(fieldName))
 {
-    return SerializedVectorSize(fieldNames) +
-           SerializedPodVectorSize(fieldsToExports) +
-           sizeof(uint32_t);
+    pod.kind_ = kind;
+    pod.funcExportIndex_ = 0;
+}
+
+uint32_t
+Export::funcExportIndex() const
+{
+    MOZ_ASSERT(pod.kind_ == DefinitionKind::Function);
+    return pod.funcExportIndex_;
+}
+
+size_t
+Export::serializedSize() const
+{
+    return fieldName_.serializedSize() +
+           sizeof(pod);
 }
 
 uint8_t*
-ExportMap::serialize(uint8_t* cursor) const
+Export::serialize(uint8_t* cursor) const
 {
-    cursor = SerializeVector(cursor, fieldNames);
-    cursor = SerializePodVector(cursor, fieldsToExports);
-    cursor = WriteScalar(cursor, startExportIndex);
+    cursor = fieldName_.serialize(cursor);
+    cursor = WriteBytes(cursor, &pod, sizeof(pod));
     return cursor;
 }
 
 const uint8_t*
-ExportMap::deserialize(const uint8_t* cursor)
+Export::deserialize(const uint8_t* cursor)
 {
-    (cursor = DeserializeVector(cursor, &fieldNames)) &&
-    (cursor = DeserializePodVector(cursor, &fieldsToExports)) &&
-    (cursor = ReadScalar(cursor, &startExportIndex));
+    (cursor = fieldName_.deserialize(cursor)) &&
+    (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 
 size_t
-ExportMap::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
-    return SizeOfVectorExcludingThis(fieldNames, mallocSizeOf) &&
-           fieldsToExports.sizeOfExcludingThis(mallocSizeOf);
+    return fieldName_.sizeOfExcludingThis(mallocSizeOf);
 }
 
 size_t
 ElemSegment::serializedSize() const
 {
     return sizeof(tableIndex) +
            SerializedPodVectorSize(elems);
 }
@@ -221,30 +238,30 @@ ElemSegment::sizeOfExcludingThis(MallocS
 }
 
 size_t
 Module::serializedSize() const
 {
     return SerializedPodVectorSize(code_) +
            linkData_.serializedSize() +
            SerializedVectorSize(imports_) +
-           exportMap_.serializedSize() +
+           SerializedVectorSize(exports_) +
            SerializedPodVectorSize(dataSegments_) +
            SerializedVectorSize(elemSegments_) +
            metadata_->serializedSize() +
            SerializedPodVectorSize(bytecode_->bytes);
 }
 
 uint8_t*
 Module::serialize(uint8_t* cursor) const
 {
     cursor = SerializePodVector(cursor, code_);
     cursor = linkData_.serialize(cursor);
     cursor = SerializeVector(cursor, imports_);
-    cursor = exportMap_.serialize(cursor);
+    cursor = SerializeVector(cursor, exports_);
     cursor = SerializePodVector(cursor, dataSegments_);
     cursor = SerializeVector(cursor, elemSegments_);
     cursor = metadata_->serialize(cursor);
     cursor = SerializePodVector(cursor, bytecode_->bytes);
     return cursor;
 }
 
 /* static */ const uint8_t*
@@ -260,18 +277,18 @@ Module::deserialize(const uint8_t* curso
     if (!cursor)
         return nullptr;
 
     ImportVector imports;
     cursor = DeserializeVector(cursor, &imports);
     if (!cursor)
         return nullptr;
 
-    ExportMap exportMap;
-    cursor = exportMap.deserialize(cursor);
+    ExportVector exports;
+    cursor = DeserializeVector(cursor, &exports);
     if (!cursor)
         return nullptr;
 
     DataSegmentVector dataSegments;
     cursor = DeserializePodVector(cursor, &dataSegments);
     if (!cursor)
         return nullptr;
 
@@ -298,17 +315,17 @@ Module::deserialize(const uint8_t* curso
         return nullptr;
     cursor = DeserializePodVector(cursor, &bytecode->bytes);
     if (!cursor)
         return nullptr;
 
     *module = js::MakeUnique<Module>(Move(code),
                                      Move(linkData),
                                      Move(imports),
-                                     Move(exportMap),
+                                     Move(exports),
                                      Move(dataSegments),
                                      Move(elemSegments),
                                      *metadata,
                                      *bytecode);
     if (!*module)
         return nullptr;
 
     return cursor;
@@ -320,17 +337,17 @@ Module::addSizeOfMisc(MallocSizeOf mallo
                       ShareableBytes::SeenSet* seenBytes,
                       size_t* code,
                       size_t* data) const
 {
     *data += mallocSizeOf(this) +
              code_.sizeOfExcludingThis(mallocSizeOf) +
              linkData_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
-             exportMap_.sizeOfExcludingThis(mallocSizeOf) +
+             SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
              dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
              metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
              bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
 }
 
 // asm.js module instantiation supplies its own buffer, but for wasm, create and
 // initialize the buffer if one is requested. Either way, the buffer is wrapped
@@ -409,89 +426,85 @@ Module::instantiateTable(JSContext* cx, 
 
 static bool
 WasmCall(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedFunction callee(cx, &args.callee().as<JSFunction>());
 
     Instance& instance = ExportedFunctionToInstance(callee);
-    uint32_t exportIndex = ExportedFunctionToExportIndex(callee);
+    uint32_t funcExportIndex = ExportedFunctionToExportIndex(callee);
 
-    return instance.callExport(cx, exportIndex, args);
+    return instance.callExport(cx, funcExportIndex, args);
 }
 
 static JSFunction*
-NewExportedFunction(JSContext* cx, Handle<WasmInstanceObject*> instanceObj, uint32_t exportIndex)
+NewExportedFunction(JSContext* cx, HandleWasmInstanceObject instanceObj, uint32_t funcExportIndex)
 {
     Instance& instance = instanceObj->instance();
     const Metadata& metadata = instance.metadata();
-    const Export& exp = metadata.exports[exportIndex];
-    unsigned numArgs = exp.sig().args().length();
+    const FuncExport& fe = metadata.funcExports[funcExportIndex];
+    unsigned numArgs = fe.sig().args().length();
 
-    RootedAtom name(cx, instance.getFuncAtom(cx, exp.funcIndex()));
+    RootedAtom name(cx, instance.getFuncAtom(cx, fe.funcIndex()));
     if (!name)
         return nullptr;
 
     JSFunction* fun = NewNativeConstructor(cx, WasmCall, numArgs, name,
                                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
                                            JSFunction::ASMJS_CTOR);
     if (!fun)
         return nullptr;
 
     fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
-    fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
+    fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(funcExportIndex));
     return fun;
 }
 
 static bool
 CreateExportObject(JSContext* cx,
                    HandleWasmInstanceObject instanceObj,
                    HandleWasmMemoryObject memoryObj,
-                   const ExportMap& exportMap,
+                   const ExportVector& exports,
                    const Metadata& metadata,
                    MutableHandleObject exportObj)
 {
-    MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length());
-
-    if (metadata.isAsmJS() &&
-        exportMap.fieldNames.length() == 1 &&
-        strlen(exportMap.fieldNames[0].get()) == 0)
-    {
+    if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
         exportObj.set(NewExportedFunction(cx, instanceObj, 0));
         return !!exportObj;
     }
 
     exportObj.set(JS_NewPlainObject(cx));
     if (!exportObj)
         return false;
 
     Rooted<ValueVector> vals(cx, ValueVector(cx));
-    for (size_t exportIndex = 0; exportIndex < metadata.exports.length(); exportIndex++) {
-        JSFunction* fun = NewExportedFunction(cx, instanceObj, exportIndex);
+    for (size_t i = 0; i < metadata.funcExports.length(); i++) {
+        JSFunction* fun = NewExportedFunction(cx, instanceObj, i);
         if (!fun || !vals.append(ObjectValue(*fun)))
             return false;
     }
 
-    for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
-        const char* fieldName = exportMap.fieldNames[fieldIndex].get();
-        JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
+    for (const Export& exp : exports) {
+        JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
         if (!atom)
             return false;
 
         RootedId id(cx, AtomToId(atom));
         RootedValue val(cx);
-        uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex];
-        if (exportIndex == MemoryExport) {
+        switch (exp.kind()) {
+          case DefinitionKind::Function:
+            val = vals[exp.funcExportIndex()];
+            break;
+          case DefinitionKind::Memory:
             if (metadata.assumptions.newFormat)
                 val = ObjectValue(*memoryObj);
             else
                 val = ObjectValue(memoryObj->buffer());
-        } else {
-            val = vals[exportIndex];
+            break;
         }
 
         if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
             return false;
     }
 
     return true;
 }
@@ -544,17 +557,17 @@ Module::instantiate(JSContext* cx,
             return false;
 
         instanceObj->init(Move(instance));
     }
 
     // Create the export object.
 
     RootedObject exportObj(cx);
-    if (!CreateExportObject(cx, instanceObj, memory, exportMap_, *metadata_, &exportObj))
+    if (!CreateExportObject(cx, instanceObj, memory, exports_, *metadata_, &exportObj))
         return false;
 
     instanceObj->initExportsObject(exportObj);
 
     JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField));
     if (!atom)
         return false;
     RootedId id(cx, AtomToId(atom));
@@ -566,19 +579,19 @@ Module::instantiate(JSContext* cx,
     // Done! Notify the Debugger of the new Instance.
 
     Debugger::onNewWasmInstance(cx, instanceObj);
 
     // Call the start function, if there's one. By specification, it does not
     // take any arguments nor does it return a value, so just create a dummy
     // arguments object.
 
-    if (exportMap_.hasStartFunction()) {
+    if (metadata_->hasStartFunction()) {
         FixedInvokeArgs<0> args(cx);
-        if (!instanceObj->instance().callExport(cx, exportMap_.startFunctionExportIndex(), args))
+        if (!instanceObj->instance().callExport(cx, metadata_->startFuncExportIndex(), args))
             return false;
     }
 
     return true;
 }
 
 bool
 wasm::IsExportedFunction(JSFunction* fun)
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -98,59 +98,48 @@ struct Import
       : module(Move(module)), func(Move(func)), kind(kind)
     {}
 
     WASM_DECLARE_SERIALIZABLE(Import)
 };
 
 typedef Vector<Import, 0, SystemAllocPolicy> ImportVector;
 
-// ExportMap describes all of a single module's exports. The ExportMap describes
-// how the Exports (stored in Metadata) are mapped to the fields of the export
-// object produced by instantiation. The 'fieldNames' vector provides the list
-// of names of the module's exports. For each field name, 'fieldsToExports'
-// provides either:
-//  - the sentinel value MemoryExport indicating an export of linear memory; or
-//  - the index of an export into the ExportVector in Metadata
-//
-// ExportMap also contains the start function's export index, which maps to the
-// export that is called at each instantiation of a given module.
+// Export describes the export of a definition in a Module to a field in the
+// export object. For functions, Export stores an index into the
+// FuncExportVector in Metadata. For memory and table exports, there is
+// at most one (default) memory/table so no index is needed. Note: a single
+// definition can be exported by multiple Exports in the ExportVector.
 //
-// ExportMap is built incrementally by ModuleGenerator and then stored immutably
-// by Module.
-
-static const uint32_t MemoryExport = UINT32_MAX;
+// ExportVector is built incrementally by ModuleGenerator and then stored
+// immutably by Module.
 
-static const uint32_t NO_START_FUNCTION = UINT32_MAX;
-
-class ExportMap
+class Export
 {
-    uint32_t startExportIndex;
+    CacheableChars fieldName_;
+    struct CacheablePod {
+        DefinitionKind kind_;
+        uint32_t funcExportIndex_;
+    } pod;
 
   public:
-    CacheableCharsVector fieldNames;
-    Uint32Vector fieldsToExports;
+    Export() = default;
+    explicit Export(UniqueChars fieldName, uint32_t funcExportIndex);
+    explicit Export(UniqueChars fieldName, DefinitionKind kind);
 
-    ExportMap() : startExportIndex(NO_START_FUNCTION) {}
+    const char* fieldName() const { return fieldName_.get(); }
 
-    bool hasStartFunction() const {
-        return startExportIndex != NO_START_FUNCTION;
-    }
-    void setStartFunction(uint32_t index) {
-        MOZ_ASSERT(!hasStartFunction());
-        startExportIndex = index;
-    }
-    uint32_t startFunctionExportIndex() const {
-        MOZ_ASSERT(hasStartFunction());
-        return startExportIndex;
-    }
+    DefinitionKind kind() const { return pod.kind_; }
+    uint32_t funcExportIndex() const;
 
-    WASM_DECLARE_SERIALIZABLE(ExportMap)
+    WASM_DECLARE_SERIALIZABLE(Export)
 };
 
+typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
+
 // DataSegment describes the offset of a data segment in the bytecode that is
 // to be copied at a given offset into linear memory upon instantiation.
 
 struct DataSegment
 {
     uint32_t memoryOffset;
     uint32_t bytecodeOffset;
     uint32_t length;
@@ -189,38 +178,38 @@ typedef Vector<ElemSegment, 0, SystemAll
 // time it is instantiated. In the future, Module will store a shareable,
 // immutable CodeSegment that can be shared by all its instances.
 
 class Module
 {
     const Bytes             code_;
     const LinkData          linkData_;
     const ImportVector      imports_;
-    const ExportMap         exportMap_;
+    const ExportVector      exports_;
     const DataSegmentVector dataSegments_;
     const ElemSegmentVector elemSegments_;
     const SharedMetadata    metadata_;
     const SharedBytes       bytecode_;
 
     bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
     bool instantiateTable(JSContext* cx, const CodeSegment& cs, SharedTableVector* tables) const;
 
   public:
     Module(Bytes&& code,
            LinkData&& linkData,
            ImportVector&& imports,
-           ExportMap&& exportMap,
+           ExportVector&& exports,
            DataSegmentVector&& dataSegments,
            ElemSegmentVector&& elemSegments,
            const Metadata& metadata,
            const ShareableBytes& bytecode)
       : code_(Move(code)),
         linkData_(Move(linkData)),
         imports_(Move(imports)),
-        exportMap_(Move(exportMap)),
+        exports_(Move(exports)),
         dataSegments_(Move(dataSegments)),
         elemSegments_(Move(elemSegments)),
         metadata_(&metadata),
         bytecode_(&bytecode)
     {}
 
     const Metadata& metadata() const { return *metadata_; }
     const ImportVector& imports() const { return imports_; }
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -91,17 +91,17 @@ static const unsigned FramePushedAfterSa
 #endif
 static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*);
 
 // Generate a stub that enters wasm from a C++ caller via the native ABI.
 // The signature of the entry point is Module::CodePtr. The exported wasm
 // function has an ABI derived from its specific signature, so this function
 // must map from the ABI of CodePtr to the export's signature's ABI.
 Offsets
-wasm::GenerateEntry(MacroAssembler& masm, const Export& exp, bool usesHeap)
+wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe, bool usesHeap)
 {
     masm.haltingAlign(CodeAlignment);
 
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
@@ -156,21 +156,21 @@ wasm::GenerateEntry(MacroAssembler& masm
     masm.storeStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
 
     // Dynamically align the stack since ABIStackAlignment is not necessarily
     // AsmJSStackAlignment. We'll use entrySP to recover the original stack
     // pointer on return.
     masm.andToStackPtr(Imm32(~(AsmJSStackAlignment - 1)));
 
     // Bump the stack for the call.
-    masm.reserveStack(AlignBytes(StackArgBytes(exp.sig().args()), AsmJSStackAlignment));
+    masm.reserveStack(AlignBytes(StackArgBytes(fe.sig().args()), AsmJSStackAlignment));
 
     // Copy parameters out of argv and into the registers/stack-slots specified by
     // the system ABI.
-    for (ABIArgValTypeIter iter(exp.sig().args()); !iter.done(); iter++) {
+    for (ABIArgValTypeIter iter(fe.sig().args()); !iter.done(); iter++) {
         unsigned argOffset = iter.index() * sizeof(ExportArg);
         Address src(argv, argOffset);
         MIRType type = iter.mirType();
         MOZ_ASSERT_IF(type == MIRType::Int64, JitOptions.wasmTestMode);
         switch (iter->kind()) {
           case ABIArg::GPR:
             if (type == MIRType::Int32)
                 masm.load32(src, iter->gpr());
@@ -248,28 +248,28 @@ wasm::GenerateEntry(MacroAssembler& masm
                 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type");
             }
             break;
         }
     }
 
     // Call into the real function.
     masm.assertStackAlignment(AsmJSStackAlignment);
-    masm.call(CallSiteDesc(CallSiteDesc::Relative), exp.funcIndex());
+    masm.call(CallSiteDesc(CallSiteDesc::Relative), fe.funcIndex());
 
     // Recover the stack pointer value before dynamic alignment.
     masm.loadWasmActivation(scratch);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.setFramePushed(FramePushedForEntrySP);
 
     // Recover the 'argv' pointer which was saved before aligning the stack.
     masm.Pop(argv);
 
     // Store the return value in argv[0]
-    switch (exp.sig().ret()) {
+    switch (fe.sig().ret()) {
       case ExprType::Void:
         break;
       case ExprType::I32:
         masm.store32(ReturnReg, Address(argv, 0));
         break;
       case ExprType::I64:
         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
         masm.store64(ReturnReg64, Address(argv, 0));
--- a/js/src/asmjs/WasmStubs.h
+++ b/js/src/asmjs/WasmStubs.h
@@ -22,21 +22,21 @@
 #include "asmjs/WasmTypes.h"
 
 namespace js {
 
 namespace jit { class MacroAssembler; }
 
 namespace wasm {
 
-class Export;
+class FuncExport;
 class FuncImport;
 
 extern Offsets
-GenerateEntry(jit::MacroAssembler& masm, const Export& exp, bool usesHeap);
+GenerateEntry(jit::MacroAssembler& masm, const FuncExport& fe, bool usesHeap);
 
 extern ProfilingOffsets
 GenerateInterpExit(jit::MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex);
 
 extern ProfilingOffsets
 GenerateJitExit(jit::MacroAssembler& masm, const FuncImport& fi, bool usesHeap);
 
 extern Offsets