Bug 1253137 - Baldr: pass around Bytes instead of Bytecode/UniqueBytecode (r=sunfish)
authorLuke Wagner <luke@mozilla.com>
Sun, 06 Mar 2016 17:46:23 -0600
changeset 287003 5eabc3a7368a09eb317dabd86b598e4f32ff6088
parent 287002 57e9d3626218d7adf9463db51ad9aae8c44cd709
child 287004 0d9926dd10ea11482e186c39a3c6ab4d66f55093
push id18032
push usercbook@mozilla.com
push dateMon, 07 Mar 2016 10:38:51 +0000
treeherderfx-team@087905ffec78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1253137
milestone47.0a1
Bug 1253137 - Baldr: pass around Bytes instead of Bytecode/UniqueBytecode (r=sunfish) MozReview-Commit-ID: 5RzN8IwDc7C
js/src/asmjs/AsmJS.cpp
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmGenerator.cpp
js/src/asmjs/WasmGenerator.h
js/src/asmjs/WasmIonCompile.cpp
js/src/asmjs/WasmIonCompile.h
js/src/asmjs/WasmText.cpp
js/src/asmjs/WasmText.h
js/src/asmjs/WasmTypes.h
js/src/builtin/TestingFunctions.cpp
js/src/jsapi-tests/testWasmLEB128.cpp
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -2645,17 +2645,17 @@ class MOZ_STACK_CLASS FunctionValidator
 
     bool init(PropertyName* name, unsigned line) {
         if (!locals_.init() || !breakLabels_.init() || !continueLabels_.init())
             return false;
 
         if (!m_.mg().startFuncDef(line, &fg_))
             return false;
 
-        encoder_.emplace(fg_.bytecode());
+        encoder_.emplace(fg_.bytes());
         return true;
     }
 
     bool finish(uint32_t funcIndex, unsigned generateTime) {
         return m_.mg().finishFuncDef(funcIndex, generateTime, &fg_);
     }
 
     bool fail(ParseNode* pn, const char* str) {
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -1260,20 +1260,20 @@ DecodeFunctionBody(JSContext* cx, Decode
     }
 
     if (!CheckType(f, type, f.sig().ret()))
         return false;
 
     if (d.currentPosition() != bodyEnd)
         return Fail(cx, d, "function body length mismatch");
 
-    if (!fg.bytecode().resize(bodySize))
+    if (!fg.bytes().resize(bodySize))
         return false;
 
-    memcpy(fg.bytecode().begin(), bodyBegin, bodySize);
+    memcpy(fg.bytes().begin(), bodyBegin, bodySize);
 
     int64_t after = PRMJ_Now();
     unsigned generateTime = (after - before) / PRMJ_USEC_PER_MSEC;
 
     return mg.finishFuncDef(funcIndex, generateTime, &fg);
 }
 
 static bool
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -14,25 +14,21 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef wasm_binary_h
 #define wasm_binary_h
 
-#include "mozilla/DebugOnly.h"
-
 #include "builtin/SIMD.h"
 
 namespace js {
 namespace wasm {
 
-using mozilla::DebugOnly;
-
 static const uint32_t MagicNumber        = 0x6d736100; // "\0asm"
 static const uint32_t EncodingVersion    = 0xa;
 
 static const char SignaturesId[]         = "signatures";
 static const char ImportTableId[]        = "import_table";
 static const char FunctionSignaturesId[] = "function_signatures";
 static const char FunctionTableId[]      = "function_table";
 static const char MemoryId[]             = "memory";
@@ -323,40 +319,39 @@ enum class ExprType
     F32x4 = uint8_t(ValType::F32x4),
     B32x4 = uint8_t(ValType::B32x4),
 
     Limit
 };
 
 typedef int32_t I32x4[4];
 typedef float F32x4[4];
-typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytecode;
-typedef UniquePtr<Bytecode> UniqueBytecode;
+typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytes;
 
-// The Encoder class appends bytes to the Bytecode object it is given during
-// construction. The client is responsible for the Bytecode's lifetime and must
-// keep the Bytecode alive as long as the Encoder is used.
+// The Encoder class appends bytes to the Bytes object it is given during
+// construction. The client is responsible for the Bytes's lifetime and must
+// keep the Bytes alive as long as the Encoder is used.
 
 class Encoder
 {
-    Bytecode& bytecode_;
+    Bytes& bytes_;
 
     template <class T>
     MOZ_WARN_UNUSED_RESULT bool write(const T& v) {
-        return bytecode_.append(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
+        return bytes_.append(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
     }
 
     template <typename UInt>
     MOZ_WARN_UNUSED_RESULT bool writeVarU(UInt i) {
         do {
             uint8_t byte = i & 0x7F;
             i >>= 7;
             if (i != 0)
                 byte |= 0x80;
-            if (!bytecode_.append(byte))
+            if (!bytes_.append(byte))
                 return false;
         } while(i != 0);
         return true;
     }
 
     template <class T>
     MOZ_WARN_UNUSED_RESULT bool writeEnum(T v) {
         static_assert(uint32_t(T::Limit) <= UINT32_MAX, "fits");
@@ -369,52 +364,52 @@ class Encoder
             uint8_t assertByte = assertBits & 0x7f;
             uint8_t patchByte = patchBits & 0x7f;
             assertBits >>= 7;
             patchBits >>= 7;
             if (assertBits != 0) {
                 assertByte |= 0x80;
                 patchByte |= 0x80;
             }
-            MOZ_ASSERT(assertByte == bytecode_[offset]);
-            bytecode_[offset] = patchByte;
+            MOZ_ASSERT(assertByte == bytes_[offset]);
+            bytes_[offset] = patchByte;
             offset++;
         } while(assertBits != 0);
     }
 
     uint32_t varU32ByteLength(size_t offset) const {
         size_t start = offset;
-        while (bytecode_[offset] & 0x80)
+        while (bytes_[offset] & 0x80)
             offset++;
         return offset - start + 1;
     }
     static const uint32_t EnumSentinel = 0x3fff;
 
     template <class T>
     MOZ_WARN_UNUSED_RESULT bool writePatchableEnum(size_t* offset) {
         static_assert(uint32_t(T::Limit) <= EnumSentinel, "reserve enough bits");
-        *offset = bytecode_.length();
+        *offset = bytes_.length();
         return writeVarU32(EnumSentinel);
     }
 
     template <class T>
     void patchEnum(size_t offset, T v) {
         static_assert(uint32_t(T::Limit) <= UINT32_MAX, "fits");
         MOZ_ASSERT(uint32_t(v) < uint32_t(T::Limit));
         return patchVarU32(offset, uint32_t(v), EnumSentinel);
     }
 
   public:
-    explicit Encoder(Bytecode& bytecode)
-      : bytecode_(bytecode)
+    explicit Encoder(Bytes& bytes)
+      : bytes_(bytes)
     {
         MOZ_ASSERT(empty());
     }
 
-    size_t currentOffset() const { return bytecode_.length(); }
+    size_t currentOffset() const { return bytes_.length(); }
     bool empty() const { return currentOffset() == 0; }
 
     // Fixed-size encoding operations simply copy the literal bytes (without
     // attempting to align).
 
     MOZ_WARN_UNUSED_RESULT bool writeFixedU32(uint32_t i) {
         return write<uint32_t>(i);
     }
@@ -447,25 +442,25 @@ class Encoder
     }
     MOZ_WARN_UNUSED_RESULT bool writeExprType(ExprType type) {
         return writeEnum(type);
     }
 
     // Variable-length encodings that allow back-patching.
 
     MOZ_WARN_UNUSED_RESULT bool writePatchableVarU32(size_t* offset) {
-        *offset = bytecode_.length();
+        *offset = bytes_.length();
         return writeVarU32(UINT32_MAX);
     }
     void patchVarU32(size_t offset, uint32_t patchBits) {
         return patchVarU32(offset, patchBits, UINT32_MAX);
     }
 
     MOZ_WARN_UNUSED_RESULT bool writePatchableVarU8(size_t* offset) {
-        *offset = bytecode_.length();
+        *offset = bytes_.length();
         return writeU8(UINT8_MAX);
     }
     void patchVarU8(size_t offset, uint8_t patchBits) {
         MOZ_ASSERT(patchBits < 0x80);
         return patchU8(offset, patchBits);
     }
 
     MOZ_WARN_UNUSED_RESULT bool writePatchableExpr(size_t* offset) {
@@ -474,20 +469,20 @@ class Encoder
     void patchExpr(size_t offset, Expr expr) {
         patchEnum(offset, expr);
     }
 
     // C-strings are written in UTF8 and null-terminated while raw data can
     // contain nulls and instead has an explicit byte length.
 
     MOZ_WARN_UNUSED_RESULT bool writeCString(const char* cstr) {
-        return bytecode_.append(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr) + 1);
+        return bytes_.append(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr) + 1);
     }
     MOZ_WARN_UNUSED_RESULT bool writeRawData(const uint8_t* bytes, uint32_t numBytes) {
-        return bytecode_.append(bytes, numBytes);
+        return bytes_.append(bytes, numBytes);
     }
 
     // A "section" is a contiguous range of bytes that stores its own size so
     // that it may be trivially skipped without examining the contents. Sections
     // require backpatching since the size of the section is only known at the
     // end while the size's uint32 must be stored at the beginning. Immediately
     // after the section length is the string id of the section.
 
@@ -495,32 +490,32 @@ class Encoder
     MOZ_WARN_UNUSED_RESULT bool startSection(const char (&id)[IdSizeWith0], size_t* offset) {
         static const size_t IdSize = IdSizeWith0 - 1;
         MOZ_ASSERT(id[IdSize] == '\0');
         return writePatchableVarU32(offset) &&
                writeVarU32(IdSize) &&
                writeRawData(reinterpret_cast<const uint8_t*>(id), IdSize);
     }
     void finishSection(size_t offset) {
-        return patchVarU32(offset, bytecode_.length() - offset - varU32ByteLength(offset));
+        return patchVarU32(offset, bytes_.length() - offset - varU32ByteLength(offset));
     }
 
     // Temporary encoding forms which should be removed as part of the
     // conversion to wasm:
 
     MOZ_WARN_UNUSED_RESULT bool writeU8(uint8_t i) {
         return write<uint8_t>(i);
     }
     MOZ_WARN_UNUSED_RESULT bool writePatchableU8(size_t* offset) {
-        *offset = bytecode_.length();
-        return bytecode_.append(0xff);
+        *offset = bytes_.length();
+        return bytes_.append(0xff);
     }
     void patchU8(size_t offset, uint8_t i) {
-        MOZ_ASSERT(bytecode_[offset] == 0xff);
-        bytecode_[offset] = i;
+        MOZ_ASSERT(bytes_[offset] == 0xff);
+        bytes_[offset] = i;
     }
 };
 
 // The Decoder class decodes the bytes in the range it is given during
 // construction. The client is responsible for keeping the byte range alive as
 // long as the Decoder is used.
 
 class Decoder
@@ -594,20 +589,20 @@ class Decoder
   public:
     Decoder(const uint8_t* begin, const uint8_t* end)
       : beg_(begin),
         end_(end),
         cur_(begin)
     {
         MOZ_ASSERT(begin <= end);
     }
-    explicit Decoder(const Bytecode& bytecode)
-      : beg_(bytecode.begin()),
-        end_(bytecode.end()),
-        cur_(bytecode.begin())
+    explicit Decoder(const Bytes& bytes)
+      : beg_(bytes.begin()),
+        end_(bytes.end()),
+        cur_(bytes.begin())
     {}
 
     bool done() const {
         MOZ_ASSERT(cur_ <= end_);
         return cur_ == end_;
     }
 
     uintptr_t bytesRemain() const {
@@ -615,19 +610,16 @@ class Decoder
         return uintptr_t(end_ - cur_);
     }
     const uint8_t* currentPosition() const {
         return cur_;
     }
     size_t currentOffset() const {
         return cur_ - beg_;
     }
-    void assertCurrentIs(const DebugOnly<size_t> offset) const {
-        MOZ_ASSERT(currentOffset() == offset);
-    }
 
     // Fixed-size encoding operations simply copy the literal bytes (without
     // attempting to align).
 
     MOZ_WARN_UNUSED_RESULT bool readFixedU32(uint32_t* u = nullptr) {
         return read<uint32_t>(u);
     }
     MOZ_WARN_UNUSED_RESULT bool readFixedF32(float* f = nullptr) {
@@ -701,17 +693,17 @@ class Decoder
         if (!readVarU32(&idSize))
             goto backup;
         if (bytesRemain() < idSize)
             return false;
         if (idSize != IdSize || !!memcmp(cur_, id, IdSize))
             goto backup;
         cur_ += IdSize;
         *startOffset = before - beg_;
-        return  true;
+        return true;
       backup:
         cur_ = before;
         *startOffset = NotStarted;
         return true;
     }
     MOZ_WARN_UNUSED_RESULT bool finishSection(uint32_t startOffset) {
         uint32_t currentOffset = cur_ - beg_;
         cur_ = beg_ + startOffset;
@@ -730,17 +722,17 @@ class Decoder
             return false;
         if (uint32_t(cur_ - begin) > size)
             return false;
         cur_ = begin + size;
         return true;
     }
 
     // The infallible "unchecked" decoding functions can be used when we are
-    // sure that the bytecode is well-formed (by construction or due to previous
+    // sure that the bytes are well-formed (by construction or due to previous
     // validation).
 
     uint32_t uncheckedReadFixedU32() {
         return uncheckedRead<uint32_t>();
     }
     float uncheckedReadFixedF32() {
         return uncheckedRead<float>();
     }
@@ -785,19 +777,16 @@ class Decoder
     }
 
     // Temporary encoding forms which should be removed as part of the
     // conversion to wasm:
 
     MOZ_WARN_UNUSED_RESULT bool readFixedU8(uint8_t* i = nullptr) {
         return read<uint8_t>(i);
     }
-    MOZ_WARN_UNUSED_RESULT bool readFixedI32(int32_t* i = nullptr) {
-        return read<int32_t>(i);
-    }
     uint8_t uncheckedReadFixedU8() {
         return uncheckedRead<uint8_t>();
     }
 };
 
 // Reusable macro encoding/decoding functions reused by both the two
 // encoders (AsmJS/WasmText) and decoders (Wasm/WasmIonCompile).
 
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -296,17 +296,17 @@ ModuleGenerator::convertOutOfRangeBranch
     masm_.clearJumpSites();
 
     return true;
 }
 
 bool
 ModuleGenerator::finishTask(IonCompileTask* task)
 {
-    const FuncBytecode& func = task->func();
+    const FuncBytes& func = task->func();
     FuncCompileResults& results = task->results();
 
     // Before merging in the new function's code, if jumps/calls in a previous
     // function's body might go out of range, patch these to thunks which have
     // full range.
     if ((masm_.size() - startOfUnpatchedBranches_) + results.masm().size() > JumpRange()) {
         startOfUnpatchedBranches_ = masm_.size();
         if (!convertOutOfRangeBranchesToThunks())
@@ -777,44 +777,36 @@ ModuleGenerator::startFuncDef(uint32_t l
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(!finishedFuncs_);
 
     if (freeTasks_.empty() && !finishOutstandingTask())
         return false;
 
     IonCompileTask* task = freeTasks_.popCopy();
 
-    task->reset(&fg->bytecode_);
-    if (fg->bytecode_) {
-        fg->bytecode_->clear();
-    } else {
-        fg->bytecode_ = MakeUnique<Bytecode>();
-        if (!fg->bytecode_)
-            return false;
-    }
-
+    task->reset(&fg->bytes_);
+    fg->bytes_.clear();
     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>(funcIndex,
-                                     funcSig(funcIndex),
-                                     Move(fg->bytecode_),
-                                     fg->lineOrBytecode_,
-                                     Move(fg->callSiteLineNums_),
-                                     generateTime);
+    auto func = js::MakeUnique<FuncBytes>(Move(fg->bytes_),
+                                          funcIndex,
+                                          funcSig(funcIndex),
+                                          fg->lineOrBytecode_,
+                                          Move(fg->callSiteLineNums_),
+                                          generateTime);
     if (!func)
         return false;
 
     fg->task_->init(Move(func));
 
     if (parallel_) {
         if (!StartOffThreadWasmCompile(cx_, fg->task_))
             return false;
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -46,17 +46,17 @@ struct SlowFunction
 };
 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
-// element is written to Bytecode sent to a ModuleGeneratorThreadView thread.
+// element is written to Bytes sent to a ModuleGeneratorThreadView thread.
 // Once created, the Vectors are never resized.
 
 struct TableModuleGeneratorData
 {
     uint32_t globalDataOffset;
     uint32_t numElems;
     Uint32Vector elemFuncIndices;
 
@@ -197,18 +197,18 @@ class MOZ_STACK_CLASS ModuleGenerator
     // Parallel compilation
     bool                            parallel_;
     uint32_t                        outstanding_;
     UniqueModuleGeneratorThreadView threadView_;
     Vector<IonCompileTask>          tasks_;
     Vector<IonCompileTask*>         freeTasks_;
 
     // Assertions
-    DebugOnly<FunctionGenerator*>   activeFunc_;
-    DebugOnly<bool>                 finishedFuncs_;
+    FunctionGenerator*              activeFunc_;
+    bool                            finishedFuncs_;
 
     bool finishOutstandingTask();
     bool funcIsDefined(uint32_t funcIndex) const;
     uint32_t funcEntry(uint32_t funcIndex) const;
     bool convertOutOfRangeBranchesToThunks();
     bool finishTask(IonCompileTask* task);
     bool finishCodegen(StaticLinkData* link);
     bool finishStaticLinkData(uint8_t* code, uint32_t codeBytes, StaticLinkData* link);
@@ -283,33 +283,33 @@ class MOZ_STACK_CLASS ModuleGenerator
 // anything else. After the body is complete, ModuleGenerator::finishFunc must
 // be called before the FunctionGenerator is destroyed and the next function is
 // started.
 
 class MOZ_STACK_CLASS FunctionGenerator
 {
     friend class ModuleGenerator;
 
-    ModuleGenerator*   m_;
-    IonCompileTask*    task_;
+    ModuleGenerator* m_;
+    IonCompileTask*  task_;
 
     // Data created during function generation, then handed over to the
-    // FuncBytecode in ModuleGenerator::finishFunc().
-    UniqueBytecode     bytecode_;
-    Uint32Vector       callSiteLineNums_;
+    // FuncBytes in ModuleGenerator::finishFunc().
+    Bytes            bytes_;
+    Uint32Vector     callSiteLineNums_;
 
     uint32_t lineOrBytecode_;
 
   public:
     FunctionGenerator()
       : m_(nullptr), task_(nullptr), lineOrBytecode_(0)
     {}
 
-    Bytecode& bytecode() const {
-        return *bytecode_;
+    Bytes& bytes() {
+        return bytes_;
     }
     bool addCallSiteLineNum(uint32_t lineno) {
         return callSiteLineNums_.append(lineno);
     }
 };
 
 } // namespace wasm
 } // namespace js
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -35,17 +35,17 @@ typedef Vector<MBasicBlock*, 8, SystemAl
 // MIR graph.
 class FunctionCompiler
 {
   private:
     typedef Vector<BlockVector, 0, SystemAllocPolicy> BlocksVector;
 
     ModuleGeneratorThreadView& mg_;
     Decoder&                   decoder_;
-    const FuncBytecode&        func_;
+    const FuncBytes&           func_;
     const ValTypeVector&       locals_;
     size_t                     lastReadCallSite_;
 
     TempAllocator&             alloc_;
     MIRGraph&                  graph_;
     const CompileInfo&         info_;
     MIRGenerator&              mirGen_;
 
@@ -55,17 +55,17 @@ class FunctionCompiler
     uint32_t                   blockDepth_;
     BlocksVector               targets_;
 
     FuncCompileResults&        compileResults_;
 
   public:
     FunctionCompiler(ModuleGeneratorThreadView& mg,
                      Decoder& decoder,
-                     const FuncBytecode& func,
+                     const FuncBytes& func,
                      const ValTypeVector& locals,
                      MIRGenerator& mirGen,
                      FuncCompileResults& compileResults)
       : mg_(mg),
         decoder_(decoder),
         func_(func),
         locals_(locals),
         lastReadCallSite_(0),
@@ -148,17 +148,17 @@ class FunctionCompiler
         MOZ_ASSERT(loopDepth_ == 0);
         MOZ_ASSERT(blockDepth_ == 0);
 #ifdef DEBUG
         for (BlockVector& vec : targets_) {
             MOZ_ASSERT(vec.empty());
         }
 #endif
         MOZ_ASSERT(inDeadCode());
-        MOZ_ASSERT(decoder_.done(), "all bytecode must be consumed");
+        MOZ_ASSERT(decoder_.done(), "all bytes must be consumed");
         MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
     }
 
     /************************* Read-only interface (after local scope setup) */
 
     MIRGenerator&       mirGen() const     { return mirGen_; }
     MIRGraph&           mirGraph() const   { return graph_; }
     const CompileInfo&  info() const       { return info_; }
@@ -3043,20 +3043,20 @@ EmitExpr(FunctionCompiler& f, MDefinitio
     MOZ_CRASH("unexpected wasm opcode");
 }
 
 bool
 wasm::IonCompileFunction(IonCompileTask* task)
 {
     int64_t before = PRMJ_Now();
 
-    const FuncBytecode& func = task->func();
+    const FuncBytes& func = task->func();
     FuncCompileResults& results = task->results();
 
-    Decoder d(func.bytecode());
+    Decoder d(func.bytes());
 
     // Build the local types vector.
 
     ValTypeVector locals;
     if (!locals.appendAll(func.sig().args()))
         return false;
     if (!DecodeLocalEntries(d, &locals))
         return false;
--- a/js/src/asmjs/WasmIonCompile.h
+++ b/js/src/asmjs/WasmIonCompile.h
@@ -26,62 +26,58 @@ namespace js {
 namespace wasm {
 
 class ModuleGeneratorThreadView;
 
 typedef Vector<jit::MIRType, 8, SystemAllocPolicy> MIRTypeVector;
 typedef jit::ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
 typedef jit::ABIArgIter<ValTypeVector> ABIArgValTypeIter;
 
-// 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.
+// The FuncBytes class represents a single, concurrently-compilable function.
+// A FuncBytes object is composed of the wasm function body bytes along with the
+// ambient metadata describing the function necessary to compile it.
 
-class FuncBytecode
+class FuncBytes
 {
-    // Function metadata
+    Bytes              bytes_;
+    uint32_t           index_;
     const DeclaredSig& sig_;
-    uint32_t lineOrBytecode_;
-    Uint32Vector callSiteLineNums_;
-
-    // Compilation bookkeeping
-    uint32_t index_;
-    unsigned generateTime_;
-
-    UniqueBytecode bytecode_;
+    uint32_t           lineOrBytecode_;
+    Uint32Vector       callSiteLineNums_;
+    unsigned           generateTime_;
 
   public:
-    FuncBytecode(uint32_t index,
-                 const DeclaredSig& sig,
-                 UniqueBytecode bytecode,
-                 uint32_t lineOrBytecode,
-                 Uint32Vector&& callSiteLineNums,
-                 unsigned generateTime)
-      : sig_(sig),
+    FuncBytes(Bytes&& bytes,
+              uint32_t index,
+              const DeclaredSig& sig,
+              uint32_t lineOrBytecode,
+              Uint32Vector&& callSiteLineNums,
+              unsigned generateTime)
+      : bytes_(Move(bytes)),
+        index_(index),
+        sig_(sig),
         lineOrBytecode_(lineOrBytecode),
         callSiteLineNums_(Move(callSiteLineNums)),
-        index_(index),
-        generateTime_(generateTime),
-        bytecode_(Move(bytecode))
+        generateTime_(generateTime)
     {}
 
-    UniqueBytecode recycleBytecode() { return Move(bytecode_); }
-
+    Bytes& bytes() { return bytes_; }
+    const Bytes& bytes() const { return bytes_; }
+    uint32_t index() const { return index_; }
+    const DeclaredSig& sig() const { return sig_; }
     uint32_t lineOrBytecode() const { return lineOrBytecode_; }
     const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
-    uint32_t index() const { return index_; }
-    const DeclaredSig& sig() const { return sig_; }
-    const Bytecode& bytecode() const { return *bytecode_; }
     unsigned generateTime() const { return generateTime_; }
 };
 
-typedef UniquePtr<FuncBytecode> UniqueFuncBytecode;
+typedef UniquePtr<FuncBytes> UniqueFuncBytes;
 
-// The FuncCompileResults contains the results of compiling a single function
-// body, ready to be merged into the whole-module MacroAssembler.
+// The FuncCompileResults class contains the results of compiling a single
+// function body, ready to be merged into the whole-module MacroAssembler.
+
 class FuncCompileResults
 {
     jit::TempAllocator alloc_;
     jit::MacroAssembler masm_;
     FuncOffsets offsets_;
     unsigned compileTime_;
 
     FuncCompileResults(const FuncCompileResults&) = delete;
@@ -103,23 +99,24 @@ class FuncCompileResults
 };
 
 // An IonCompileTask represents the task of compiling a single function body. An
 // IonCompileTask is filled with the wasm code to be compiled on the main
 // validation thread, sent off to an Ion compilation helper thread which creates
 // the FuncCompileResults, and finally sent back to the validation thread. To
 // save time allocating and freeing memory, IonCompileTasks are reset() and
 // reused.
+
 class IonCompileTask
 {
-    JSRuntime* const runtime_;
+    JSRuntime* const           runtime_;
     ModuleGeneratorThreadView& mg_;
-    LifoAlloc lifo_;
-    UniqueFuncBytecode func_;
-    mozilla::Maybe<FuncCompileResults> results_;
+    LifoAlloc                  lifo_;
+    UniqueFuncBytes            func_;
+    Maybe<FuncCompileResults>  results_;
 
     IonCompileTask(const IonCompileTask&) = delete;
     IonCompileTask& operator=(const IonCompileTask&) = delete;
 
   public:
     IonCompileTask(JSRuntime* rt, ModuleGeneratorThreadView& mg, size_t defaultChunkSize)
       : runtime_(rt), mg_(mg), lifo_(defaultChunkSize), func_(nullptr)
     {}
@@ -127,31 +124,31 @@ class IonCompileTask
         return runtime_;
     }
     LifoAlloc& lifo() {
         return lifo_;
     }
     ModuleGeneratorThreadView& mg() const {
         return mg_;
     }
-    void init(UniqueFuncBytecode func) {
+    void init(UniqueFuncBytes func) {
         MOZ_ASSERT(!func_);
-        func_ = mozilla::Move(func);
+        func_ = Move(func);
         results_.emplace(lifo_);
     }
-    const FuncBytecode& func() const {
+    const FuncBytes& func() const {
         MOZ_ASSERT(func_);
         return *func_;
     }
     FuncCompileResults& results() {
         return *results_;
     }
-    void reset(UniqueBytecode* recycled) {
+    void reset(Bytes* recycled) {
         if (func_)
-            *recycled = func_->recycleBytecode();
+            *recycled = Move(func_->bytes());
         func_.reset(nullptr);
         results_.reset();
         lifo_.releaseAll();
     }
 };
 
 bool
 IonCompileFunction(IonCompileTask* task);
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -4019,65 +4019,61 @@ EncodeDataSegments(Encoder& e, WasmAstMo
         if (!EncodeDataSegment(e, *segment))
             return false;
     }
 
     e.finishSection(offset);
     return true;
 }
 
-static UniqueBytecode
-EncodeModule(WasmAstModule& module)
+static bool
+EncodeModule(WasmAstModule& module, Bytes* bytes)
 {
-    UniqueBytecode bytecode = MakeUnique<Bytecode>();
-    if (!bytecode)
-        return nullptr;
-
-    Encoder e(*bytecode);
+    Encoder e(*bytes);
 
     if (!e.writeFixedU32(MagicNumber))
-        return nullptr;
+        return false;
 
     if (!e.writeFixedU32(EncodingVersion))
-        return nullptr;
+        return false;
 
     if (!EncodeSignatures(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeImportTable(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeFunctionSignatures(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeFunctionTable(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeMemory(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeExportTable(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeFunctionBodies(e, module))
-        return nullptr;
+        return false;
 
     if (!EncodeDataSegments(e, module))
-        return nullptr;
-
-    return Move(bytecode);
+        return false;
+
+    return true;
 }
 
 /*****************************************************************************/
 
-UniqueBytecode
-wasm::TextToBinary(const char16_t* text, UniqueChars* error)
+bool
+wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
 {
     LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
     WasmAstModule* module = ParseModule(text, lifo, error);
     if (!module)
-        return nullptr;
+        return false;
 
     if (!ResolveModule(lifo, module, error))
-        return nullptr;
-
-    return EncodeModule(*module);
+        return false;
+
+    return EncodeModule(*module, bytes);
 }
--- a/js/src/asmjs/WasmText.h
+++ b/js/src/asmjs/WasmText.h
@@ -21,18 +21,18 @@
 
 #include "asmjs/WasmBinary.h"
 #include "js/Utility.h"
 
 namespace js {
 namespace wasm {
 
 // Translate the textual representation of a wasm module (given by a
-// null-terminated char16_t array) into a Bytecode object. If there is an error
+// null-terminated char16_t array) into serialized bytes. If there is an error
 // other than out-of-memory an error message string will be stored in 'error'.
 
-extern UniqueBytecode
-TextToBinary(const char16_t* text, UniqueChars* error);
+extern bool
+TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error);
 
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_text_h
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -16,16 +16,17 @@
  * limitations under the License.
  */
 
 #ifndef wasm_types_h
 #define wasm_types_h
 
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 
 #include "NamespaceImports.h"
 
 #include "asmjs/WasmBinary.h"
 #include "ds/LifoAlloc.h"
 #include "jit/IonTypes.h"
 #include "js/UniquePtr.h"
@@ -34,16 +35,17 @@
 
 namespace js {
 
 class PropertyName;
 
 namespace wasm {
 
 using mozilla::EnumeratedArray;
+using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::MallocSizeOf;
 
 typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
 
 // ValType/ExprType utilities
 
 static inline bool
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -520,29 +520,29 @@ WasmTextToBinary(JSContext* cx, unsigned
         ReportUsageError(cx, callee, "First argument must be a String");
         return false;
     }
 
     AutoStableStringChars twoByteChars(cx);
     if (!twoByteChars.initTwoByte(cx, args[0].toString()))
         return false;
 
+    wasm::Bytes bytes;
     UniqueChars error;
-    wasm::UniqueBytecode bytes = wasm::TextToBinary(twoByteChars.twoByteChars(), &error);
-    if (!bytes) {
+    if (!wasm::TextToBinary(twoByteChars.twoByteChars(), &bytes, &error)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
                              error.get() ? error.get() : "out of memory");
         return false;
     }
 
-    RootedObject obj(cx, JS_NewUint8Array(cx, bytes->length()));
+    RootedObject obj(cx, JS_NewUint8Array(cx, bytes.length()));
     if (!obj)
         return false;
 
-    memcpy(obj->as<TypedArrayObject>().viewDataUnshared(), bytes->begin(), bytes->length());
+    memcpy(obj->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 IsLazyFunction(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/jsapi-tests/testWasmLEB128.cpp
+++ b/js/src/jsapi-tests/testWasmLEB128.cpp
@@ -38,73 +38,73 @@ static bool WriteValidBytes(js::wasm::En
     return true;
 }
 
 BEGIN_TEST(testWasmLEB128_encoding)
 {
     using namespace js;
     using namespace wasm;
 
-    Bytecode bc;
-    Encoder encoder(bc);
+    Bytes bytes;
+    Encoder encoder(bytes);
 
     bool passed;
     if (!WriteValidBytes(encoder, &passed))
         return false;
     CHECK(passed);
 
     size_t i = 0;
-    CHECK(bc[i++] == 0x0);
-    CHECK(bc[i++] == 0x1);
-    CHECK(bc[i++] == 0x42);
+    CHECK(bytes[i++] == 0x0);
+    CHECK(bytes[i++] == 0x1);
+    CHECK(bytes[i++] == 0x42);
 
-    CHECK(bc[i++] == 0x80);
-    CHECK(bc[i++] == 0x01);
+    CHECK(bytes[i++] == 0x80);
+    CHECK(bytes[i++] == 0x01);
 
-    CHECK(bc[i++] == 0x80);
-    CHECK(bc[i++] == 0x03);
+    CHECK(bytes[i++] == 0x80);
+    CHECK(bytes[i++] == 0x03);
 
-    if (i + 1 < bc.length())
-        CHECK(bc[i++] == 0x00);
+    if (i + 1 < bytes.length())
+        CHECK(bytes[i++] == 0x00);
     return true;
 }
 END_TEST(testWasmLEB128_encoding)
 
 BEGIN_TEST(testWasmLEB128_valid_decoding)
 {
     using namespace js;
     using namespace wasm;
 
-    Bytecode bc;
-    if (!bc.append(0x0) || !bc.append(0x1) || !bc.append(0x42))
+    Bytes bytes;
+    if (!bytes.append(0x0) || !bytes.append(0x1) || !bytes.append(0x42))
         return false;
 
-    if (!bc.append(0x80) || !bc.append(0x01))
+    if (!bytes.append(0x80) || !bytes.append(0x01))
         return false;
 
-    if (!bc.append(0x80) || !bc.append(0x03))
+    if (!bytes.append(0x80) || !bytes.append(0x03))
         return false;
 
     {
         // Fallible decoding
-        Decoder decoder(bc);
+        Decoder decoder(bytes);
         uint32_t value;
 
         CHECK(decoder.readVarU32(&value) && value == 0x0);
         CHECK(decoder.readVarU32(&value) && value == 0x1);
         CHECK(decoder.readVarU32(&value) && value == 0x42);
         CHECK(decoder.readVarU32(&value) && value == 0x80);
         CHECK(decoder.readVarU32(&value) && value == 0x180);
 
         CHECK(decoder.done());
     }
 
     {
         // Infallible decoding
-        Decoder decoder(bc);
+        Decoder decoder(bytes);
         uint32_t value;
 
         value = decoder.uncheckedReadVarU32();
         CHECK(value == 0x0);
         value = decoder.uncheckedReadVarU32();
         CHECK(value == 0x1);
         value = decoder.uncheckedReadVarU32();
         CHECK(value == 0x42);
@@ -119,48 +119,48 @@ BEGIN_TEST(testWasmLEB128_valid_decoding
 }
 END_TEST(testWasmLEB128_valid_decoding)
 
 BEGIN_TEST(testWasmLEB128_invalid_decoding)
 {
     using namespace js;
     using namespace wasm;
 
-    Bytecode bc;
+    Bytes bytes;
     // Fill bits as per 28 encoded bits
-    if (!bc.append(0x80) || !bc.append(0x80) || !bc.append(0x80) || !bc.append(0x80))
+    if (!bytes.append(0x80) || !bytes.append(0x80) || !bytes.append(0x80) || !bytes.append(0x80))
         return false;
 
     // Test last valid values
-    if (!bc.append(0x00))
+    if (!bytes.append(0x00))
         return false;
 
     for (uint8_t i = 0; i < 0x0F; i++) {
-        bc[4] = i;
+        bytes[4] = i;
 
         {
-            Decoder decoder(bc);
+            Decoder decoder(bytes);
             uint32_t value;
             CHECK(decoder.readVarU32(&value));
             CHECK(value == uint32_t(i << 28));
             CHECK(decoder.done());
         }
 
         {
-            Decoder decoder(bc);
+            Decoder decoder(bytes);
             uint32_t value = decoder.uncheckedReadVarU32();
             CHECK(value == uint32_t(i << 28));
             CHECK(decoder.done());
         }
     }
 
     // Test all invalid values of the same size
     for (uint8_t i = 0x10; i < 0xF0; i++) {
-        bc[4] = i;
+        bytes[4] = i;
 
-        Decoder decoder(bc);
+        Decoder decoder(bytes);
         uint32_t value;
         CHECK(!decoder.readVarU32(&value));
     }
 
     return true;
 }
 END_TEST(testWasmLEB128_invalid_decoding)