new file mode 100644
--- /dev/null
+++ b/js/src/asmjs/WasmAST.h
@@ -0,0 +1,765 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2015 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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 wasmast_h
+#define wasmast_h
+
+#include "asmjs/WasmTypes.h"
+
+#include "ds/LifoAlloc.h"
+#include "js/HashTable.h"
+#include "js/Vector.h"
+
+namespace js {
+namespace wasm {
+
+const uint32_t AstNoIndex = UINT32_MAX;
+const unsigned AST_LIFO_DEFAULT_CHUNK_SIZE = 4096;
+
+/*****************************************************************************/
+// wasm AST
+
+class AstExpr;
+
+template <class T>
+using AstVector = mozilla::Vector<T, 0, LifoAllocPolicy<Fallible>>;
+
+template <class K, class V, class HP>
+using AstHashMap = HashMap<K, V, HP, LifoAllocPolicy<Fallible>>;
+
+class AstName
+{
+ const char16_t* begin_;
+ const char16_t* end_;
+ public:
+ AstName(const char16_t* begin, size_t length) : begin_(begin), end_(begin + length) {}
+ AstName() : begin_(nullptr), end_(nullptr) {}
+ const char16_t* begin() const { return begin_; }
+ const char16_t* end() const { return end_; }
+ size_t length() const { return end_ - begin_; }
+ bool empty() const { return begin_ == nullptr; }
+
+ bool operator==(AstName rhs) const {
+ if (length() != rhs.length())
+ return false;
+ if (begin() == rhs.begin())
+ return true;
+ return EqualChars(begin(), rhs.begin(), length());
+ }
+ bool operator!=(AstName rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+class AstRef
+{
+ AstName name_;
+ uint32_t index_;
+
+ public:
+ AstRef()
+ : index_(AstNoIndex)
+ {
+ MOZ_ASSERT(isInvalid());
+ }
+ AstRef(AstName name, uint32_t index)
+ : name_(name), index_(index)
+ {
+ MOZ_ASSERT(name.empty() ^ (index == AstNoIndex));
+ MOZ_ASSERT(!isInvalid());
+ }
+ bool isInvalid() const {
+ return name_.empty() && index_ == AstNoIndex;
+ }
+ AstName name() const {
+ return name_;
+ }
+ size_t index() const {
+ MOZ_ASSERT(index_ != AstNoIndex);
+ return index_;
+ }
+ void setIndex(uint32_t index) {
+ MOZ_ASSERT(index_ == AstNoIndex);
+ index_ = index;
+ }
+};
+
+struct AstNameHasher
+{
+ typedef const AstName Lookup;
+ static js::HashNumber hash(Lookup l) {
+ return mozilla::HashString(l.begin(), l.length());
+ }
+ static bool match(const AstName key, Lookup lookup) {
+ return key == lookup;
+ }
+};
+
+using AstNameMap = AstHashMap<AstName, uint32_t, AstNameHasher>;
+
+typedef AstVector<ValType> AstValTypeVector;
+typedef AstVector<AstExpr*> AstExprVector;
+typedef AstVector<AstName> AstNameVector;
+typedef AstVector<AstRef> AstRefVector;
+
+struct AstBase
+{
+ void* operator new(size_t numBytes, LifoAlloc& astLifo) throw() {
+ return astLifo.alloc(numBytes);
+ }
+};
+
+class AstSig : public AstBase
+{
+ AstName name_;
+ AstValTypeVector args_;
+ ExprType ret_;
+
+ public:
+ explicit AstSig(LifoAlloc& lifo)
+ : args_(lifo),
+ ret_(ExprType::Void)
+ {}
+ AstSig(AstValTypeVector&& args, ExprType ret)
+ : args_(Move(args)),
+ ret_(ret)
+ {}
+ AstSig(AstName name, AstSig&& rhs)
+ : name_(name),
+ args_(Move(rhs.args_)),
+ ret_(rhs.ret_)
+ {}
+ void operator=(AstSig&& rhs) {
+ args_ = Move(rhs.args_);
+ ret_ = rhs.ret_;
+ }
+ const AstValTypeVector& args() const {
+ return args_;
+ }
+ ExprType ret() const {
+ return ret_;
+ }
+ AstName name() const {
+ return name_;
+ }
+ bool operator==(const AstSig& rhs) const {
+ return ret() == rhs.ret() && EqualContainers(args(), rhs.args());
+ }
+
+ typedef const AstSig& Lookup;
+ static HashNumber hash(Lookup sig) {
+ return AddContainerToHash(sig.args(), HashNumber(sig.ret()));
+ }
+ static bool match(const AstSig* lhs, Lookup rhs) {
+ return *lhs == rhs;
+ }
+};
+
+class AstNode : public AstBase
+{};
+
+enum class AstExprKind
+{
+ BinaryOperator,
+ Block,
+ Branch,
+ BranchTable,
+ Call,
+ CallIndirect,
+ ComparisonOperator,
+ Const,
+ ConversionOperator,
+ GetLocal,
+ If,
+ Load,
+ Nop,
+ Return,
+ SetLocal,
+ Store,
+ TernaryOperator,
+ UnaryOperator,
+ Unreachable
+};
+
+class AstExpr : public AstNode
+{
+ const AstExprKind kind_;
+
+ protected:
+ explicit AstExpr(AstExprKind kind)
+ : kind_(kind)
+ {}
+
+ public:
+ AstExprKind kind() const { return kind_; }
+
+ template <class T>
+ T& as() {
+ MOZ_ASSERT(kind() == T::Kind);
+ return static_cast<T&>(*this);
+ }
+};
+
+struct AstNop : AstExpr
+{
+ static const AstExprKind Kind = AstExprKind::Nop;
+ AstNop()
+ : AstExpr(AstExprKind::Nop)
+ {}
+};
+
+struct AstUnreachable : AstExpr
+{
+ static const AstExprKind Kind = AstExprKind::Unreachable;
+ AstUnreachable()
+ : AstExpr(AstExprKind::Unreachable)
+ {}
+};
+
+class AstConst : public AstExpr
+{
+ const Val val_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Const;
+ explicit AstConst(Val val)
+ : AstExpr(Kind),
+ val_(val)
+ {}
+ Val val() const { return val_; }
+};
+
+class AstGetLocal : public AstExpr
+{
+ AstRef local_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::GetLocal;
+ explicit AstGetLocal(AstRef local)
+ : AstExpr(Kind),
+ local_(local)
+ {}
+ AstRef& local() {
+ return local_;
+ }
+};
+
+class AstSetLocal : public AstExpr
+{
+ AstRef local_;
+ AstExpr& value_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::SetLocal;
+ AstSetLocal(AstRef local, AstExpr& value)
+ : AstExpr(Kind),
+ local_(local),
+ value_(value)
+ {}
+ AstRef& local() {
+ return local_;
+ }
+ AstExpr& value() const {
+ return value_;
+ }
+};
+
+class AstBlock : public AstExpr
+{
+ Expr expr_;
+ AstName breakName_;
+ AstName continueName_;
+ AstExprVector exprs_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Block;
+ explicit AstBlock(Expr expr, AstName breakName,
+ AstName continueName, AstExprVector&& exprs)
+ : AstExpr(Kind),
+ expr_(expr),
+ breakName_(breakName),
+ continueName_(continueName),
+ exprs_(Move(exprs))
+ {}
+
+ Expr expr() const { return expr_; }
+ AstName breakName() const { return breakName_; }
+ AstName continueName() const { return continueName_; }
+ const AstExprVector& exprs() const { return exprs_; }
+};
+
+class AstBranch : public AstExpr
+{
+ Expr expr_;
+ AstExpr* cond_;
+ AstRef target_;
+ AstExpr* value_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Branch;
+ explicit AstBranch(Expr expr, AstExpr* cond, AstRef target, AstExpr* value)
+ : AstExpr(Kind),
+ expr_(expr),
+ cond_(cond),
+ target_(target),
+ value_(value)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstRef& target() { return target_; }
+ AstExpr& cond() const { MOZ_ASSERT(cond_); return *cond_; }
+ AstExpr* maybeValue() const { return value_; }
+};
+
+class AstCall : public AstExpr
+{
+ Expr expr_;
+ AstRef func_;
+ AstExprVector args_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Call;
+ AstCall(Expr expr, AstRef func, AstExprVector&& args)
+ : AstExpr(Kind), expr_(expr), func_(func), args_(Move(args))
+ {}
+
+ Expr expr() const { return expr_; }
+ AstRef& func() { return func_; }
+ const AstExprVector& args() const { return args_; }
+};
+
+class AstCallIndirect : public AstExpr
+{
+ AstRef sig_;
+ AstExpr* index_;
+ AstExprVector args_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::CallIndirect;
+ AstCallIndirect(AstRef sig, AstExpr* index, AstExprVector&& args)
+ : AstExpr(Kind), sig_(sig), index_(index), args_(Move(args))
+ {}
+ AstRef& sig() { return sig_; }
+ AstExpr* index() const { return index_; }
+ const AstExprVector& args() const { return args_; }
+};
+
+class AstReturn : public AstExpr
+{
+ AstExpr* maybeExpr_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Return;
+ explicit AstReturn(AstExpr* maybeExpr)
+ : AstExpr(Kind),
+ maybeExpr_(maybeExpr)
+ {}
+ AstExpr* maybeExpr() const { return maybeExpr_; }
+};
+
+class AstIf : public AstExpr
+{
+ AstExpr* cond_;
+ AstExpr* thenBranch_;
+ AstExpr* elseBranch_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::If;
+ AstIf(AstExpr* cond, AstExpr* thenBranch, AstExpr* elseBranch)
+ : AstExpr(Kind),
+ cond_(cond),
+ thenBranch_(thenBranch),
+ elseBranch_(elseBranch)
+ {}
+
+ AstExpr& cond() const { return *cond_; }
+ AstExpr& thenBranch() const { return *thenBranch_; }
+ bool hasElse() const { return !!elseBranch_; }
+ AstExpr& elseBranch() const { MOZ_ASSERT(hasElse()); return *elseBranch_; }
+};
+
+class AstLoadStoreAddress
+{
+ AstExpr* base_;
+ int32_t flags_;
+ int32_t offset_;
+
+ public:
+ explicit AstLoadStoreAddress(AstExpr* base, int32_t flags, int32_t offset)
+ : base_(base),
+ flags_(flags),
+ offset_(offset)
+ {}
+
+ AstExpr& base() const { return *base_; }
+ int32_t flags() const { return flags_; }
+ int32_t offset() const { return offset_; }
+};
+
+class AstLoad : public AstExpr
+{
+ Expr expr_;
+ AstLoadStoreAddress address_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Load;
+ explicit AstLoad(Expr expr, const AstLoadStoreAddress &address)
+ : AstExpr(Kind),
+ expr_(expr),
+ address_(address)
+ {}
+
+ Expr expr() const { return expr_; }
+ const AstLoadStoreAddress& address() const { return address_; }
+};
+
+class AstStore : public AstExpr
+{
+ Expr expr_;
+ AstLoadStoreAddress address_;
+ AstExpr* value_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::Store;
+ explicit AstStore(Expr expr, const AstLoadStoreAddress &address,
+ AstExpr* value)
+ : AstExpr(Kind),
+ expr_(expr),
+ address_(address),
+ value_(value)
+ {}
+
+ Expr expr() const { return expr_; }
+ const AstLoadStoreAddress& address() const { return address_; }
+ AstExpr& value() const { return *value_; }
+};
+
+class AstBranchTable : public AstExpr
+{
+ AstExpr& index_;
+ AstRef default_;
+ AstRefVector table_;
+ AstExpr* value_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::BranchTable;
+ explicit AstBranchTable(AstExpr& index, AstRef def, AstRefVector&& table,
+ AstExpr* maybeValue)
+ : AstExpr(Kind),
+ index_(index),
+ default_(def),
+ table_(Move(table)),
+ value_(maybeValue)
+ {}
+ AstExpr& index() const { return index_; }
+ AstRef& def() { return default_; }
+ AstRefVector& table() { return table_; }
+ AstExpr* maybeValue() { return value_; }
+};
+
+class AstFunc : public AstNode
+{
+ AstName name_;
+ AstRef sig_;
+ AstValTypeVector vars_;
+ AstNameVector localNames_;
+ AstExprVector body_;
+
+ public:
+ AstFunc(AstName name, AstRef sig, AstValTypeVector&& vars,
+ AstNameVector&& locals, AstExprVector&& body)
+ : name_(name),
+ sig_(sig),
+ vars_(Move(vars)),
+ localNames_(Move(locals)),
+ body_(Move(body))
+ {}
+ AstRef& sig() { return sig_; }
+ const AstValTypeVector& vars() const { return vars_; }
+ const AstNameVector& locals() const { return localNames_; }
+ const AstExprVector& body() const { return body_; }
+ AstName name() const { return name_; }
+};
+
+class AstImport : public AstNode
+{
+ AstName name_;
+ AstName module_;
+ AstName func_;
+ uint32_t sigIndex_;
+
+ public:
+ AstImport(AstName name, AstName module, AstName func, uint32_t sigIndex)
+ : name_(name), module_(module), func_(func), sigIndex_(sigIndex)
+ {}
+ AstName name() const { return name_; }
+ AstName module() const { return module_; }
+ AstName func() const { return func_; }
+ uint32_t sigIndex() const { return sigIndex_; }
+};
+
+enum class AstExportKind { Func, Memory };
+
+class AstExport : public AstNode
+{
+ AstName name_;
+ AstExportKind kind_;
+ AstRef func_;
+
+ public:
+ AstExport(AstName name, AstRef func)
+ : name_(name), kind_(AstExportKind::Func), func_(func)
+ {}
+ explicit AstExport(AstName name)
+ : name_(name), kind_(AstExportKind::Memory)
+ {}
+ AstName name() const { return name_; }
+ AstExportKind kind() const { return kind_; }
+ AstRef& func() { return func_; }
+};
+
+typedef AstVector<AstRef> AstTableElemVector;
+
+class AstTable : public AstNode
+{
+ AstTableElemVector elems_;
+
+ public:
+ explicit AstTable(AstTableElemVector&& elems) : elems_(Move(elems)) {}
+ AstTableElemVector& elems() { return elems_; }
+};
+
+class AstSegment : public AstNode
+{
+ uint32_t offset_;
+ AstName text_;
+
+ public:
+ AstSegment(uint32_t offset, AstName text)
+ : offset_(offset), text_(text)
+ {}
+ uint32_t offset() const { return offset_; }
+ AstName text() const { return text_; }
+};
+
+typedef AstVector<AstSegment*> AstSegmentVector;
+
+class AstMemory : public AstNode
+{
+ uint32_t initialSize_;
+ Maybe<uint32_t> maxSize_;
+ AstSegmentVector segments_;
+
+ public:
+ explicit AstMemory(uint32_t initialSize, Maybe<uint32_t> maxSize,
+ AstSegmentVector&& segments)
+ : initialSize_(initialSize),
+ maxSize_(maxSize),
+ segments_(Move(segments))
+ {}
+ uint32_t initialSize() const { return initialSize_; }
+ const Maybe<uint32_t>& maxSize() const { return maxSize_; }
+ const AstSegmentVector& segments() const { return segments_; }
+};
+
+class AstModule : public AstNode
+{
+ public:
+ typedef AstVector<AstFunc*> FuncVector;
+ typedef AstVector<AstImport*> ImportVector;
+ typedef AstVector<AstExport*> ExportVector;
+ typedef AstVector<AstSig*> SigVector;
+
+ private:
+ typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap;
+
+ LifoAlloc& lifo_;
+ AstMemory* memory_;
+ SigVector sigs_;
+ SigMap sigMap_;
+ ImportVector imports_;
+ ExportVector exports_;
+ AstTable* table_;
+ FuncVector funcs_;
+
+ public:
+ explicit AstModule(LifoAlloc& lifo)
+ : lifo_(lifo),
+ memory_(nullptr),
+ sigs_(lifo),
+ sigMap_(lifo),
+ imports_(lifo),
+ exports_(lifo),
+ table_(nullptr),
+ funcs_(lifo)
+ {}
+ bool init() {
+ return sigMap_.init();
+ }
+ bool setMemory(AstMemory* memory) {
+ if (memory_)
+ return false;
+ memory_ = memory;
+ return true;
+ }
+ AstMemory* maybeMemory() const {
+ return memory_;
+ }
+ bool declare(AstSig&& sig, uint32_t* sigIndex) {
+ SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
+ if (p) {
+ *sigIndex = p->value();
+ return true;
+ }
+ *sigIndex = sigs_.length();
+ auto* lifoSig = new (lifo_) AstSig(AstName(), Move(sig));
+ return lifoSig &&
+ sigs_.append(lifoSig) &&
+ sigMap_.add(p, sigs_.back(), *sigIndex);
+ }
+ bool append(AstSig* sig) {
+ uint32_t sigIndex = sigs_.length();
+ if (!sigs_.append(sig))
+ return false;
+ SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
+ return p || sigMap_.add(p, sig, sigIndex);
+ }
+ const SigVector& sigs() const {
+ return sigs_;
+ }
+ bool append(AstFunc* func) {
+ return funcs_.append(func);
+ }
+ const FuncVector& funcs() const {
+ return funcs_;
+ }
+ const ImportVector& imports() const {
+ return imports_;
+ }
+ bool append(AstImport* imp) {
+ return imports_.append(imp);
+ }
+ bool append(AstExport* exp) {
+ return exports_.append(exp);
+ }
+ const ExportVector& exports() const {
+ return exports_;
+ }
+ bool initTable(AstTable* table) {
+ if (table_)
+ return false;
+ table_ = table;
+ return true;
+ }
+ AstTable* maybeTable() const {
+ return table_;
+ }
+};
+
+class AstUnaryOperator final : public AstExpr
+{
+ Expr expr_;
+ AstExpr* op_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::UnaryOperator;
+ explicit AstUnaryOperator(Expr expr, AstExpr* op)
+ : AstExpr(Kind),
+ expr_(expr), op_(op)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstExpr* op() const { return op_; }
+};
+
+class AstBinaryOperator final : public AstExpr
+{
+ Expr expr_;
+ AstExpr* lhs_;
+ AstExpr* rhs_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::BinaryOperator;
+ explicit AstBinaryOperator(Expr expr, AstExpr* lhs, AstExpr* rhs)
+ : AstExpr(Kind),
+ expr_(expr), lhs_(lhs), rhs_(rhs)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstExpr* lhs() const { return lhs_; }
+ AstExpr* rhs() const { return rhs_; }
+};
+
+class AstTernaryOperator : public AstExpr
+{
+ Expr expr_;
+ AstExpr* op0_;
+ AstExpr* op1_;
+ AstExpr* op2_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::TernaryOperator;
+ AstTernaryOperator(Expr expr, AstExpr* op0, AstExpr* op1, AstExpr* op2)
+ : AstExpr(Kind),
+ expr_(expr), op0_(op0), op1_(op1), op2_(op2)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstExpr* op0() const { return op0_; }
+ AstExpr* op1() const { return op1_; }
+ AstExpr* op2() const { return op2_; }
+};
+
+class AstComparisonOperator final : public AstExpr
+{
+ Expr expr_;
+ AstExpr* lhs_;
+ AstExpr* rhs_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::ComparisonOperator;
+ explicit AstComparisonOperator(Expr expr, AstExpr* lhs, AstExpr* rhs)
+ : AstExpr(Kind),
+ expr_(expr), lhs_(lhs), rhs_(rhs)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstExpr* lhs() const { return lhs_; }
+ AstExpr* rhs() const { return rhs_; }
+};
+
+class AstConversionOperator final : public AstExpr
+{
+ Expr expr_;
+ AstExpr* op_;
+
+ public:
+ static const AstExprKind Kind = AstExprKind::ConversionOperator;
+ explicit AstConversionOperator(Expr expr, AstExpr* op)
+ : AstExpr(Kind),
+ expr_(expr), op_(op)
+ {}
+
+ Expr expr() const { return expr_; }
+ AstExpr* op() const { return op_; }
+};
+
+} // end wasm namespace
+} // end js namespace
+
+#endif // namespace wasmast_h
new file mode 100644
--- /dev/null
+++ b/js/src/asmjs/WasmBinaryToAST.cpp
@@ -0,0 +1,1387 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2016 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+#include "asmjs/WasmBinaryToAST.h"
+
+#include "mozilla/MathAlgorithms.h"
+
+#include "asmjs/Wasm.h"
+#include "asmjs/WasmBinaryIterator.h"
+
+using namespace js;
+using namespace js::wasm;
+
+using mozilla::FloorLog2;
+
+enum AstDecodeTerminationKind
+{
+ Unknown,
+ End,
+ Else
+};
+
+struct AstDecodeStackItem
+{
+ AstExpr* expr;
+ union {
+ uint32_t stackDelta;
+ AstDecodeTerminationKind terminationKind;
+ };
+
+ explicit AstDecodeStackItem(): expr(nullptr), terminationKind(AstDecodeTerminationKind::Unknown) {}
+ explicit AstDecodeStackItem(AstDecodeTerminationKind terminationKind): expr(nullptr), terminationKind(terminationKind) {}
+ explicit AstDecodeStackItem(AstExpr* expr): expr(expr), stackDelta(0) {}
+ explicit AstDecodeStackItem(AstExpr* expr, uint32_t stackDelta): expr(expr), stackDelta(stackDelta) {}
+};
+
+struct AstDecodePolicy : ExprIterPolicy
+{
+ static const bool Output = true;
+ typedef AstDecodeStackItem Value;
+};
+
+typedef ExprIter<AstDecodePolicy> AstDecodeExprIter;
+
+class AstDecodeContext
+{
+ public:
+ typedef AstVector<uint32_t> AstIndexVector;
+
+ JSContext* cx;
+ LifoAlloc& lifo;
+ Decoder& d;
+ bool generateNames;
+
+ uint32_t numTableElems;
+ Maybe<uint32_t> initialSizePages;
+ Maybe<uint32_t> maxSizePages;
+
+ private:
+ AstModule& module_;
+ AstIndexVector funcSigs_;
+ AstDecodeExprIter *iter_;
+ const ValTypeVector* locals_;
+
+ public:
+ AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module, bool generateNames)
+ : cx(cx),
+ lifo(lifo),
+ d(d),
+ generateNames(generateNames),
+ numTableElems(0),
+ initialSizePages(),
+ maxSizePages(),
+ module_(module),
+ funcSigs_(lifo),
+ iter_(nullptr),
+ locals_(nullptr)
+ {}
+
+ AstModule& module() { return module_; }
+ AstIndexVector& funcSigs() { return funcSigs_; }
+ AstDecodeExprIter& iter() { return *iter_; }
+ const ValTypeVector& locals() { return *locals_; }
+
+ void startFunction(AstDecodeExprIter *iter, const ValTypeVector* locals)
+ {
+ this->iter_ = iter;
+ this->locals_ = locals;
+ }
+ void endFunction()
+ {
+ this->iter_ = nullptr;
+ this->locals_ = nullptr;
+ }
+};
+
+static bool
+AstDecodeFail(AstDecodeContext& c, const char* str)
+{
+ uint32_t offset = c.d.currentOffset();
+ char offsetStr[sizeof "4294967295"];
+ JS_snprintf(offsetStr, sizeof offsetStr, "%" PRIu32, offset);
+ JS_ReportErrorNumber(c.cx, GetErrorMessage, nullptr, JSMSG_WASM_DECODE_FAIL, offsetStr, str);
+ return false;
+}
+
+static bool
+AstDecodeGenerateName(AstDecodeContext& c, const AstName& prefix, uint32_t index, AstName& name)
+{
+ if (!c.generateNames) {
+ name = AstName();
+ return true;
+ }
+
+ AstVector<char16_t> result(c.lifo);
+ if (!result.append(prefix.begin(), prefix.length()))
+ return false;
+ uint32_t tmp = index;
+ do {
+ if (!result.append(MOZ_UTF16('0')))
+ return false;
+ tmp /= 10;
+ } while (tmp);
+
+ if (index) {
+ char16_t* p = result.end();
+ for (tmp = index; tmp; tmp /= 10)
+ *(--p) = MOZ_UTF16('0' + (tmp % 10));
+ }
+
+ size_t length = result.length();
+ char16_t* begin = result.extractOrCopyRawBuffer();
+ if (!begin)
+ return false;
+
+ name = AstName(begin, length);
+ return true;
+}
+
+static bool
+AstDecodeGenerateRef(AstDecodeContext& c, const AstName& prefix, uint32_t index, AstRef& ref)
+{
+ MOZ_ASSERT(index != AstNoIndex);
+
+ if (!c.generateNames) {
+ ref = AstRef(AstName(), index);
+ return true;
+ }
+
+ AstName name;
+ if (!AstDecodeGenerateName(c, prefix, index, name))
+ return false;
+ MOZ_ASSERT(!name.empty());
+
+ ref = AstRef(name, AstNoIndex);
+ ref.setIndex(index);
+ return true;
+}
+
+static bool
+AstDecodeCallArgs(AstDecodeContext& c, uint32_t arity, const AstSig& sig, AstExprVector& funcArgs)
+{
+ if (arity != sig.args().length())
+ return c.iter().fail("call arity out of range");
+
+ const AstValTypeVector& args = sig.args();
+ uint32_t numArgs = args.length();
+
+ if (!funcArgs.resize(numArgs))
+ return false;
+
+ for (size_t i = 0; i < numArgs; ++i) {
+ ValType argType = args[i];
+ AstDecodeStackItem item;
+ if (!c.iter().readCallArg(argType, numArgs, i, &item))
+ return false;
+ funcArgs[i] = item.expr;
+ }
+
+ return c.iter().readCallArgsEnd(numArgs);
+}
+
+static bool
+AstDecodeCallReturn(AstDecodeContext& c, const AstSig& sig)
+{
+ return c.iter().readCallReturn(sig.ret());
+}
+
+static bool
+AstDecodeExpr(AstDecodeContext& c);
+
+static bool
+AstDecodeCall(AstDecodeContext& c)
+{
+ uint32_t calleeIndex;
+ uint32_t arity;
+ if (!c.iter().readCall(&calleeIndex, &arity))
+ return false;
+
+ if (calleeIndex >= c.funcSigs().length())
+ return c.iter().fail("callee index out of range");
+
+ uint32_t sigIndex = c.funcSigs()[calleeIndex];
+ const AstSig* sig = c.module().sigs()[sigIndex];
+ AstRef funcRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$func$"), 6), calleeIndex, funcRef))
+ return false;
+ AstExprVector args(c.lifo);
+ if (!AstDecodeCallArgs(c, arity, *sig, args) ||
+ !AstDecodeCallReturn(c, *sig))
+ return false;
+ AstCall* call = new(c.lifo) AstCall(Expr::Call, funcRef, Move(args));
+ c.iter().setResult(AstDecodeStackItem(call, args.length()));
+ return call;
+}
+
+static bool
+AstDecodeCallIndirect(AstDecodeContext& c)
+{
+ uint32_t sigIndex;
+ uint32_t arity;
+ if (!c.iter().readCallIndirect(&sigIndex, &arity))
+ return false;
+
+ if (sigIndex >= c.module().sigs().length())
+ return c.iter().fail("signature index out of range");
+
+ const AstSig* sig = c.module().sigs()[sigIndex];
+ AstExprVector args(c.lifo);
+ if (!AstDecodeCallArgs(c, arity, *sig, args))
+ return false;
+
+ AstDecodeStackItem index;
+ if (!c.iter().readCallIndirectCallee(&index))
+ return false;
+
+
+ if (!AstDecodeCallReturn(c, *sig))
+ return false;
+ AstRef sigRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, sigRef))
+ return false;
+ AstCallIndirect* call = new(c.lifo) AstCallIndirect(sigRef, index.expr, Move(args));
+ c.iter().setResult(AstDecodeStackItem(call, 1 + args.length()));
+ return call;
+}
+
+static bool
+AstDecodeCallImport(AstDecodeContext& c)
+{
+ uint32_t importIndex;
+ uint32_t arity;
+ if (!c.iter().readCallImport(&importIndex, &arity))
+ return false;
+
+ if (importIndex >= c.module().imports().length())
+ return c.iter().fail("import index out of range");
+
+ const AstImport* import = c.module().imports()[importIndex];
+ const AstSig* sig = c.module().sigs()[import->sigIndex()];
+ AstRef funcRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$import$"), 8), importIndex, funcRef))
+ return false;
+ AstExprVector args(c.lifo);
+ if (!AstDecodeCallArgs(c, arity, *sig, args) ||
+ !AstDecodeCallReturn(c, *sig))
+ return false;
+ AstCall* call = new(c.lifo) AstCall(Expr::CallImport, funcRef, Move(args));
+ c.iter().setResult(AstDecodeStackItem(call, args.length()));
+ return call;
+}
+
+static bool
+AstDecodeBrTable(AstDecodeContext& c)
+{
+ uint32_t tableLength;
+ ExprType type;
+ AstDecodeStackItem index;
+ AstDecodeStackItem value;
+ if (!c.iter().readBrTable(&tableLength, &type, &value, &index))
+ return false;
+
+ AstRefVector table(c.lifo);
+ if (!table.resize(tableLength))
+ return false;
+
+ uint32_t depth;
+ for (size_t i = 0, e = tableLength; i < e; ++i) {
+ if (!c.iter().readBrTableEntry(type, &depth))
+ return false;
+ table[i] = AstRef(AstName(), depth);
+ }
+
+ // Read the default label.
+ if (!c.iter().readBrTableEntry(type, &depth))
+ return false;
+ AstRef def(AstName(), depth);
+
+
+ AstBranchTable* branchTable = new(c.lifo) AstBranchTable(*index.expr, def, Move(table), value.expr);
+ c.iter().setResult(AstDecodeStackItem(branchTable, value.expr ? 2 : 1));
+ return branchTable;
+}
+
+static bool
+AstDecodeBlock(AstDecodeContext& c, Expr expr)
+{
+ MOZ_ASSERT(expr == Expr::Block || expr == Expr::Loop);
+
+ if (expr == Expr::Loop) {
+ if (!c.iter().readLoop())
+ return false;
+ } else {
+ if (!c.iter().readBlock())
+ return false;
+ }
+ AstExprVector exprs(c.lifo);
+ while (true) {
+ if (!AstDecodeExpr(c))
+ return false;
+ AstDecodeStackItem item = c.iter().getResult();
+ if (!item.expr) // Expr::End was found
+ break;
+ exprs.shrinkBy(item.stackDelta);
+ if (!exprs.append(item.expr))
+ return false;
+ }
+ AstBlock* block = new(c.lifo) AstBlock(expr, AstName(), AstName(), Move(exprs));
+ c.iter().setResult(AstDecodeStackItem(block));
+ return block;
+}
+
+static bool
+AstDecodeIf(AstDecodeContext& c)
+{
+ AstDecodeStackItem cond;
+ if (!c.iter().readIf(&cond))
+ return false;
+
+ if (!AstDecodeExpr(c))
+ return false;
+
+ AstDecodeStackItem nextItem;
+ AstDecodeStackItem thenItem = c.iter().getResult();
+ while (true) {
+ if (!AstDecodeExpr(c))
+ return false;
+ nextItem = c.iter().getResult();
+ if (!nextItem.expr)
+ break;
+ thenItem = nextItem;
+ }
+
+ AstDecodeStackItem elseItem;
+ if (nextItem.terminationKind == AstDecodeTerminationKind::Else) {
+ if (!AstDecodeExpr(c))
+ return false;
+ elseItem = c.iter().getResult();
+
+ while (true) {
+ if (!AstDecodeExpr(c))
+ return false;
+ nextItem = c.iter().getResult();
+ if (!nextItem.expr)
+ break;
+ elseItem = nextItem;
+ }
+ }
+
+ AstIf* if_ = new(c.lifo) AstIf(cond.expr, thenItem.expr, elseItem.expr);
+ c.iter().setResult(AstDecodeStackItem(if_, 1));
+ return if_;
+}
+
+static bool
+AstDecodeEnd(AstDecodeContext& c)
+{
+ LabelKind kind;
+ ExprType type;
+ AstDecodeStackItem tmp;
+ if (!c.iter().readEnd(&kind, &type, &tmp))
+ return false;
+
+ c.iter().setResult(AstDecodeStackItem(AstDecodeTerminationKind::End));
+ return true;
+}
+
+static bool
+AstDecodeElse(AstDecodeContext& c)
+{
+ ExprType type;
+ AstDecodeStackItem tmp;
+
+ if (!c.iter().readElse(&type, &tmp))
+ return false;
+
+ c.iter().setResult(AstDecodeStackItem(AstDecodeTerminationKind::Else));
+ return true;
+}
+
+static bool
+AstDecodeUnary(AstDecodeContext& c, ValType type, Expr expr)
+{
+ AstDecodeStackItem op;
+ if (!c.iter().readUnary(type, &op))
+ return false;
+ AstUnaryOperator* unary = new(c.lifo) AstUnaryOperator(expr, op.expr);
+ c.iter().setResult(AstDecodeStackItem(unary, 1));
+ return unary;
+}
+
+static bool
+AstDecodeBinary(AstDecodeContext& c, ValType type, Expr expr)
+{
+ AstDecodeStackItem lhs;
+ AstDecodeStackItem rhs;
+ if (!c.iter().readBinary(type, &lhs, &rhs))
+ return false;
+ AstBinaryOperator* binary = new(c.lifo) AstBinaryOperator(expr, lhs.expr, rhs.expr);
+ c.iter().setResult(AstDecodeStackItem(binary, 2));
+ return binary;
+}
+
+static bool
+AstDecodeSelect(AstDecodeContext& c)
+{
+ ExprType type;
+ AstDecodeStackItem cond;
+ AstDecodeStackItem selectTrue;
+ AstDecodeStackItem selectFalse;
+ if (!c.iter().readSelect(&type, &cond, &selectTrue, &selectFalse))
+ return false;
+ AstTernaryOperator* ternary = new(c.lifo) AstTernaryOperator(Expr::Select, cond.expr, selectTrue.expr, selectFalse.expr);
+ c.iter().setResult(AstDecodeStackItem(ternary, 3));
+ return ternary;
+}
+
+static bool
+AstDecodeComparison(AstDecodeContext& c, ValType type, Expr expr)
+{
+ AstDecodeStackItem lhs;
+ AstDecodeStackItem rhs;
+ if (!c.iter().readComparison(type, &lhs, &rhs))
+ return false;
+ AstComparisonOperator* comparison = new(c.lifo) AstComparisonOperator(expr, lhs.expr, rhs.expr);
+ c.iter().setResult(AstDecodeStackItem(comparison, 2));
+ return comparison;
+}
+
+static bool
+AstDecodeConversion(AstDecodeContext& c, ValType fromType, ValType toType, Expr expr)
+{
+ AstDecodeStackItem op;
+ if (!c.iter().readConversion(fromType, toType, &op))
+ return false;
+ AstConversionOperator* conversion = new(c.lifo) AstConversionOperator(expr, op.expr);
+ c.iter().setResult(AstDecodeStackItem(conversion, 1));
+ return conversion;
+}
+
+static AstLoadStoreAddress
+AstDecodeLoadStoreAddress(const LinearMemoryAddress<AstDecodeStackItem>& addr)
+{
+ uint32_t flags = FloorLog2(addr.align);
+ return AstLoadStoreAddress(addr.base.expr, flags, addr.offset);
+}
+
+static bool
+AstDecodeLoad(AstDecodeContext& c, ValType type, uint32_t byteSize, Expr expr)
+{
+ LinearMemoryAddress<AstDecodeStackItem> addr;
+ if (!c.iter().readLoad(type, byteSize, &addr))
+ return false;
+ AstLoad* load = new(c.lifo) AstLoad(expr, AstDecodeLoadStoreAddress(addr));
+ c.iter().setResult(AstDecodeStackItem(load, 1));
+ return load;
+}
+
+static bool
+AstDecodeStore(AstDecodeContext& c, ValType type, uint32_t byteSize, Expr expr)
+{
+ LinearMemoryAddress<AstDecodeStackItem> addr;
+ AstDecodeStackItem value;
+ if (!c.iter().readStore(type, byteSize, &addr, &value))
+ return false;
+ AstStore* store = new(c.lifo) AstStore(expr, AstDecodeLoadStoreAddress(addr), value.expr);
+ c.iter().setResult(AstDecodeStackItem(store, 2));
+ return store;
+}
+
+static bool
+AstDecodeBranch(AstDecodeContext& c, Expr expr)
+{
+ MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf);
+
+ uint32_t depth;
+ ExprType type;
+ AstDecodeStackItem value;
+ AstDecodeStackItem cond;
+ uint32_t stackDelta;
+ if (expr == Expr::Br) {
+ if (!c.iter().readBr(&depth, &type, &value))
+ return false;
+ stackDelta = value.expr ? 1 : 0;
+ } else {
+ if (!c.iter().readBrIf(&depth, &type, &value, &cond))
+ return false;
+ stackDelta = value.expr ? 2 : 1;
+ }
+
+ AstRef depthRef(AstName(), depth);
+ AstBranch* branch = new(c.lifo) AstBranch(expr, cond.expr, depthRef, value.expr);
+ c.iter().setResult(AstDecodeStackItem(branch, stackDelta));
+ return branch;
+}
+
+static bool
+AstDecodeGetLocal(AstDecodeContext& c)
+{
+ uint32_t getLocalId;
+ if (!c.iter().readGetLocal(c.locals(), &getLocalId))
+ return false;
+ AstRef localRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$var$"), 5), getLocalId, localRef))
+ return false;
+ AstGetLocal* getLocal = new(c.lifo) AstGetLocal(localRef);
+ c.iter().setResult(AstDecodeStackItem(getLocal));
+ return getLocal;
+}
+
+static bool
+AstDecodeSetLocal(AstDecodeContext& c)
+{
+ uint32_t setLocalId;
+ AstDecodeStackItem setLocalValue;
+ if (!c.iter().readSetLocal(c.locals(), &setLocalId, &setLocalValue))
+ return false;
+ AstRef localRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$var$"), 5), setLocalId, localRef))
+ return false;
+ AstSetLocal* setLocal = new(c.lifo) AstSetLocal(localRef, *setLocalValue.expr);
+ c.iter().setResult(AstDecodeStackItem(setLocal, 1));
+ return setLocal;
+}
+
+static bool
+AstDecodeReturn(AstDecodeContext& c)
+{
+ AstDecodeStackItem result;
+ if (!c.iter().readReturn(&result))
+ return false;
+ AstReturn* ret = new(c.lifo) AstReturn(result.expr);
+ c.iter().setResult(AstDecodeStackItem(ret, result.expr ? 1 : 0));
+ return ret;
+}
+
+static bool
+AstDecodeExpr(AstDecodeContext& c)
+{
+ Expr expr;
+ if (!c.iter().readExpr(&expr))
+ return false;
+
+ AstExpr* tmp;
+ switch (expr) {
+ case Expr::Nop:
+ if (!c.iter().readNullary())
+ return false;
+ tmp = new(c.lifo) AstNop();
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ case Expr::Call:
+ return AstDecodeCall(c);
+ case Expr::CallIndirect:
+ return AstDecodeCallIndirect(c);
+ case Expr::CallImport:
+ return AstDecodeCallImport(c);
+ case Expr::I32Const:
+ int32_t i32;
+ if (!c.iter().readI32Const(&i32))
+ return false;
+ tmp = new(c.lifo) AstConst(Val((uint32_t)i32));
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ case Expr::I64Const:
+ int64_t i64;
+ if (!c.iter().readI64Const(&i64))
+ return false;
+ tmp = new(c.lifo) AstConst(Val((uint64_t)i64));
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ case Expr::F32Const:
+ float f32;
+ if (!c.iter().readF32Const(&f32))
+ return false;
+ tmp = new(c.lifo) AstConst(Val(f32));
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ case Expr::F64Const:
+ double f64;
+ if (!c.iter().readF64Const(&f64))
+ return false;
+ tmp = new(c.lifo) AstConst(Val(f64));
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ case Expr::GetLocal:
+ return AstDecodeGetLocal(c);
+ case Expr::SetLocal:
+ return AstDecodeSetLocal(c);
+ case Expr::Select:
+ return AstDecodeSelect(c);
+ case Expr::Block:
+ case Expr::Loop:
+ return AstDecodeBlock(c, expr);
+ case Expr::If:
+ return AstDecodeIf(c);
+ case Expr::Else:
+ return AstDecodeElse(c);
+ case Expr::End:
+ return AstDecodeEnd(c);
+ case Expr::I32Clz:
+ case Expr::I32Ctz:
+ case Expr::I32Popcnt:
+ return AstDecodeUnary(c, ValType::I32, expr);
+ case Expr::I64Clz:
+ case Expr::I64Ctz:
+ case Expr::I64Popcnt:
+ return AstDecodeUnary(c, ValType::I64, expr);
+ case Expr::F32Abs:
+ case Expr::F32Neg:
+ case Expr::F32Ceil:
+ case Expr::F32Floor:
+ case Expr::F32Sqrt:
+ case Expr::F32Trunc:
+ case Expr::F32Nearest:
+ return AstDecodeUnary(c, ValType::F32, expr);
+ case Expr::F64Abs:
+ case Expr::F64Neg:
+ case Expr::F64Ceil:
+ case Expr::F64Floor:
+ case Expr::F64Sqrt:
+ case Expr::F64Trunc:
+ case Expr::F64Nearest:
+ return AstDecodeUnary(c, ValType::F64, expr);
+ case Expr::I32Add:
+ case Expr::I32Sub:
+ case Expr::I32Mul:
+ case Expr::I32DivS:
+ case Expr::I32DivU:
+ case Expr::I32RemS:
+ case Expr::I32RemU:
+ case Expr::I32And:
+ case Expr::I32Or:
+ case Expr::I32Xor:
+ case Expr::I32Shl:
+ case Expr::I32ShrS:
+ case Expr::I32ShrU:
+ case Expr::I32Rotl:
+ case Expr::I32Rotr:
+ return AstDecodeBinary(c, ValType::I32, expr);
+ case Expr::I64Add:
+ case Expr::I64Sub:
+ case Expr::I64Mul:
+ case Expr::I64DivS:
+ case Expr::I64DivU:
+ case Expr::I64RemS:
+ case Expr::I64RemU:
+ case Expr::I64And:
+ case Expr::I64Or:
+ case Expr::I64Xor:
+ case Expr::I64Shl:
+ case Expr::I64ShrS:
+ case Expr::I64ShrU:
+ case Expr::I64Rotl:
+ case Expr::I64Rotr:
+ return AstDecodeBinary(c, ValType::I64, expr);
+ case Expr::F32Add:
+ case Expr::F32Sub:
+ case Expr::F32Mul:
+ case Expr::F32Div:
+ case Expr::F32Min:
+ case Expr::F32Max:
+ case Expr::F32CopySign:
+ return AstDecodeBinary(c, ValType::F32, expr);
+ case Expr::F64Add:
+ case Expr::F64Sub:
+ case Expr::F64Mul:
+ case Expr::F64Div:
+ case Expr::F64Min:
+ case Expr::F64Max:
+ case Expr::F64CopySign:
+ return AstDecodeBinary(c, ValType::F64, expr);
+ case Expr::I32Eq:
+ case Expr::I32Ne:
+ case Expr::I32LtS:
+ case Expr::I32LtU:
+ case Expr::I32LeS:
+ case Expr::I32LeU:
+ case Expr::I32GtS:
+ case Expr::I32GtU:
+ case Expr::I32GeS:
+ case Expr::I32GeU:
+ return AstDecodeComparison(c, ValType::I32, expr);
+ case Expr::I64Eq:
+ case Expr::I64Ne:
+ case Expr::I64LtS:
+ case Expr::I64LtU:
+ case Expr::I64LeS:
+ case Expr::I64LeU:
+ case Expr::I64GtS:
+ case Expr::I64GtU:
+ case Expr::I64GeS:
+ case Expr::I64GeU:
+ return AstDecodeComparison(c, ValType::I64, expr);
+ case Expr::F32Eq:
+ case Expr::F32Ne:
+ case Expr::F32Lt:
+ case Expr::F32Le:
+ case Expr::F32Gt:
+ case Expr::F32Ge:
+ return AstDecodeComparison(c, ValType::F32, expr);
+ case Expr::F64Eq:
+ case Expr::F64Ne:
+ case Expr::F64Lt:
+ case Expr::F64Le:
+ case Expr::F64Gt:
+ case Expr::F64Ge:
+ return AstDecodeComparison(c, ValType::F64, expr);
+ case Expr::I32Eqz:
+ return AstDecodeConversion(c, ValType::I32, ValType::I32, expr);
+ case Expr::I64Eqz:
+ return AstDecodeConversion(c, ValType::I64, ValType::I32, expr);
+ case Expr::I32TruncSF32:
+ case Expr::I32TruncUF32:
+ case Expr::I32ReinterpretF32:
+ return AstDecodeConversion(c, ValType::F32, ValType::I32, expr);
+ case Expr::I32TruncSF64:
+ case Expr::I32TruncUF64:
+ return AstDecodeConversion(c, ValType::F64, ValType::I32, expr);
+ case Expr::I64ExtendSI32:
+ case Expr::I64ExtendUI32:
+ return AstDecodeConversion(c, ValType::I32, ValType::I64, expr);
+ case Expr::I64TruncSF32:
+ case Expr::I64TruncUF32:
+ return AstDecodeConversion(c, ValType::F32, ValType::I64, expr);
+ case Expr::I64TruncSF64:
+ case Expr::I64TruncUF64:
+ case Expr::I64ReinterpretF64:
+ return AstDecodeConversion(c, ValType::F64, ValType::I64, expr);
+ case Expr::F32ConvertSI32:
+ case Expr::F32ConvertUI32:
+ case Expr::F32ReinterpretI32:
+ return AstDecodeConversion(c, ValType::I32, ValType::F32, expr);
+ case Expr::F32ConvertSI64:
+ case Expr::F32ConvertUI64:
+ return AstDecodeConversion(c, ValType::I64, ValType::F32, expr);
+ case Expr::F32DemoteF64:
+ return AstDecodeConversion(c, ValType::F64, ValType::F32, expr);
+ case Expr::F64ConvertSI32:
+ case Expr::F64ConvertUI32:
+ return AstDecodeConversion(c, ValType::I32, ValType::F64, expr);
+ case Expr::F64ConvertSI64:
+ case Expr::F64ConvertUI64:
+ case Expr::F64ReinterpretI64:
+ return AstDecodeConversion(c, ValType::I64, ValType::F64, expr);
+ case Expr::F64PromoteF32:
+ return AstDecodeConversion(c, ValType::F32, ValType::F64, expr);
+ case Expr::I32Load8S:
+ case Expr::I32Load8U:
+ return AstDecodeLoad(c, ValType::I32, 1, expr);
+ case Expr::I32Load16S:
+ case Expr::I32Load16U:
+ return AstDecodeLoad(c, ValType::I32, 2, expr);
+ case Expr::I32Load:
+ return AstDecodeLoad(c, ValType::I32, 4, expr);
+ case Expr::I64Load8S:
+ case Expr::I64Load8U:
+ return AstDecodeLoad(c, ValType::I64, 1, expr);
+ case Expr::I64Load16S:
+ case Expr::I64Load16U:
+ return AstDecodeLoad(c, ValType::I64, 2, expr);
+ case Expr::I64Load32S:
+ case Expr::I64Load32U:
+ return AstDecodeLoad(c, ValType::I64, 4, expr);
+ case Expr::I64Load:
+ return AstDecodeLoad(c, ValType::I64, 8, expr);
+ case Expr::F32Load:
+ return AstDecodeLoad(c, ValType::F32, 4, expr);
+ case Expr::F64Load:
+ return AstDecodeLoad(c, ValType::F64, 8, expr);
+ case Expr::I32Store8:
+ return AstDecodeStore(c, ValType::I32, 1, expr);
+ case Expr::I32Store16:
+ return AstDecodeStore(c, ValType::I32, 2, expr);
+ case Expr::I32Store:
+ return AstDecodeStore(c, ValType::I32, 4, expr);
+ case Expr::I64Store8:
+ return AstDecodeStore(c, ValType::I64, 1, expr);
+ case Expr::I64Store16:
+ return AstDecodeStore(c, ValType::I64, 2, expr);
+ case Expr::I64Store32:
+ return AstDecodeStore(c, ValType::I64, 4, expr);
+ case Expr::I64Store:
+ return AstDecodeStore(c, ValType::I64, 8, expr);
+ case Expr::F32Store:
+ return AstDecodeStore(c, ValType::F32, 4, expr);
+ case Expr::F64Store:
+ return AstDecodeStore(c, ValType::F64, 8, expr);
+ case Expr::Br:
+ case Expr::BrIf:
+ return AstDecodeBranch(c, expr);
+ case Expr::BrTable:
+ return AstDecodeBrTable(c);
+ case Expr::Return:
+ return AstDecodeReturn(c);
+ case Expr::Unreachable:
+ if (!c.iter().readUnreachable())
+ return false;
+ tmp = new(c.lifo) AstUnreachable();
+ c.iter().setResult(AstDecodeStackItem(tmp));
+ return tmp;
+ default:
+ // Note: it's important not to remove this default since readExpr()
+ // can return Expr values for which there is no enumerator.
+ break;
+ }
+
+ return c.iter().unrecognizedOpcode(expr);
+}
+
+/*****************************************************************************/
+// wasm decoding and generation
+
+static bool
+AstDecodeTypeSection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(TypeSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ uint32_t numSigs;
+ if (!c.d.readVarU32(&numSigs))
+ return AstDecodeFail(c, "expected number of signatures");
+
+ if (numSigs > MaxSigs)
+ return AstDecodeFail(c, "too many signatures");
+
+ for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
+ uint32_t form;
+ if (!c.d.readVarU32(&form) || form != uint32_t(TypeConstructor::Function))
+ return AstDecodeFail(c, "expected function form");
+
+ uint32_t numArgs;
+ if (!c.d.readVarU32(&numArgs))
+ return AstDecodeFail(c, "bad number of function args");
+
+ if (numArgs > MaxArgsPerFunc)
+ return AstDecodeFail(c, "too many arguments in signature");
+
+ AstValTypeVector args(c.lifo);
+ if (!args.resize(numArgs))
+ return false;
+
+ for (uint32_t i = 0; i < numArgs; i++) {
+ if (!c.d.readValType(&args[i]))
+ return AstDecodeFail(c, "bad value type");
+ }
+
+ uint32_t numRets;
+ if (!c.d.readVarU32(&numRets))
+ return AstDecodeFail(c, "bad number of function returns");
+
+ if (numRets > 1)
+ return AstDecodeFail(c, "too many returns in signature");
+
+ ExprType result = ExprType::Void;
+
+ if (numRets == 1) {
+ ValType type;
+ if (!c.d.readValType(&type))
+ return AstDecodeFail(c, "bad expression type");
+
+ result = ToExprType(type);
+ }
+
+ AstSig sigNoName(Move(args), result);
+ AstName sigName;
+ if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, sigName))
+ return false;
+
+ AstSig* sig = new(c.lifo) AstSig(sigName, Move(sigNoName));
+ if (!c.module().append(sig))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "decls section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeSignatureIndex(AstDecodeContext& c, uint32_t* sigIndex)
+{
+ if (!c.d.readVarU32(sigIndex))
+ return AstDecodeFail(c, "expected signature index");
+
+ if (*sigIndex >= c.module().sigs().length())
+ return AstDecodeFail(c, "signature index out of range");
+
+ return true;
+}
+
+static bool
+AstDecodeFunctionSection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(FunctionSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ uint32_t numDecls;
+ if (!c.d.readVarU32(&numDecls))
+ return AstDecodeFail(c, "expected number of declarations");
+
+ if (numDecls > MaxFuncs)
+ return AstDecodeFail(c, "too many functions");
+
+
+ if (!c.funcSigs().resize(numDecls))
+ return false;
+
+ for (uint32_t i = 0; i < numDecls; i++) {
+ if (!AstDecodeSignatureIndex(c, &c.funcSigs()[i]))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "decls section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeTableSection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(TableSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ if (!c.d.readVarU32(&c.numTableElems))
+ return AstDecodeFail(c, "expected number of table elems");
+
+ if (c.numTableElems > MaxTableElems)
+ return AstDecodeFail(c, "too many table elements");
+
+ AstTableElemVector elems(c.lifo);
+ if (!elems.resize(c.numTableElems))
+ return false;
+
+ for (uint32_t i = 0; i < c.numTableElems; i++) {
+ uint32_t funcIndex;
+ if (!c.d.readVarU32(&funcIndex))
+ return AstDecodeFail(c, "expected table element");
+
+ if (funcIndex >= c.funcSigs().length())
+ return AstDecodeFail(c, "table element out of range");
+
+ elems[i] = AstRef(AstName(), funcIndex);
+ }
+
+ c.module().initTable(new(c.lifo) AstTable(Move(elems)));
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "table section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeName(AstDecodeContext& c, AstName* name)
+{
+ Bytes bytes;
+ if (!c.d.readBytes(&bytes))
+ return false;
+ size_t length = bytes.length();
+ char16_t *buffer = static_cast<char16_t *>(c.lifo.alloc(length * sizeof(char16_t)));
+ for (size_t i = 0; i < length; i++)
+ buffer[i] = bytes[i];
+ *name = AstName(buffer, length);
+ return true;
+}
+
+static bool
+AstDecodeImport(AstDecodeContext& c, uint32_t importIndex, AstImport** import)
+{
+ uint32_t sigIndex = AstNoIndex;
+ if (!AstDecodeSignatureIndex(c, &sigIndex))
+ return false;
+
+ AstName moduleName;
+ if (!AstDecodeName(c, &moduleName))
+ return AstDecodeFail(c, "expected import module name");
+
+ if (moduleName.empty())
+ return AstDecodeFail(c, "module name cannot be empty");
+
+ AstName funcName;
+ if (!AstDecodeName(c, &funcName))
+ return AstDecodeFail(c, "expected import func name");
+
+ AstName importName;
+ if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$import$"), 8), importIndex, importName))
+ return false;
+
+ *import = new(c.lifo) AstImport(importName, moduleName, funcName, sigIndex);
+ return *import;
+}
+
+static bool
+AstDecodeImportSection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(ImportSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ uint32_t numImports;
+ if (!c.d.readVarU32(&numImports))
+ return AstDecodeFail(c, "failed to read number of imports");
+
+ if (numImports > MaxImports)
+ return AstDecodeFail(c, "too many imports");
+
+ for (uint32_t i = 0; i < numImports; i++) {
+ AstImport* import;
+ if (!AstDecodeImport(c, i, &import))
+ return false;
+ if (!c.module().append(import))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "import section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeMemorySection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(MemorySectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ uint32_t initialSizePages;
+ if (!c.d.readVarU32(&initialSizePages))
+ return AstDecodeFail(c, "expected initial memory size");
+
+ CheckedInt<int32_t> initialSize = initialSizePages;
+ initialSize *= PageSize;
+ if (!initialSize.isValid())
+ return AstDecodeFail(c, "initial memory size too big");
+
+ uint32_t maxSizePages;
+ if (!c.d.readVarU32(&maxSizePages))
+ return AstDecodeFail(c, "expected initial memory size");
+
+ CheckedInt<int32_t> maxSize = maxSizePages;
+ maxSize *= PageSize;
+ if (!maxSize.isValid())
+ return AstDecodeFail(c, "initial memory size too big");
+
+ uint8_t exported;
+ if (!c.d.readFixedU8(&exported))
+ return AstDecodeFail(c, "expected exported byte");
+
+ c.initialSizePages.emplace(initialSizePages);
+ if (initialSizePages != maxSizePages) {
+ c.maxSizePages.emplace(maxSizePages);
+ }
+
+ if (exported) {
+ if (!c.module().append(new(c.lifo) AstExport(AstName(MOZ_UTF16("memory"), 6))))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "memory section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeFunctionExport(AstDecodeContext& c, AstExport** export_)
+{
+ uint32_t funcIndex;
+ if (!c.d.readVarU32(&funcIndex))
+ return AstDecodeFail(c, "expected export internal index");
+
+ if (funcIndex >= c.funcSigs().length())
+ return AstDecodeFail(c, "export function index out of range");
+
+ AstName fieldName;
+ if (!AstDecodeName(c, &fieldName))
+ return AstDecodeFail(c, "expected export name");
+
+ *export_ = new(c.lifo) AstExport(fieldName, AstRef(AstName(), funcIndex));
+ return *export_;
+}
+
+static bool
+AstDecodeExportSection(AstDecodeContext& c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(ExportSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ if (sectionStart == Decoder::NotStarted)
+ return true;
+
+ uint32_t numExports;
+ if (!c.d.readVarU32(&numExports))
+ return AstDecodeFail(c, "failed to read number of exports");
+
+ if (numExports > MaxExports)
+ return AstDecodeFail(c, "too many exports");
+
+ for (uint32_t i = 0; i < numExports; i++) {
+ AstExport* export_;
+ if (!AstDecodeFunctionExport(c, &export_))
+ return false;
+ if (!c.module().append(export_))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "export section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
+{
+ uint32_t bodySize;
+ if (!c.d.readVarU32(&bodySize))
+ return AstDecodeFail(c, "expected number of function body bytes");
+
+ if (c.d.bytesRemain() < bodySize)
+ return AstDecodeFail(c, "function body length too big");
+
+ const uint8_t* bodyBegin = c.d.currentPosition();
+ const uint8_t* bodyEnd = bodyBegin + bodySize;
+
+ AstDecodeExprIter iter(AstDecodePolicy(), c.d);
+
+ uint32_t sigIndex = c.funcSigs()[funcIndex];
+ const AstSig* sig = c.module().sigs()[sigIndex];
+
+ AstValTypeVector vars(c.lifo);
+ AstNameVector localsNames(c.lifo);
+ AstExprVector body(c.lifo);
+
+ ValTypeVector locals;
+ if (!locals.appendAll(sig->args()))
+ return false;
+
+ if (!DecodeLocalEntries(c.d, &locals))
+ return AstDecodeFail(c, "failed decoding local entries");
+
+ c.startFunction(&iter, &locals);
+
+ uint32_t numParams = sig->args().length();
+ uint32_t numLocals = locals.length();
+ for (uint32_t i = numParams; i < numLocals; i++) {
+ if (!vars.append(locals[i]))
+ return false;
+ }
+ for (uint32_t i = 0; i < numLocals; i++) {
+ AstName varName;
+ if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$var$"), 5), i, varName))
+ return false;
+ if (!localsNames.append(varName))
+ return false;
+ }
+
+ if (!c.iter().readFunctionStart())
+ return false;
+
+ while (c.d.currentPosition() < bodyEnd) {
+ if (!AstDecodeExpr(c))
+ return false;
+ AstDecodeStackItem item = c.iter().getResult();
+ body.shrinkBy(item.stackDelta);
+ if (!body.append(item.expr))
+ return false;
+ }
+
+ AstDecodeStackItem tmp;
+ if (!c.iter().readFunctionEnd(sig->ret(), &tmp))
+ return false;
+
+ c.endFunction();
+
+ if (c.d.currentPosition() != bodyEnd)
+ return AstDecodeFail(c, "function body length mismatch");
+
+ AstName funcName;
+ if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$func$"), 6), funcIndex, funcName))
+ return false;
+ AstRef sigRef;
+ if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, sigRef))
+ return false;
+ *func = new(c.lifo) AstFunc(funcName, sigRef,
+ Move(vars), Move(localsNames), Move(body));
+ return *func;
+}
+
+static bool
+AstDecodeCodeSection(AstDecodeContext &c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(CodeSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+
+ if (sectionStart == Decoder::NotStarted) {
+ if (c.funcSigs().length() != 0)
+ return AstDecodeFail(c, "expected function bodies");
+
+ return false;
+ }
+
+ uint32_t numFuncBodies;
+ if (!c.d.readVarU32(&numFuncBodies))
+ return AstDecodeFail(c, "expected function body count");
+
+ if (numFuncBodies != c.funcSigs().length())
+ return AstDecodeFail(c, "function body count does not match function signature count");
+
+ for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
+ AstFunc* func;
+ if (!AstDecodeFunctionBody(c, funcIndex, &func))
+ return false;
+ if (!c.module().append(func))
+ return false;
+ }
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "function section byte size mismatch");
+
+ return true;
+}
+
+static bool
+AstDecodeDataSection(AstDecodeContext &c)
+{
+ uint32_t sectionStart, sectionSize;
+ if (!c.d.startSection(DataSectionId, §ionStart, §ionSize))
+ return AstDecodeFail(c, "failed to start section");
+ AstSegmentVector segments(c.lifo);
+ if (sectionStart == Decoder::NotStarted) {
+ if (!c.initialSizePages)
+ return true;
+ c.module().setMemory(new(c.lifo) AstMemory(*c.initialSizePages, c.maxSizePages, Move(segments)));
+
+ return true;
+ }
+
+ uint32_t numSegments;
+ if (!c.d.readVarU32(&numSegments))
+ return AstDecodeFail(c, "failed to read number of data segments");
+
+ uint32_t initialSizePages = c.initialSizePages ? *c.initialSizePages : 0;
+ uint32_t heapLength = initialSizePages * PageSize;
+ uint32_t prevEnd = 0;
+
+ for (uint32_t i = 0; i < numSegments; i++) {
+ uint32_t dstOffset;
+ if (!c.d.readVarU32(&dstOffset))
+ return AstDecodeFail(c, "expected segment destination offset");
+
+ if (dstOffset < prevEnd)
+ return AstDecodeFail(c, "data segments must be disjoint and ordered");
+
+ uint32_t numBytes;
+ if (!c.d.readVarU32(&numBytes))
+ return AstDecodeFail(c, "expected segment size");
+
+ if (dstOffset > heapLength || heapLength - dstOffset < numBytes)
+ return AstDecodeFail(c, "data segment does not fit in memory");
+
+ const uint8_t* src;
+ if (!c.d.readBytesRaw(numBytes, &src))
+ return AstDecodeFail(c, "data segment shorter than declared");
+
+ char16_t *buffer = static_cast<char16_t *>(c.lifo.alloc(numBytes * sizeof(char16_t)));
+ for (size_t i = 0; i < numBytes; i++)
+ buffer[i] = src[i];
+ AstName name(buffer, numBytes);
+ if (!segments.append(new(c.lifo) AstSegment(dstOffset, name)))
+ return false;
+ prevEnd = dstOffset + numBytes;
+ }
+
+ c.module().setMemory(new(c.lifo) AstMemory(initialSizePages, c.maxSizePages, Move(segments)));
+
+ if (!c.d.finishSection(sectionStart, sectionSize))
+ return AstDecodeFail(c, "data section byte size mismatch");
+
+ return true;
+}
+
+
+bool
+wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length,
+ LifoAlloc& lifo, AstModule** module)
+{
+ AstModule* result = new(lifo) AstModule(lifo);
+ if (!result->init())
+ return false;
+
+ Decoder d(bytes, bytes + length);
+ AstDecodeContext c(cx, lifo, d, *result, true);
+
+ uint32_t u32;
+ if (!d.readFixedU32(&u32) || u32 != MagicNumber)
+ return AstDecodeFail(c, "failed to match magic number");
+
+ if (!d.readFixedU32(&u32) || u32 != EncodingVersion)
+ return AstDecodeFail(c, "failed to match binary version");
+
+ if (!AstDecodeTypeSection(c))
+ return false;
+
+ if (!AstDecodeImportSection(c))
+ return false;
+
+ if (!AstDecodeFunctionSection(c))
+ return false;
+
+ if (!AstDecodeTableSection(c))
+ return false;
+
+ if (!AstDecodeMemorySection(c))
+ return false;
+
+ if (!AstDecodeExportSection(c))
+ return false;
+
+ if (!AstDecodeCodeSection(c))
+ return false;
+
+ if (!AstDecodeDataSection(c))
+ return false;
+
+ while (!d.done()) {
+ if (!d.skipSection())
+ return AstDecodeFail(c, "failed to skip unknown section at end");
+ }
+
+ *module = result;
+ return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/asmjs/WasmBinaryToAST.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2015 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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 wasmbinarytoast_h
+#define wasmbinarytoast_h
+
+#include "asmjs/WasmAST.h"
+#include "asmjs/WasmTypes.h"
+
+#include "ds/LifoAlloc.h"
+
+namespace js {
+namespace wasm {
+
+bool
+BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAlloc& lifo, AstModule** module);
+
+} // end wasm namespace
+} // end js namespace
+
+#endif // namespace wasmbinarytoast_h
--- a/js/src/asmjs/WasmBinaryToText.cpp
+++ b/js/src/asmjs/WasmBinaryToText.cpp
@@ -19,61 +19,53 @@
#include "asmjs/WasmBinaryToText.h"
#include "mozilla/CheckedInt.h"
#include "jsnum.h"
#include "jsprf.h"
#include "asmjs/Wasm.h"
+#include "asmjs/WasmAST.h"
+#include "asmjs/WasmBinaryToAST.h"
#include "asmjs/WasmTypes.h"
#include "vm/ArrayBufferObject.h"
#include "vm/StringBuffer.h"
using namespace js;
using namespace js::wasm;
using mozilla::CheckedInt;
using mozilla::IsInfinite;
using mozilla::IsNaN;
using mozilla::IsNegativeZero;
struct WasmRenderContext
{
JSContext* cx;
- Decoder& d;
+ AstModule* module;
StringBuffer& buffer;
uint32_t indent;
DeclaredSigVector signatures;
Uint32Vector funcSigs;
Uint32Vector funcLocals;
Uint32Vector importSigs;
uint32_t currentFuncIndex;
- WasmRenderContext(JSContext* cx, Decoder& d, StringBuffer& buffer)
- : cx(cx), d(d), buffer(buffer), indent(0), currentFuncIndex(0)
+ WasmRenderContext(JSContext* cx, AstModule* module, StringBuffer& buffer)
+ : cx(cx), module(module), buffer(buffer), indent(0), currentFuncIndex(0)
{}
};
/*****************************************************************************/
// utilities
static bool
-RenderFail(WasmRenderContext& c, const char* str)
-{
- uint32_t offset = c.d.currentOffset();
- char offsetStr[sizeof "4294967295"];
- JS_snprintf(offsetStr, sizeof offsetStr, "%" PRIu32, offset);
- JS_ReportErrorNumber(c.cx, GetErrorMessage, nullptr, JSMSG_WASM_DECODE_FAIL, offsetStr, str);
- return false;
-}
-
-static bool
RenderIndent(WasmRenderContext& c)
{
for (uint32_t i = 0; i < c.indent; i++) {
if (!c.buffer.append(" "))
return false;
}
return true;
}
@@ -123,20 +115,22 @@ RenderDouble(WasmRenderContext& c, doubl
if (num > 0)
return c.buffer.append("infinity");
return c.buffer.append("-infinity");
}
return NumberValueToStringBuffer(c.cx, DoubleValue(num), c.buffer);
}
static bool
-RenderString(WasmRenderContext& c, const uint8_t* s, size_t length)
+RenderEscapedString(WasmRenderContext& c, const AstName& s)
{
+ size_t length = s.length();
+ const char16_t* p = s.begin();
for (size_t i = 0; i < length; i++) {
- uint8_t byte = s[i];
+ char16_t byte = p[i];
bool success;
switch (byte) {
case '\n': success = c.buffer.append("\\n"); break;
case '\r': success = c.buffer.append("\\0d"); break;
case '\t': success = c.buffer.append("\\t"); break;
case '\f': success = c.buffer.append("\\0c"); break;
case '\b': success = c.buffer.append("\\08"); break;
case '\\': success = c.buffer.append("\\\\"); break;
@@ -174,321 +168,211 @@ RenderExprType(WasmRenderContext& c, Exp
static bool
RenderValType(WasmRenderContext& c, ValType type)
{
return RenderExprType(c, ToExprType(type));
}
static bool
-RenderExpr(WasmRenderContext& c);
+RenderName(WasmRenderContext& c, const AstName& name)
+{
+ return c.buffer.append(name.begin(), name.end());
+}
static bool
-RenderFullLine(WasmRenderContext& c)
+RenderRef(WasmRenderContext& c, const AstRef& ref) {
+ return ref.name().empty() ? RenderInt32(c, ref.index()) : RenderName(c, ref.name());
+}
+
+static bool
+RenderExpr(WasmRenderContext& c, AstExpr& expr);
+
+static bool
+RenderFullLine(WasmRenderContext& c, AstExpr& expr)
{
if (!RenderIndent(c))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, expr))
return false;
return c.buffer.append('\n');
}
/*****************************************************************************/
// binary format parsing and rendering
static bool
-RenderNop(WasmRenderContext& c)
+RenderNop(WasmRenderContext& c, AstNop& nop)
{
return c.buffer.append("(nop)");
}
static bool
-RenderUnreachable(WasmRenderContext& c)
+RenderUnreachable(WasmRenderContext& c, AstUnreachable& unreachable)
{
return c.buffer.append("(trap)");
}
static bool
-RenderCallWithSig(WasmRenderContext& c, uint32_t sigIndex)
+RenderCallArgs(WasmRenderContext& c, const AstExprVector& args)
{
- const DeclaredSig& sig = c.signatures[sigIndex];
- for (uint32_t i = 0; i < sig.args().length(); i++) {
+ for (uint32_t i = 0; i < args.length(); i++) {
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *args[i]))
return false;
}
return true;
}
static bool
-RenderCall(WasmRenderContext& c)
+RenderCall(WasmRenderContext& c, AstCall& call)
{
- uint32_t funcIndex;
- if (!c.d.readVarU32(&funcIndex))
- return RenderFail(c, "unable to read import index");
-
- if (!c.buffer.append("(call $func$"))
+ if (call.expr() == Expr::Call) {
+ if (!c.buffer.append("(call "))
+ return false;
+ } else if (call.expr() == Expr::CallImport) {
+ if (!c.buffer.append("(call_import "))
+ return false;
+ } else
return false;
- if (!RenderInt32(c, funcIndex))
+ if (!RenderRef(c, call.func()))
return false;
-
- if (funcIndex >= c.funcSigs.length())
- return RenderFail(c, "callee index out of range");
-
- uint32_t sigIndex = c.funcSigs[funcIndex];
- if (!RenderCallWithSig(c, sigIndex))
+ if (!RenderCallArgs(c, call.args()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderCallImport(WasmRenderContext& c)
+RenderCallIndirect(WasmRenderContext& c, AstCallIndirect& call)
{
- uint32_t importIndex;
- if (!c.d.readVarU32(&importIndex))
- return RenderFail(c, "unable to read import index");
-
- if (!c.buffer.append("(call_import $import$"))
- return false;
- if (!RenderInt32(c, importIndex))
- return false;
-
- if (importIndex >= c.importSigs.length())
- return RenderFail(c, "import index out of range");
-
- uint32_t sigIndex = c.importSigs[importIndex];
- if (!RenderCallWithSig(c, sigIndex))
+ if (!c.buffer.append("(call_indirect "))
return false;
- if (!c.buffer.append(")"))
- return false;
-
- return true;
-}
-
-static bool
-RenderCallIndirect(WasmRenderContext& c)
-{
- uint32_t sigIndex;
- if (!c.d.readVarU32(&sigIndex))
- return RenderFail(c, "unable to read indirect call signature index");
-
- if (!c.buffer.append("(call_indirect $type$"))
- return false;
- if (!RenderInt32(c, sigIndex))
+ if (!RenderRef(c, call.sig()))
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *call.index()))
return false;
if (!c.buffer.append(" "))
return false;
-
- if (!RenderCallWithSig(c, sigIndex))
+ if (!RenderCallArgs(c, call.args()))
return false;
- if (!c.buffer.append(")"))
- return false;
-
return true;
}
static bool
-RenderConstI32(WasmRenderContext& c)
+RenderConst(WasmRenderContext& c, AstConst& cst)
{
- if (!c.buffer.append("(i32.const "))
+ if (!c.buffer.append('('))
+ return false;
+ if (!RenderValType(c, cst.val().type()))
+ return false;
+ if (!c.buffer.append(".const "))
return false;
- int32_t i32;
- if (!c.d.readVarS32(&i32))
- return RenderFail(c, "unable to read i32.const immediate");
+ switch (ToExprType(cst.val().type()))
+ {
+ case ExprType::I32:
+ if (!RenderInt32(c, (uint32_t)cst.val().i32()))
+ return false;
+ break;
+ case ExprType::I64:
+ if (!RenderInt64(c, (uint32_t)cst.val().i64()))
+ return false;
+ break;
+ case ExprType::F32:
+ if (!RenderDouble(c, (double)cst.val().f32()))
+ return false;
+ break;
+ case ExprType::F64:
+ if (!RenderDouble(c, cst.val().f64()))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ if (!c.buffer.append(")"))
+ return false;
+ return true;
+}
- if (!RenderInt32(c, (uint32_t)i32))
+static bool
+RenderGetLocal(WasmRenderContext& c, AstGetLocal& gl)
+{
+ if (!c.buffer.append("(get_local "))
+ return false;
+ if (!RenderRef(c, gl.local()))
+ return false;
+ if (!c.buffer.append(")"))
+ return false;
+ return true;
+}
+
+static bool
+RenderSetLocal(WasmRenderContext& c, AstSetLocal& sl)
+{
+ if (!c.buffer.append("(set_local "))
+ return false;
+ if (!RenderRef(c, sl.local()))
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+
+ if (!RenderExpr(c, sl.value()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderConstI64(WasmRenderContext& c)
-{
- if (!c.buffer.append("(i64.const "))
- return false;
-
- int64_t i64;
- if (!c.d.readVarS64(&i64))
- return RenderFail(c, "unable to read i64.const immediate");
-
- if (!RenderInt64(c, i64))
- return false;
-
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderConstF32(WasmRenderContext& c)
-{
- if (!c.buffer.append("(f32.const "))
- return false;
-
- float value;
- if (!c.d.readFixedF32(&value))
- return RenderFail(c, "unable to read f32.const immediate");
-
- if (IsNaN(value)) {
- const float jsNaN = (float)JS::GenericNaN();
- if (memcmp(&value, &jsNaN, sizeof(value)) != 0)
- return RenderFail(c, "NYI: NaN literals with custom payloads");
- }
-
- if (!RenderDouble(c, (double)value))
- return false;
-
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderConstF64(WasmRenderContext& c)
+RenderBlock(WasmRenderContext& c, AstBlock& block)
{
- if (!c.buffer.append("(f64.const "))
- return false;
-
- double value;
- if (!c.d.readFixedF64(&value))
- return RenderFail(c, "unable to read f64.const immediate");
-
- if (IsNaN(value)) {
- const double jsNaN = JS::GenericNaN();
- if (memcmp(&value, &jsNaN, sizeof(value)) != 0)
- return RenderFail(c, "NYI: NaN literals with custom payloads");
- }
-
- if (!RenderDouble(c, value))
- return false;
-
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderGetLocal(WasmRenderContext& c)
-{
- uint32_t localIndex;
- if (!c.d.readVarU32(&localIndex))
- return RenderFail(c, "unable to read get_local index");
-
- if (localIndex >= c.funcLocals[c.currentFuncIndex])
- return RenderFail(c, "get_local index out of range");
-
- if (!c.buffer.append("(get_local $var$"))
- return false;
- if (!RenderInt32(c, localIndex))
- return false;
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderSetLocal(WasmRenderContext& c)
-{
- uint32_t localIndex;
- if (!c.d.readVarU32(&localIndex))
- return RenderFail(c, "unable to read set_local index");
-
- if (localIndex >= c.funcLocals[c.currentFuncIndex])
- return RenderFail(c, "set_local index out of range");
-
- if (!c.buffer.append("(set_local $var$"))
- return false;
- if (!RenderInt32(c, localIndex))
- return false;
- if (!c.buffer.append(" "))
- return false;
-
- if (!RenderExpr(c))
- return false;
-
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderBlock(WasmRenderContext& c)
-{
- if (!c.buffer.append("(block"))
+ if (block.expr() == Expr::Block) {
+ if (!c.buffer.append("(block "))
+ return false;
+ } else if (block.expr() == Expr::Loop) {
+ if (!c.buffer.append("(loop "))
+ return false;
+ } else
return false;
c.indent++;
- uint32_t numExprs;
- if (!c.d.readVarU32(&numExprs))
- return RenderFail(c, "unable to read block's number of expressions");
-
+ uint32_t numExprs = block.exprs().length();
for (uint32_t i = 0; i < numExprs; i++) {
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *(block.exprs()[i])))
return false;
}
c.indent--;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderLoop(WasmRenderContext& c)
-{
- if (!c.buffer.append("(loop"))
- return false;
-
- c.indent++;
-
- uint32_t numExprs;
- if (!c.d.readVarU32(&numExprs))
- return RenderFail(c, "unable to read block's number of expressions");
-
- for (uint32_t i = 0; i < numExprs; i++) {
- if (!c.buffer.append(" "))
- return false;
- if (!RenderExpr(c))
- return false;
- }
-
- c.indent--;
- if (!c.buffer.append(")"))
- return false;
-
- return true;
-}
-
-static bool
-RenderUnaryOperator(WasmRenderContext& c, Expr expr, ValType argType)
+RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& op)
{
if (!c.buffer.append("("))
return false;
bool success = false;
- switch (expr) {
+ switch (op.expr()) {
case Expr::I32Eqz: success = c.buffer.append("i32.eqz"); break;
case Expr::I32Clz: success = c.buffer.append("i32.clz"); break;
case Expr::I32Ctz: success = c.buffer.append("i32.ctz"); break;
case Expr::I32Popcnt: success = c.buffer.append("i32.popcnt"); break;
case Expr::I64Clz: success = c.buffer.append("i64.clz"); break;
case Expr::I64Ctz: success = c.buffer.append("i64.ctz"); break;
case Expr::I64Popcnt: success = c.buffer.append("i64.popcnt"); break;
case Expr::F32Abs: success = c.buffer.append("f32.abs"); break;
@@ -506,32 +390,32 @@ RenderUnaryOperator(WasmRenderContext& c
default: return false;
}
if (!success)
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.op()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderBinaryOperator(WasmRenderContext& c, Expr expr, ValType argType)
+RenderBinaryOperator(WasmRenderContext& c, AstBinaryOperator& op)
{
if (!c.buffer.append("("))
return false;
bool success = false;
- switch (expr) {
+ switch (op.expr()) {
case Expr::I32Add: success = c.buffer.append("i32.add"); break;
case Expr::I32Sub: success = c.buffer.append("i32.sub"); break;
case Expr::I32Mul: success = c.buffer.append("i32.mul"); break;
case Expr::I32DivS: success = c.buffer.append("i32.div_s"); break;
case Expr::I32DivU: success = c.buffer.append("i32.div_u"); break;
case Expr::I32RemS: success = c.buffer.append("i32.rem_s"); break;
case Expr::I32RemU: success = c.buffer.append("i32.rem_u"); break;
case Expr::I32And: success = c.buffer.append("i32.and"); break;
@@ -567,35 +451,65 @@ RenderBinaryOperator(WasmRenderContext&
case Expr::F64Min: success = c.buffer.append("f64.min"); break;
case Expr::F64Max: success = c.buffer.append("f64.max"); break;
default: return false;
}
if (!success)
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.lhs()))
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.rhs()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderComparisonOperator(WasmRenderContext& c, Expr expr, ValType argType)
+RenderTernaryOperator(WasmRenderContext& c, AstTernaryOperator& op)
+{
+ if (!c.buffer.append("("))
+ return false;
+
+ bool success = false;
+ switch (op.expr()) {
+ case Expr::Select: success = c.buffer.append("select"); break;
+ default: return false;
+ }
+ if (!success)
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+ if (!RenderExpr(c, *op.op0()))
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+ if (!RenderExpr(c, *op.op1()))
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+ if (!RenderExpr(c, *op.op2()))
+ return false;
+ if (!c.buffer.append(")"))
+ return false;
+ return true;
+}
+
+static bool
+RenderComparisonOperator(WasmRenderContext& c, AstComparisonOperator& op)
{
if (!c.buffer.append("("))
return false;
bool success = false;
- switch (expr) {
+ switch (op.expr()) {
case Expr::I32Eq: success = c.buffer.append("i32.eq"); break;
case Expr::I32Ne: success = c.buffer.append("i32.ne"); break;
case Expr::I32LtS: success = c.buffer.append("i32.lt_s"); break;
case Expr::I32LtU: success = c.buffer.append("i32.lt_u"); break;
case Expr::I32LeS: success = c.buffer.append("i32.le_s"); break;
case Expr::I32LeU: success = c.buffer.append("i32.le_u"); break;
case Expr::I32GtS: success = c.buffer.append("i32.gt_s"); break;
case Expr::I32GtU: success = c.buffer.append("i32.gt_u"); break;
@@ -625,35 +539,35 @@ RenderComparisonOperator(WasmRenderConte
case Expr::F64Ge: success = c.buffer.append("f64.ge"); break;
default: return false;
}
if (!success)
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.lhs()))
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.rhs()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderConversionOperator(WasmRenderContext& c, Expr expr, ValType to, ValType argType)
+RenderConversionOperator(WasmRenderContext& c, AstConversionOperator& op)
{
if (!c.buffer.append("("))
return false;
bool success = false;
- switch (expr) {
+ switch (op.expr()) {
case Expr::I32WrapI64: success = c.buffer.append("i32.wrap/i64"); break;
case Expr::I32TruncSF32: success = c.buffer.append("i32.trunc_s/f32"); break;
case Expr::I32TruncUF32: success = c.buffer.append("i32.trunc_u/f32"); break;
case Expr::I32ReinterpretF32: success = c.buffer.append("i32.reinterpret/f32"); break;
case Expr::I32TruncSF64: success = c.buffer.append("i32.trunc_s/f64"); break;
case Expr::I32TruncUF64: success = c.buffer.append("i32.trunc_u/f64"); break;
case Expr::I64ExtendSI32: success = c.buffer.append("i64.extend_s/i32"); break;
case Expr::I64ExtendUI32: success = c.buffer.append("i64.extend_u/i32"); break;
@@ -677,575 +591,409 @@ RenderConversionOperator(WasmRenderConte
default: return false;
}
if (!success)
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *op.op()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderIfElse(WasmRenderContext& c, bool hasElse)
+RenderIfElse(WasmRenderContext& c, AstIf& if_)
{
if (!c.buffer.append("(if "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, if_.cond()))
return false;
if (!c.buffer.append(" "))
return false;
c.indent++;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, if_.thenBranch()))
return false;
c.indent--;
- if (hasElse) {
+ if (if_.hasElse()) {
if (!c.buffer.append(" "))
return false;
c.indent++;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, if_.elseBranch()))
return false;
c.indent--;
}
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderLoadStoreAddress(WasmRenderContext& c)
+RenderLoadStoreAddress(WasmRenderContext& c, const AstLoadStoreAddress& lsa, uint32_t defaultAlignLog2)
{
- uint32_t flags;
- if (!c.d.readVarU32(&flags))
- return RenderFail(c, "expected memory access flags");
-
- uint32_t offset;
- if (!c.d.readVarU32(&offset))
- return RenderFail(c, "expected memory access offset");
-
- if (offset != 0) {
+ if (lsa.offset() != 0) {
if (!c.buffer.append(" offset="))
return false;
- if (!RenderInt32(c, offset))
+ if (!RenderInt32(c, lsa.offset()))
return false;
}
- uint32_t alignLog2 = flags;
- if (!c.buffer.append(" align="))
- return false;
- if (!RenderInt32(c, 1 << alignLog2))
- return false;
+ uint32_t alignLog2 = lsa.flags();
+ if (defaultAlignLog2 != alignLog2) {
+ if (!c.buffer.append(" align="))
+ return false;
+ if (!RenderInt32(c, 1 << alignLog2))
+ return false;
+ }
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, lsa.base()))
return false;
return true;
}
static bool
-RenderLoad(WasmRenderContext& c, Expr expr, ValType loadType)
+RenderLoad(WasmRenderContext& c, AstLoad& load)
{
- if (!c.buffer.append("("))
- return false;
- if (!RenderValType(c, loadType))
- return false;
- if (!c.buffer.append(".load"))
- return false;
- switch (expr) {
+ uint32_t defaultAlignLog2;
+ switch (load.expr()) {
case Expr::I32Load8S:
+ if (!c.buffer.append("(i32.load8_s"))
+ return false;
+ defaultAlignLog2 = 0;
+ break;
case Expr::I64Load8S:
- if (!c.buffer.append("8_s"))
+ if (!c.buffer.append("(i64.load8_s"))
return false;
+ defaultAlignLog2 = 0;
break;
case Expr::I32Load8U:
+ if (!c.buffer.append("(i32.load8_u"))
+ return false;
+ defaultAlignLog2 = 0;
+ break;
case Expr::I64Load8U:
- if (!c.buffer.append("8_u"))
+ if (!c.buffer.append("(i64.load8_u"))
return false;
+ defaultAlignLog2 = 0;
break;
case Expr::I32Load16S:
+ if (!c.buffer.append("(i32.load16_s"))
+ return false;
+ defaultAlignLog2 = 1;
+ break;
case Expr::I64Load16S:
- if (!c.buffer.append("16_s"))
+ if (!c.buffer.append("(i64.load16_s"))
return false;
+ defaultAlignLog2 = 1;
break;
case Expr::I32Load16U:
+ if (!c.buffer.append("(i32.load16_u"))
+ return false;
+ defaultAlignLog2 = 1;
+ break;
case Expr::I64Load16U:
- if (!c.buffer.append("16_u"))
+ if (!c.buffer.append("(i64.load16_u"))
return false;
+ defaultAlignLog2 = 1;
break;
case Expr::I64Load32S:
- if (!c.buffer.append("32_s"))
+ if (!c.buffer.append("(i64.load32_s"))
return false;
+ defaultAlignLog2 = 2;
break;
case Expr::I64Load32U:
- if (!c.buffer.append("32_u"))
+ if (!c.buffer.append("(i64.load32_u"))
return false;
+ defaultAlignLog2 = 2;
+ break;
+ case Expr::I32Load:
+ if (!c.buffer.append("(i32.load"))
+ return false;
+ defaultAlignLog2 = 2;
break;
- default: /* rest of them have not prefix */
+ case Expr::I64Load:
+ if (!c.buffer.append("(i64.load"))
+ return false;
+ defaultAlignLog2 = 3;
break;
+ case Expr::F32Load:
+ if (!c.buffer.append("(f32.load"))
+ return false;
+ defaultAlignLog2 = 2;
+ break;
+ case Expr::F64Load:
+ if (!c.buffer.append("(f64.load"))
+ return false;
+ defaultAlignLog2 = 3;
+ break;
+ default:
+ return false;
}
- if (!RenderLoadStoreAddress(c))
+
+ if (!RenderLoadStoreAddress(c, load.address(), defaultAlignLog2))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderStore(WasmRenderContext& c, Expr expr, ValType storeType)
+RenderStore(WasmRenderContext& c, AstStore& store)
{
- if (!c.buffer.append("("))
- return false;
- if (!RenderValType(c, storeType))
- return false;
- if (!c.buffer.append(".store"))
- return false;
- switch (expr) {
+ uint32_t defaultAlignLog2;
+ switch (store.expr()) {
case Expr::I32Store8:
+ if (!c.buffer.append("(i32.store8"))
+ return false;
+ defaultAlignLog2 = 0;
+ break;
case Expr::I64Store8:
- if (!c.buffer.append("8"))
+ if (!c.buffer.append("(i64.store8"))
return false;
+ defaultAlignLog2 = 0;
break;
case Expr::I32Store16:
+ if (!c.buffer.append("(i32.store16"))
+ return false;
+ defaultAlignLog2 = 1;
+ break;
case Expr::I64Store16:
- if (!c.buffer.append("16"))
+ if (!c.buffer.append("(i64.store16"))
return false;
+ defaultAlignLog2 = 1;
break;
case Expr::I64Store32:
- if (!c.buffer.append("32"))
+ if (!c.buffer.append("(i64.store32"))
return false;
+ defaultAlignLog2 = 2;
+ break;
+ case Expr::I32Store:
+ if (!c.buffer.append("(i32.store"))
+ return false;
+ defaultAlignLog2 = 2;
break;
- default: /* rest of them have not prefix */
+ case Expr::I64Store:
+ if (!c.buffer.append("(i64.store"))
+ return false;
+ defaultAlignLog2 = 3;
break;
+ case Expr::F32Store:
+ if (!c.buffer.append("(f32.store"))
+ return false;
+ defaultAlignLog2 = 2;
+ break;
+ case Expr::F64Store:
+ if (!c.buffer.append("(f64.store"))
+ return false;
+ defaultAlignLog2 = 3;
+ break;
+ default:
+ return false;
}
- if (!RenderLoadStoreAddress(c))
+ if (!RenderLoadStoreAddress(c, store.address(), defaultAlignLog2))
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, store.value()))
return false;
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderBranch(WasmRenderContext& c, Expr expr)
+RenderBranch(WasmRenderContext& c, AstBranch& branch)
{
+ Expr expr = branch.expr();
MOZ_ASSERT(expr == Expr::BrIf || expr == Expr::Br);
- uint32_t relativeDepth;
- if (!c.d.readVarU32(&relativeDepth))
- return RenderFail(c, "expected relative depth");
-
if (expr == Expr::BrIf ? !c.buffer.append("(br_if ") : !c.buffer.append("(br "))
return false;
- if (!RenderInt32(c, relativeDepth))
- return false;
-
- if (!c.buffer.append(" "))
- return false;
-
- if (!RenderExpr(c))
+ if (!RenderRef(c, branch.target()))
return false;
if (expr == Expr::BrIf) {
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
- return false;
- }
- if (!c.buffer.append(")"))
- return false;
- return true;
-}
-
-static bool
-RenderBrTable(WasmRenderContext& c)
-{
- uint32_t tableLength;
- if (!c.d.readVarU32(&tableLength))
- return false;
-
- if (!c.buffer.append("(br_table "))
- return false;
-
- for (uint32_t i = 0; i < tableLength; i++) {
- uint32_t depth;
- if (!c.d.readFixedU32(&depth))
- return RenderFail(c, "missing br_table entry");
-
- if (!RenderInt32(c, depth))
- return false;
-
- if (!c.buffer.append(" "))
+ if (!RenderExpr(c, branch.cond()))
return false;
}
- uint32_t defaultDepth;
- if (!c.d.readFixedU32(&defaultDepth))
- return RenderFail(c, "expected default relative depth");
-
- if (!RenderInt32(c, defaultDepth))
- return false;
-
- if (!c.buffer.append(" "))
- return false;
-
- // Value
- if (!RenderExpr(c))
- return false;
-
- if (!c.buffer.append(" "))
- return false;
-
- // Index
- if (!RenderExpr(c))
- return false;
-
- if (!c.buffer.append(")"))
- return false;
-
- return true;
-}
-
-static bool
-RenderReturn(WasmRenderContext& c)
-{
- if (!c.buffer.append("(return"))
- return false;
-
- if (c.signatures[c.funcSigs[c.currentFuncIndex]].ret() != ExprType::Void) {
+ if (branch.maybeValue()) {
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (!RenderExpr(c, *(branch.maybeValue())))
return false;
}
if (!c.buffer.append(")"))
return false;
return true;
}
static bool
-RenderSelect(WasmRenderContext& c)
+RenderBrTable(WasmRenderContext& c, AstBranchTable& table)
{
- if (!c.buffer.append("(select "))
+ if (!c.buffer.append("(br_table "))
return false;
- if (!RenderExpr(c))
- return false;
+ uint32_t tableLength = table.table().length();
+ for (uint32_t i = 0; i < tableLength; i++) {
+ if (!RenderRef(c, table.table()[i]))
+ return false;
- if (!c.buffer.append(" "))
- return false;
+ if (!c.buffer.append(" "))
+ return false;
+ }
- if (!RenderExpr(c))
+ if (!RenderRef(c, table.def()))
return false;
if (!c.buffer.append(" "))
return false;
- if (!RenderExpr(c))
+ if (table.maybeValue()) {
+ if (!RenderExpr(c, *(table.maybeValue())))
+ return false;
+
+ if (!c.buffer.append(" "))
+ return false;
+ }
+
+ // Index
+ if (!RenderExpr(c, table.index()))
+ return false;
+
+ if (!c.buffer.append(")"))
return false;
- return c.buffer.append(")");
+ return true;
+}
+
+static bool
+RenderReturn(WasmRenderContext& c, AstReturn& ret)
+{
+ if (!c.buffer.append("(return"))
+ return false;
+
+ if (ret.maybeExpr()) {
+ if (!c.buffer.append(" "))
+ return false;
+ if (!RenderExpr(c, *(ret.maybeExpr())))
+ return false;
+ }
+
+ if (!c.buffer.append(")"))
+ return false;
+ return true;
}
static bool
-RenderExpr(WasmRenderContext& c)
+RenderExpr(WasmRenderContext& c, AstExpr& expr)
{
- Expr expr;
- if (!c.d.readExpr(&expr))
- return RenderFail(c, "unable to read expression");
-
- switch (expr) {
- case Expr::Nop:
- return RenderNop(c);
- case Expr::Unreachable:
- return RenderUnreachable(c);
- case Expr::Call:
- return RenderCall(c);
- case Expr::CallImport:
- return RenderCallImport(c);
- case Expr::CallIndirect:
- return RenderCallIndirect(c);
- case Expr::I32Const:
- return RenderConstI32(c);
- case Expr::I64Const:
- return RenderConstI64(c);
- case Expr::F32Const:
- return RenderConstF32(c);
- case Expr::F64Const:
- return RenderConstF64(c);
- case Expr::GetLocal:
- return RenderGetLocal(c);
- case Expr::SetLocal:
- return RenderSetLocal(c);
- case Expr::Block:
- return RenderBlock(c);
- case Expr::Loop:
- return RenderLoop(c);
- case Expr::If:
- return RenderIfElse(c, false);
- case Expr::Else:
- return RenderIfElse(c, true);
- case Expr::I32Clz:
- case Expr::I32Ctz:
- case Expr::I32Popcnt:
- case Expr::I32Eqz:
- return RenderUnaryOperator(c, expr, ValType::I32);
- case Expr::I64Clz:
- case Expr::I64Ctz:
- case Expr::I64Popcnt:
- return RenderFail(c, "NYI: i64") &&
- RenderUnaryOperator(c, expr, ValType::I64);
- case Expr::F32Abs:
- case Expr::F32Neg:
- case Expr::F32Ceil:
- case Expr::F32Floor:
- case Expr::F32Sqrt:
- return RenderUnaryOperator(c, expr, ValType::F32);
- case Expr::F32Trunc:
- return RenderFail(c, "NYI: trunc");
- case Expr::F32Nearest:
- return RenderFail(c, "NYI: nearest");
- case Expr::F64Abs:
- case Expr::F64Neg:
- case Expr::F64Ceil:
- case Expr::F64Floor:
- case Expr::F64Sqrt:
- return RenderUnaryOperator(c, expr, ValType::F64);
- case Expr::F64Trunc:
- return RenderFail(c, "NYI: trunc");
- case Expr::F64Nearest:
- return RenderFail(c, "NYI: nearest");
- case Expr::I32Add:
- case Expr::I32Sub:
- case Expr::I32Mul:
- case Expr::I32DivS:
- case Expr::I32DivU:
- case Expr::I32RemS:
- case Expr::I32RemU:
- case Expr::I32And:
- case Expr::I32Or:
- case Expr::I32Xor:
- case Expr::I32Shl:
- case Expr::I32ShrS:
- case Expr::I32ShrU:
- return RenderBinaryOperator(c, expr, ValType::I32);
- case Expr::I64Add:
- case Expr::I64Sub:
- case Expr::I64Mul:
- case Expr::I64DivS:
- case Expr::I64DivU:
- case Expr::I64RemS:
- case Expr::I64RemU:
- case Expr::I64And:
- case Expr::I64Or:
- case Expr::I64Xor:
- case Expr::I64Shl:
- case Expr::I64ShrS:
- case Expr::I64ShrU:
- return RenderBinaryOperator(c, expr, ValType::I64);
- case Expr::F32Add:
- case Expr::F32Sub:
- case Expr::F32Mul:
- case Expr::F32Div:
- case Expr::F32Min:
- case Expr::F32Max:
- return RenderBinaryOperator(c, expr, ValType::F32);
- case Expr::F32CopySign:
- return RenderFail(c, "NYI: copysign");
- case Expr::F64Add:
- case Expr::F64Sub:
- case Expr::F64Mul:
- case Expr::F64Div:
- case Expr::F64Min:
- case Expr::F64Max:
- return RenderBinaryOperator(c, expr, ValType::F64);
- case Expr::F64CopySign:
- return RenderFail(c, "NYI: copysign");
- case Expr::I32Eq:
- case Expr::I32Ne:
- case Expr::I32LtS:
- case Expr::I32LtU:
- case Expr::I32LeS:
- case Expr::I32LeU:
- case Expr::I32GtS:
- case Expr::I32GtU:
- case Expr::I32GeS:
- case Expr::I32GeU:
- return RenderComparisonOperator(c, expr, ValType::I32);
- case Expr::I64Eq:
- case Expr::I64Ne:
- case Expr::I64LtS:
- case Expr::I64LtU:
- case Expr::I64LeS:
- case Expr::I64LeU:
- case Expr::I64GtS:
- case Expr::I64GtU:
- case Expr::I64GeS:
- case Expr::I64GeU:
- return RenderComparisonOperator(c, expr, ValType::I64);
- case Expr::F32Eq:
- case Expr::F32Ne:
- case Expr::F32Lt:
- case Expr::F32Le:
- case Expr::F32Gt:
- case Expr::F32Ge:
- return RenderComparisonOperator(c, expr, ValType::F32);
- case Expr::F64Eq:
- case Expr::F64Ne:
- case Expr::F64Lt:
- case Expr::F64Le:
- case Expr::F64Gt:
- case Expr::F64Ge:
- return RenderComparisonOperator(c, expr, ValType::F64);
- case Expr::I32WrapI64:
- return RenderConversionOperator(c, expr, ValType::I32, ValType::I64);
- case Expr::I32TruncSF32:
- case Expr::I32TruncUF32:
- case Expr::I32ReinterpretF32:
- return RenderConversionOperator(c, expr, ValType::I32, ValType::F32);
- case Expr::I32TruncSF64:
- case Expr::I32TruncUF64:
- return RenderConversionOperator(c, expr, ValType::I32, ValType::F64);
- case Expr::I64ExtendSI32:
- case Expr::I64ExtendUI32:
- return RenderConversionOperator(c, expr, ValType::I64, ValType::I32);
- case Expr::I64TruncSF32:
- case Expr::I64TruncUF32:
- return RenderConversionOperator(c, expr, ValType::I64, ValType::F32);
- case Expr::I64TruncSF64:
- case Expr::I64TruncUF64:
- case Expr::I64ReinterpretF64:
- return RenderConversionOperator(c, expr, ValType::I64, ValType::F64);
- case Expr::F32ConvertSI32:
- case Expr::F32ConvertUI32:
- case Expr::F32ReinterpretI32:
- return RenderConversionOperator(c, expr, ValType::F32, ValType::I32);
- case Expr::F32ConvertSI64:
- case Expr::F32ConvertUI64:
- return RenderConversionOperator(c, expr, ValType::F32, ValType::I64);
- case Expr::F32DemoteF64:
- return RenderConversionOperator(c, expr, ValType::F32, ValType::I64);
- case Expr::F64ConvertSI32:
- case Expr::F64ConvertUI32:
- return RenderConversionOperator(c, expr, ValType::F64, ValType::I32);
- case Expr::F64ConvertSI64:
- case Expr::F64ConvertUI64:
- case Expr::F64ReinterpretI64:
- return RenderConversionOperator(c, expr, ValType::F64, ValType::I64);
- case Expr::F64PromoteF32:
- return RenderConversionOperator(c, expr, ValType::F64, ValType::F32);
- case Expr::I32Load8S:
- case Expr::I32Load8U:
- case Expr::I32Load16S:
- case Expr::I32Load16U:
- case Expr::I32Load:
- return RenderLoad(c, expr, ValType::I32);
- case Expr::I64Load:
- case Expr::I64Load8S:
- case Expr::I64Load8U:
- case Expr::I64Load16S:
- case Expr::I64Load16U:
- case Expr::I64Load32S:
- case Expr::I64Load32U:
- return RenderFail(c, "NYI: i64") &&
- RenderLoad(c, expr, ValType::I64);
- case Expr::F32Load:
- return RenderLoad(c, expr, ValType::F32);
- case Expr::F64Load:
- return RenderLoad(c, expr, ValType::F64);
- case Expr::I32Store8:
- return RenderStore(c, expr, ValType::I32);
- case Expr::I32Store16:
- return RenderStore(c, expr, ValType::I32);
- case Expr::I32Store:
- return RenderStore(c, expr, ValType::I32);
- case Expr::I64Store:
- case Expr::I64Store8:
- case Expr::I64Store16:
- case Expr::I64Store32:
- return RenderFail(c, "NYI: i64") &&
- RenderStore(c, expr, ValType::I64);
- case Expr::F32Store:
- return RenderStore(c, expr, ValType::F32);
- case Expr::F64Store:
- return RenderStore(c, expr, ValType::F64);
- case Expr::Br:
- return RenderBranch(c, expr);
- case Expr::BrIf:
- return RenderBranch(c, expr);
- case Expr::BrTable:
- return RenderBrTable(c);
- case Expr::Return:
- return RenderReturn(c);
- case Expr::Select:
- return RenderSelect(c);
+ switch (expr.kind()) {
+ case AstExprKind::Nop:
+ return RenderNop(c, expr.as<AstNop>());
+ case AstExprKind::Unreachable:
+ return RenderUnreachable(c, expr.as<AstUnreachable>());
+ case AstExprKind::Call:
+ return RenderCall(c, expr.as<AstCall>());
+ case AstExprKind::CallIndirect:
+ return RenderCallIndirect(c, expr.as<AstCallIndirect>());
+ case AstExprKind::Const:
+ return RenderConst(c, expr.as<AstConst>());
+ case AstExprKind::GetLocal:
+ return RenderGetLocal(c, expr.as<AstGetLocal>());
+ case AstExprKind::SetLocal:
+ return RenderSetLocal(c, expr.as<AstSetLocal>());
+ case AstExprKind::Block:
+ return RenderBlock(c, expr.as<AstBlock>());
+ case AstExprKind::If:
+ return RenderIfElse(c, expr.as<AstIf>());
+ case AstExprKind::UnaryOperator:
+ return RenderUnaryOperator(c, expr.as<AstUnaryOperator>());
+ case AstExprKind::BinaryOperator:
+ return RenderBinaryOperator(c, expr.as<AstBinaryOperator>());
+ case AstExprKind::TernaryOperator:
+ return RenderTernaryOperator(c, expr.as<AstTernaryOperator>());
+ case AstExprKind::ComparisonOperator:
+ return RenderComparisonOperator(c, expr.as<AstComparisonOperator>());
+ case AstExprKind::ConversionOperator:
+ return RenderConversionOperator(c, expr.as<AstConversionOperator>());
+ case AstExprKind::Load:
+ return RenderLoad(c, expr.as<AstLoad>());
+ case AstExprKind::Store:
+ return RenderStore(c, expr.as<AstStore>());
+ case AstExprKind::Branch:
+ return RenderBranch(c, expr.as<AstBranch>());
+ case AstExprKind::BranchTable:
+ return RenderBrTable(c, expr.as<AstBranchTable>());
+ case AstExprKind::Return:
+ return RenderReturn(c, expr.as<AstReturn>());
default:
// Note: it's important not to remove this default since readExpr()
// can return Expr values for which there is no enumerator.
break;
}
- return RenderFail(c, "bad expression code");
+ return false;
}
static bool
-RenderSignature(WasmRenderContext& c, const DeclaredSig& sig, bool varAssignment)
+RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* maybeLocals = nullptr)
{
uint32_t paramsNum = sig.args().length();
- if (varAssignment) {
+ if (maybeLocals) {
for (uint32_t i = 0; i < paramsNum; i++) {
if (!c.buffer.append(" (param "))
return false;
- if (!c.buffer.append("$var$"))
- return false;
- if (!RenderInt32(c, i))
- return false;
- if (!c.buffer.append(" "))
- return false;
- ValType arg = sig.arg(i);
+ const AstName& name = (*maybeLocals)[i];
+ if (!name.empty()) {
+ if (!RenderName(c, name))
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+ }
+ ValType arg = sig.args()[i];
if (!RenderValType(c, arg))
return false;
if (!c.buffer.append(")"))
return false;
}
} else if (paramsNum > 0) {
if (!c.buffer.append(" (param"))
return false;
for (uint32_t i = 0; i < paramsNum; i++) {
if (!c.buffer.append(" "))
return false;
- ValType arg = sig.arg(i);
+ ValType arg = sig.args()[i];
if (!RenderValType(c, arg))
return false;
}
if (!c.buffer.append(")"))
return false;
}
if (sig.ret() != ExprType::Void) {
if (!c.buffer.append(" (result "))
@@ -1254,579 +1002,351 @@ RenderSignature(WasmRenderContext& c, co
return false;
if (!c.buffer.append(")"))
return false;
}
return true;
}
static bool
-RenderTypeSection(WasmRenderContext& c)
+RenderTypeSection(WasmRenderContext& c, const AstModule::SigVector& sigs)
{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(TypeSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
+ uint32_t numSigs = sigs.length();
+ if (!numSigs)
return true;
- uint32_t numSigs;
- if (!c.d.readVarU32(&numSigs))
- return RenderFail(c, "expected number of signatures");
-
- if (!c.signatures.resize(numSigs))
- return false;
-
for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
- uint32_t form;
- if (!c.d.readVarU32(&form) || form != uint32_t(TypeConstructor::Function))
- return RenderFail(c, "expected function form");
-
- uint32_t numArgs;
- if (!c.d.readVarU32(&numArgs))
- return RenderFail(c, "bad number of signature args");
-
- ValTypeVector args;
- if (!args.resize(numArgs))
- return false;
-
- for (uint32_t i = 0; i < numArgs; i++) {
- ValType arg;
- if (!c.d.readValType(&arg))
- return RenderFail(c, "bad value type");
- args[i] = arg;
- }
-
- uint32_t numRets;
- if (!c.d.readVarU32(&numRets))
- return RenderFail(c, "bad number of function returns");
-
- if (numRets > 1)
- return RenderFail(c, "too many returns in signature");
-
- ExprType result = ExprType::Void;
-
- if (numRets == 1) {
- ValType type;
- if (!c.d.readValType(&type))
- return RenderFail(c, "bad expression type");
-
- result = ToExprType(type);
- }
-
- c.signatures[sigIndex] = Sig(Move(args), result);
-
+ const AstSig* sig = sigs[sigIndex];
if (!RenderIndent(c))
return false;
- if (!c.buffer.append("(type $type$"))
+ if (!c.buffer.append("(type"))
return false;
- if (!RenderInt32(c, sigIndex))
- return false;
+ if (!sig->name().empty()) {
+ if (!c.buffer.append(" "))
+ return false;
+ if (!RenderName(c, sig->name()))
+ return false;
+ }
if (!c.buffer.append(" (func"))
return false;
- if (!RenderSignature(c, c.signatures[sigIndex], false))
+ if (!RenderSignature(c, *sig))
return false;
if (!c.buffer.append("))\n"))
return false;
}
+ return true;
+}
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "decls section byte size mismatch");
+static bool
+RenderTableSection(WasmRenderContext& c, AstTable* maybeTable, const AstModule::FuncVector& funcs)
+{
+ if (!maybeTable)
+ return true;
+
+ uint32_t numTableElems = maybeTable->elems().length();
+
+ if (!c.buffer.append("(table "))
+ return false;
+
+ for (uint32_t i = 0; i < numTableElems; i++) {
+ AstRef& elem = maybeTable->elems()[i];
+ AstFunc* func = funcs[elem.index()];
+ if (func->name().empty()) {
+ if (!RenderInt32(c, elem.index()))
+ return false;
+ } else {
+ if (!RenderName(c, func->name()))
+ return false;
+ }
+ }
+
+ if (!c.buffer.append(")"))
+ return false;
return true;
}
static bool
-RenderFunctionSection(WasmRenderContext& c)
-{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(FunctionSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t numDecls;
- if (!c.d.readVarU32(&numDecls))
- return RenderFail(c, "expected number of declarations");
-
- if (!c.funcSigs.resize(numDecls))
- return false;
-
- for (uint32_t i = 0; i < numDecls; i++) {
- uint32_t sigIndex;
- if (!c.d.readVarU32(&sigIndex))
- return RenderFail(c, "expected signature index");
- c.funcSigs[i] = sigIndex;
- }
-
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "decls section byte size mismatch");
-
- return true;
-}
-
-static bool
-RenderTableSection(WasmRenderContext& c)
+RenderImport(WasmRenderContext& c, AstImport& import, const AstModule::SigVector& sigs)
{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(TableSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t numTableElems;
- if (!c.d.readVarU32(&numTableElems))
- return RenderFail(c, "expected number of table elems");
-
- if (!c.buffer.append("(table "))
- return false;
-
- for (uint32_t i = 0; i < numTableElems; i++) {
- uint32_t funcIndex;
- if (!c.d.readVarU32(&funcIndex))
- return RenderFail(c, "expected table element");
- if (!RenderInt32(c, funcIndex))
- return false;
- if (!c.buffer.append(" "))
- return false;
- }
-
- if (!c.buffer.append(")"))
- return false;
-
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "table section byte size mismatch");
-
- return true;
-}
-
-static bool
-RenderImport(WasmRenderContext& c, uint32_t importIndex)
-{
- uint32_t sigIndex;
- if (!c.d.readVarU32(&sigIndex))
- return RenderFail(c, "expected signature index");
-
- c.importSigs[importIndex] = sigIndex;
-
+ const AstSig* sig = sigs[import.sigIndex()];
if (!RenderIndent(c))
return false;
- if (!c.buffer.append("(import $import$"))
+ if (!c.buffer.append("(import "))
return false;
- if (!RenderInt32(c, importIndex))
+ if (!RenderName(c, import.name()))
return false;
if (!c.buffer.append(" \""))
return false;
- Bytes moduleName;
- if (!c.d.readBytes(&moduleName))
- return RenderFail(c, "expected import module name");
-
- if (moduleName.empty())
- return RenderFail(c, "module name cannot be empty");
-
- if (!RenderString(c, moduleName.begin(), moduleName.length()))
+ const AstName& moduleName = import.module();
+ if (!RenderEscapedString(c, moduleName))
return false;
if (!c.buffer.append("\" \""))
return false;
- Bytes funcName;
- if (!c.d.readBytes(&funcName))
- return RenderFail(c, "expected import func name");
-
- if (!RenderString(c, funcName.begin(), funcName.length()))
+ const AstName& funcName = import.func();
+ if (!RenderEscapedString(c, funcName))
return false;
if (!c.buffer.append("\""))
return false;
- if (!RenderSignature(c, c.signatures[sigIndex], false))
+ if (!RenderSignature(c, *sig))
return false;
if (!c.buffer.append(")\n"))
return false;
return true;
}
static bool
-RenderImportSection(WasmRenderContext& c)
+RenderImportSection(WasmRenderContext& c, const AstModule::ImportVector& imports, const AstModule::SigVector& sigs)
{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(ImportSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t numImports;
- if (!c.d.readVarU32(&numImports))
- return RenderFail(c, "failed to read number of imports");
-
- if (!c.importSigs.resize(numImports))
- return false;
+ uint32_t numImports = imports.length();
for (uint32_t i = 0; i < numImports; i++) {
- if (!RenderImport(c, i))
+ if (!RenderImport(c, *imports[i], sigs))
return false;
}
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "import section byte size mismatch");
-
return true;
}
static bool
-RenderMemorySection(WasmRenderContext& c, uint32_t* memInitial, uint32_t* memMax)
+RenderExport(WasmRenderContext& c, AstExport& export_, const AstModule::FuncVector& funcs)
{
- *memInitial = 0;
- *memMax = 0;
-
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(MemorySectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t initialSizePages;
- if (!c.d.readVarU32(&initialSizePages))
- return RenderFail(c, "expected initial memory size");
- *memInitial = initialSizePages;
-
- uint32_t maxSizePages;
- if (!c.d.readVarU32(&maxSizePages))
- return RenderFail(c, "expected initial memory size");
- *memMax = maxSizePages;
-
- uint8_t exported;
- if (!c.d.readFixedU8(&exported))
- return RenderFail(c, "expected exported byte");
-
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "memory section byte size mismatch");
-
- if (exported && !c.buffer.append("(export \"memory\" memory)"))
- return false;
-
- return true;
-}
-
-static bool
-RenderExportName(WasmRenderContext& c)
-{
- Bytes fieldBytes;
- if (!c.d.readBytes(&fieldBytes)) {
- RenderFail(c, "expected export name");
- return false;
- }
-
- if (!RenderString(c, fieldBytes.begin(), fieldBytes.length()))
- return false;
-
- return true;
-}
-
-static bool
-RenderFunctionExport(WasmRenderContext& c)
-{
- uint32_t funcIndex;
- if (!c.d.readVarU32(&funcIndex))
- return RenderFail(c, "expected export internal index");
-
- if (funcIndex >= c.funcSigs.length())
- return RenderFail(c, "export function index out of range");
-
if (!RenderIndent(c))
return false;
if (!c.buffer.append("(export \""))
return false;
- if (!RenderExportName(c))
+ if (!RenderEscapedString(c, export_.name()))
return false;
if (!c.buffer.append("\" "))
return false;
- if (!c.buffer.append("$func$"))
- return false;
- if (!RenderInt32(c, funcIndex))
- return false;
+ if (export_.kind() == AstExportKind::Memory) {
+ if (!c.buffer.append("memory"))
+ return false;
+ } else {
+ const AstFunc* func = funcs[export_.func().index()];
+ if (func->name().empty()) {
+ if (!RenderInt32(c, export_.func().index()))
+ return false;
+ } else {
+ if (!RenderName(c, func->name()))
+ return false;
+ }
+ }
if (!c.buffer.append(")\n"))
return false;
return true;
}
static bool
-RenderExportSection(WasmRenderContext& c)
+RenderExportSection(WasmRenderContext& c, const AstModule::ExportVector& exports, const AstModule::FuncVector& funcs)
{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(ExportSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t numExports;
- if (!c.d.readVarU32(&numExports))
- return RenderFail(c, "failed to read number of exports");
-
+ uint32_t numExports = exports.length();
for (uint32_t i = 0; i < numExports; i++) {
- if (!RenderFunctionExport(c))
+ if (!RenderExport(c, *exports[i], funcs))
return false;
}
-
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "export section byte size mismatch");
-
return true;
}
static bool
-RenderFunctionBody(WasmRenderContext& c, uint32_t funcIndex, uint32_t paramsNum)
+RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::SigVector& sigs)
{
- uint32_t bodySize;
- if (!c.d.readVarU32(&bodySize))
- return RenderFail(c, "expected number of function body bytes");
-
- if (c.d.bytesRemain() < bodySize)
- return RenderFail(c, "function body length too big");
-
- const uint8_t* bodyBegin = c.d.currentPosition();
- const uint8_t* bodyEnd = bodyBegin + bodySize;
-
+ const AstSig* sig = sigs[func.sig().index()];
c.indent++;
- ValTypeVector locals;
- if (!DecodeLocalEntries(c.d, &locals))
- return RenderFail(c, "failed decoding local entries");
-
- uint32_t localsNum = locals.length();
+ uint32_t argsNum = sig->args().length();
+ uint32_t localsNum = func.vars().length();
if (localsNum > 0) {
if (!RenderIndent(c))
return false;
for (uint32_t i = 0; i < localsNum; i++) {
if (!c.buffer.append("(local "))
return false;
- if (!c.buffer.append("$var$"))
- return false;
- if (!RenderInt32(c, i + paramsNum))
- return false;
- ValType local = locals[i];
- if (!c.buffer.append(" "))
- return false;
+ const AstName& name = func.locals()[argsNum + i];
+ if (!name.empty()) {
+ if (!RenderName(c, name))
+ return false;
+ if (!c.buffer.append(" "))
+ return false;
+ }
+ ValType local = func.vars()[i];
if (!RenderValType(c, local))
return false;
if (!c.buffer.append(") "))
return false;
}
if (!c.buffer.append("\n"))
return false;
}
- if (funcIndex >= c.funcLocals.length() && !c.funcLocals.resize(funcIndex + 1))
- return false;
- c.funcLocals[funcIndex] = localsNum + paramsNum;
-
- while (c.d.currentPosition() < bodyEnd) {
- if (!RenderFullLine(c))
+ uint32_t exprsNum = func.body().length();
+ for (uint32_t i = 0; i < exprsNum; i++) {
+ if (!RenderFullLine(c, *func.body()[i]))
return false;
}
- if (c.d.currentPosition() != bodyEnd)
- return RenderFail(c, "function body length mismatch");
-
c.indent--;
return true;
}
static bool
-RenderCodeSection(WasmRenderContext& c)
+RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs, const AstModule::SigVector& sigs)
{
- uint32_t sectionStart, sectionSize;
- if (!c.d.startSection(CodeSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
-
- if (sectionStart == Decoder::NotStarted)
- return true;
-
- uint32_t numFuncSigs = c.funcSigs.length();
-
- uint32_t numFuncBodies;
- if (!c.d.readVarU32(&numFuncBodies))
- return RenderFail(c, "expected function body count");
- if (numFuncBodies != numFuncSigs)
- return RenderFail(c, "function body count does not match function signature count");
+ uint32_t numFuncBodies = funcs.length();
for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
- uint32_t sigIndex = c.funcSigs[funcIndex];
- const DeclaredSig& sig = c.signatures[sigIndex];
+ AstFunc* func = funcs[funcIndex];
+ uint32_t sigIndex = func->sig().index();
+ AstSig* sig = sigs[sigIndex];
if (!RenderIndent(c))
return false;
- if (!c.buffer.append("(func $func$"))
+ if (!c.buffer.append("(func "))
return false;
- if (!RenderInt32(c, funcIndex))
- return false;
+ if (!func->name().empty()) {
+ if (!RenderName(c, func->name()))
+ return false;
+ }
- if (!RenderSignature(c, sig, true))
+ if (!RenderSignature(c, *sig, &(func->locals())))
return false;
if (!c.buffer.append("\n"))
return false;
c.currentFuncIndex = funcIndex;
c.indent++;
- if (!RenderFunctionBody(c, funcIndex, sig.args().length()))
+ if (!RenderFunctionBody(c, *func, sigs))
return false;
c.indent--;
if (!RenderIndent(c))
return false;
if (!c.buffer.append(")\n"))
return false;
}
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "function section byte size mismatch");
-
return true;
}
static bool
-RenderDataSection(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax)
+RenderDataSection(WasmRenderContext& c, AstMemory* maybeMemory)
{
+ if (!maybeMemory)
+ return true;
+
if (!RenderIndent(c))
return false;
if (!c.buffer.append("(memory "))
return false;
- if (!RenderInt32(c, memInitial))
+ if (!RenderInt32(c, maybeMemory->initialSize()))
return false;
- if (memMax != 0 && ~memMax != 0) {
+ Maybe<uint32_t> memMax = maybeMemory->maxSize();
+ if (memMax) {
if (!c.buffer.append(" "))
return false;
- if (!RenderInt32(c, memMax))
+ if (!RenderInt32(c, *memMax))
return false;
}
c.indent++;
- uint32_t sectionStart;
- uint32_t sectionSize;
- if (!c.d.startSection(DataSectionId, §ionStart, §ionSize))
- return RenderFail(c, "failed to start section");
- if (sectionStart == Decoder::NotStarted) {
+
+ uint32_t numSegments = maybeMemory->segments().length();
+ if (!numSegments) {
if (!c.buffer.append(")\n"))
return false;
return true;
}
if (!c.buffer.append("\n"))
return false;
- uint32_t numSegments;
- if (!c.d.readVarU32(&numSegments))
- return RenderFail(c, "failed to read number of data segments");
-
for (uint32_t i = 0; i < numSegments; i++) {
- uint32_t dstOffset;
- if (!c.d.readVarU32(&dstOffset))
- return RenderFail(c, "expected segment destination offset");
+ const AstSegment* segment = maybeMemory->segments()[i];
if (!RenderIndent(c))
return false;
if (!c.buffer.append("(segment "))
return false;
- if (!RenderInt32(c, dstOffset))
+ if (!RenderInt32(c, segment->offset()))
return false;
if (!c.buffer.append(" \""))
return false;
- uint32_t numBytes;
- if (!c.d.readVarU32(&numBytes))
- return RenderFail(c, "expected segment size");
-
- const uint8_t* src;
- if (!c.d.readBytesRaw(numBytes, &src))
- return RenderFail(c, "data segment shorter than declared");
-
- RenderString(c, src, numBytes);
+ RenderEscapedString(c, segment->text());
if (!c.buffer.append("\")\n"))
return false;
}
- if (!c.d.finishSection(sectionStart, sectionSize))
- return RenderFail(c, "data section byte size mismatch");
-
c.indent--;
if (!c.buffer.append(")\n"))
return false;
return true;
}
static bool
-RenderModule(WasmRenderContext& c)
+RenderModule(WasmRenderContext& c, AstModule& module)
{
- uint32_t u32;
- if (!c.d.readFixedU32(&u32) || u32 != MagicNumber)
- return RenderFail(c, "failed to match magic number");
-
- if (!c.d.readFixedU32(&u32) || u32 != EncodingVersion)
- return RenderFail(c, "failed to match binary version");
-
if (!c.buffer.append("(module\n"))
return false;
c.indent++;
- if (!RenderTypeSection(c))
+ if (!RenderTypeSection(c, module.sigs()))
return false;
- if (!RenderImportSection(c))
- return false;
-
- if (!RenderFunctionSection(c))
- return false;
-
- if (!RenderTableSection(c))
+ if (!RenderImportSection(c, module.imports(), module.sigs()))
return false;
- uint32_t memInitial, memMax;
- if (!RenderMemorySection(c, &memInitial, &memMax))
+ if (!RenderTableSection(c, module.maybeTable(), module.funcs()))
return false;
- if (!RenderExportSection(c))
+ if (!RenderExportSection(c, module.exports(), module.funcs()))
return false;
- if (!RenderCodeSection(c))
+ if (!RenderCodeSection(c, module.funcs(), module.sigs()))
return false;
- if (!RenderDataSection(c, memInitial, memMax))
+ if (!RenderDataSection(c, module.maybeMemory()))
return false;
c.indent--;
if (!c.buffer.append(")"))
return false;
return true;
}
/*****************************************************************************/
// Top-level functions
bool
wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer)
{
- Decoder d(bytes, bytes + length);
+
+ LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
- WasmRenderContext c(cx, d, buffer);
-
- if (!c.buffer.append("Binary-to-text is temporarily unavailable\n"))
+ AstModule* module;
+ if (!BinaryToAst(cx, bytes, length, lifo, &module))
return false;
- // FIXME: Implement binary-to-text and re-enable this.
- if (0 && !RenderModule(c)) {
+ WasmRenderContext c(cx, module, buffer);
+
+ if (!RenderModule(c, *module)) {
if (!cx->isExceptionPending())
ReportOutOfMemory(cx);
return false;
}
return true;
}
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -22,16 +22,17 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Maybe.h"
#include "jsdtoa.h"
#include "jsnum.h"
#include "jsprf.h"
#include "jsstr.h"
+#include "asmjs/WasmAST.h"
#include "asmjs/WasmBinary.h"
#include "asmjs/WasmTypes.h"
#include "ds/LifoAlloc.h"
#include "js/CharacterEncoding.h"
#include "js/HashTable.h"
using namespace js;
using namespace js::wasm;
@@ -40,746 +41,16 @@ using mozilla::BitwiseCast;
using mozilla::CeilingLog2;
using mozilla::CountLeadingZeroes32;
using mozilla::CheckedInt;
using mozilla::FloatingPoint;
using mozilla::Maybe;
using mozilla::PositiveInfinity;
using mozilla::SpecificNaN;
-static const unsigned AST_LIFO_DEFAULT_CHUNK_SIZE = 4096;
-static const uint32_t WasmNoIndex = UINT32_MAX;
-
-/*****************************************************************************/
-// wasm AST
-
-namespace {
-
-class WasmAstExpr;
-
-template <class T>
-using WasmAstVector = mozilla::Vector<T, 0, LifoAllocPolicy<Fallible>>;
-
-template <class K, class V, class HP>
-using WasmAstHashMap = HashMap<K, V, HP, LifoAllocPolicy<Fallible>>;
-
-class WasmName
-{
- const char16_t* begin_;
- const char16_t* end_;
- public:
- WasmName(const char16_t* begin, size_t length) : begin_(begin), end_(begin + length) {}
- WasmName() : begin_(nullptr), end_(nullptr) {}
- const char16_t* begin() const { return begin_; }
- const char16_t* end() const { return end_; }
- size_t length() const { return end_ - begin_; }
- bool empty() const { return begin_ == nullptr; }
-
- bool operator==(WasmName rhs) const {
- if (length() != rhs.length())
- return false;
- if (begin() == rhs.begin())
- return true;
- return EqualChars(begin(), rhs.begin(), length());
- }
- bool operator!=(WasmName rhs) const {
- return !(*this == rhs);
- }
-};
-
-class WasmRef
-{
- WasmName name_;
- uint32_t index_;
-
- public:
- WasmRef()
- : index_(WasmNoIndex)
- {
- MOZ_ASSERT(isInvalid());
- }
- WasmRef(WasmName name, uint32_t index)
- : name_(name), index_(index)
- {
- MOZ_ASSERT(name.empty() ^ (index == WasmNoIndex));
- MOZ_ASSERT(!isInvalid());
- }
- bool isInvalid() const {
- return name_.empty() && index_ == WasmNoIndex;
- }
- WasmName name() const {
- return name_;
- }
- size_t index() const {
- MOZ_ASSERT(index_ != WasmNoIndex);
- return index_;
- }
- void setIndex(uint32_t index) {
- MOZ_ASSERT(index_ == WasmNoIndex);
- index_ = index;
- }
-};
-
-struct WasmNameHasher
-{
- typedef const WasmName Lookup;
- static js::HashNumber hash(Lookup l) {
- return mozilla::HashString(l.begin(), l.length());
- }
- static bool match(const WasmName key, Lookup lookup) {
- return key == lookup;
- }
-};
-
-using WasmNameMap = WasmAstHashMap<WasmName, uint32_t, WasmNameHasher>;
-
-typedef WasmAstVector<ValType> WasmAstValTypeVector;
-typedef WasmAstVector<WasmAstExpr*> WasmAstExprVector;
-typedef WasmAstVector<WasmName> WasmNameVector;
-typedef WasmAstVector<WasmRef> WasmRefVector;
-
-struct WasmAstBase
-{
- void* operator new(size_t numBytes, LifoAlloc& astLifo) throw() {
- return astLifo.alloc(numBytes);
- }
-};
-
-class WasmAstSig : public WasmAstBase
-{
- WasmName name_;
- WasmAstValTypeVector args_;
- ExprType ret_;
-
- public:
- explicit WasmAstSig(LifoAlloc& lifo)
- : args_(lifo),
- ret_(ExprType::Void)
- {}
- WasmAstSig(WasmAstValTypeVector&& args, ExprType ret)
- : args_(Move(args)),
- ret_(ret)
- {}
- WasmAstSig(WasmName name, WasmAstSig&& rhs)
- : name_(name),
- args_(Move(rhs.args_)),
- ret_(rhs.ret_)
- {}
- void operator=(WasmAstSig&& rhs) {
- args_ = Move(rhs.args_);
- ret_ = rhs.ret_;
- }
- const WasmAstValTypeVector& args() const {
- return args_;
- }
- ExprType ret() const {
- return ret_;
- }
- WasmName name() const {
- return name_;
- }
- bool operator==(const WasmAstSig& rhs) const {
- return ret() == rhs.ret() && EqualContainers(args(), rhs.args());
- }
-
- typedef const WasmAstSig& Lookup;
- static HashNumber hash(Lookup sig) {
- return AddContainerToHash(sig.args(), HashNumber(sig.ret()));
- }
- static bool match(const WasmAstSig* lhs, Lookup rhs) {
- return *lhs == rhs;
- }
-};
-
-class WasmAstNode : public WasmAstBase
-{};
-
-enum class WasmAstExprKind
-{
- BinaryOperator,
- Block,
- Branch,
- BranchTable,
- Call,
- CallIndirect,
- ComparisonOperator,
- Const,
- ConversionOperator,
- GetLocal,
- If,
- Load,
- Nop,
- Return,
- SetLocal,
- Store,
- TernaryOperator,
- UnaryOperator,
- Unreachable
-};
-
-class WasmAstExpr : public WasmAstNode
-{
- const WasmAstExprKind kind_;
-
- protected:
- explicit WasmAstExpr(WasmAstExprKind kind)
- : kind_(kind)
- {}
-
- public:
- WasmAstExprKind kind() const { return kind_; }
-
- template <class T>
- T& as() {
- MOZ_ASSERT(kind() == T::Kind);
- return static_cast<T&>(*this);
- }
-};
-
-struct WasmAstNop : WasmAstExpr
-{
- WasmAstNop()
- : WasmAstExpr(WasmAstExprKind::Nop)
- {}
-};
-
-struct WasmAstUnreachable : WasmAstExpr
-{
- WasmAstUnreachable()
- : WasmAstExpr(WasmAstExprKind::Unreachable)
- {}
-};
-
-class WasmAstConst : public WasmAstExpr
-{
- const Val val_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Const;
- explicit WasmAstConst(Val val)
- : WasmAstExpr(Kind),
- val_(val)
- {}
- Val val() const { return val_; }
-};
-
-class WasmAstGetLocal : public WasmAstExpr
-{
- WasmRef local_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::GetLocal;
- explicit WasmAstGetLocal(WasmRef local)
- : WasmAstExpr(Kind),
- local_(local)
- {}
- WasmRef& local() {
- return local_;
- }
-};
-
-class WasmAstSetLocal : public WasmAstExpr
-{
- WasmRef local_;
- WasmAstExpr& value_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::SetLocal;
- WasmAstSetLocal(WasmRef local, WasmAstExpr& value)
- : WasmAstExpr(Kind),
- local_(local),
- value_(value)
- {}
- WasmRef& local() {
- return local_;
- }
- WasmAstExpr& value() const {
- return value_;
- }
-};
-
-class WasmAstBlock : public WasmAstExpr
-{
- Expr expr_;
- WasmName breakName_;
- WasmName continueName_;
- WasmAstExprVector exprs_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Block;
- explicit WasmAstBlock(Expr expr, WasmName breakName,
- WasmName continueName, WasmAstExprVector&& exprs)
- : WasmAstExpr(Kind),
- expr_(expr),
- breakName_(breakName),
- continueName_(continueName),
- exprs_(Move(exprs))
- {}
-
- Expr expr() const { return expr_; }
- WasmName breakName() const { return breakName_; }
- WasmName continueName() const { return continueName_; }
- const WasmAstExprVector& exprs() const { return exprs_; }
-};
-
-class WasmAstBranch : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* cond_;
- WasmRef target_;
- WasmAstExpr* value_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Branch;
- explicit WasmAstBranch(Expr expr, WasmAstExpr* cond, WasmRef target, WasmAstExpr* value)
- : WasmAstExpr(Kind),
- expr_(expr),
- cond_(cond),
- target_(target),
- value_(value)
- {}
-
- Expr expr() const { return expr_; }
- WasmRef& target() { return target_; }
- WasmAstExpr& cond() const { MOZ_ASSERT(cond_); return *cond_; }
- WasmAstExpr* maybeValue() const { return value_; }
-};
-
-class WasmAstCall : public WasmAstExpr
-{
- Expr expr_;
- WasmRef func_;
- WasmAstExprVector args_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Call;
- WasmAstCall(Expr expr, WasmRef func, WasmAstExprVector&& args)
- : WasmAstExpr(Kind), expr_(expr), func_(func), args_(Move(args))
- {}
-
- Expr expr() const { return expr_; }
- WasmRef& func() { return func_; }
- const WasmAstExprVector& args() const { return args_; }
-};
-
-class WasmAstCallIndirect : public WasmAstExpr
-{
- WasmRef sig_;
- WasmAstExpr* index_;
- WasmAstExprVector args_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::CallIndirect;
- WasmAstCallIndirect(WasmRef sig, WasmAstExpr* index, WasmAstExprVector&& args)
- : WasmAstExpr(Kind), sig_(sig), index_(index), args_(Move(args))
- {}
- WasmRef& sig() { return sig_; }
- WasmAstExpr* index() const { return index_; }
- const WasmAstExprVector& args() const { return args_; }
-};
-
-class WasmAstReturn : public WasmAstExpr
-{
- WasmAstExpr* maybeExpr_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Return;
- explicit WasmAstReturn(WasmAstExpr* maybeExpr)
- : WasmAstExpr(Kind),
- maybeExpr_(maybeExpr)
- {}
- WasmAstExpr* maybeExpr() const { return maybeExpr_; }
-};
-
-class WasmAstIf : public WasmAstExpr
-{
- WasmAstExpr* cond_;
- WasmAstExpr* thenBranch_;
- WasmAstExpr* elseBranch_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::If;
- WasmAstIf(WasmAstExpr* cond, WasmAstExpr* thenBranch, WasmAstExpr* elseBranch)
- : WasmAstExpr(Kind),
- cond_(cond),
- thenBranch_(thenBranch),
- elseBranch_(elseBranch)
- {}
-
- WasmAstExpr& cond() const { return *cond_; }
- WasmAstExpr& thenBranch() const { return *thenBranch_; }
- bool hasElse() const { return !!elseBranch_; }
- WasmAstExpr& elseBranch() const { MOZ_ASSERT(hasElse()); return *elseBranch_; }
-};
-
-class WasmAstLoadStoreAddress
-{
- WasmAstExpr* base_;
- int32_t flags_;
- int32_t offset_;
-
- public:
- explicit WasmAstLoadStoreAddress(WasmAstExpr* base, int32_t flags, int32_t offset)
- : base_(base),
- flags_(flags),
- offset_(offset)
- {}
-
- WasmAstExpr& base() const { return *base_; }
- int32_t flags() const { return flags_; }
- int32_t offset() const { return offset_; }
-};
-
-class WasmAstLoad : public WasmAstExpr
-{
- Expr expr_;
- WasmAstLoadStoreAddress address_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Load;
- explicit WasmAstLoad(Expr expr, const WasmAstLoadStoreAddress &address)
- : WasmAstExpr(Kind),
- expr_(expr),
- address_(address)
- {}
-
- Expr expr() const { return expr_; }
- const WasmAstLoadStoreAddress& address() const { return address_; }
-};
-
-class WasmAstStore : public WasmAstExpr
-{
- Expr expr_;
- WasmAstLoadStoreAddress address_;
- WasmAstExpr* value_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::Store;
- explicit WasmAstStore(Expr expr, const WasmAstLoadStoreAddress &address,
- WasmAstExpr* value)
- : WasmAstExpr(Kind),
- expr_(expr),
- address_(address),
- value_(value)
- {}
-
- Expr expr() const { return expr_; }
- const WasmAstLoadStoreAddress& address() const { return address_; }
- WasmAstExpr& value() const { return *value_; }
-};
-
-class WasmAstBranchTable : public WasmAstExpr
-{
- WasmAstExpr& index_;
- WasmRef default_;
- WasmRefVector table_;
- WasmAstExpr* value_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::BranchTable;
- explicit WasmAstBranchTable(WasmAstExpr& index, WasmRef def, WasmRefVector&& table,
- WasmAstExpr* maybeValue)
- : WasmAstExpr(Kind),
- index_(index),
- default_(def),
- table_(Move(table)),
- value_(maybeValue)
- {}
- WasmAstExpr& index() const { return index_; }
- WasmRef& def() { return default_; }
- WasmRefVector& table() { return table_; }
- WasmAstExpr* maybeValue() { return value_; }
-};
-
-class WasmAstFunc : public WasmAstNode
-{
- WasmName name_;
- WasmRef sig_;
- WasmAstValTypeVector vars_;
- WasmNameVector localNames_;
- WasmAstExprVector body_;
-
- public:
- WasmAstFunc(WasmName name, WasmRef sig, WasmAstValTypeVector&& vars,
- WasmNameVector&& locals, WasmAstExprVector&& body)
- : name_(name),
- sig_(sig),
- vars_(Move(vars)),
- localNames_(Move(locals)),
- body_(Move(body))
- {}
- WasmRef& sig() { return sig_; }
- const WasmAstValTypeVector& vars() const { return vars_; }
- const WasmNameVector& locals() const { return localNames_; }
- const WasmAstExprVector& body() const { return body_; }
- WasmName name() const { return name_; }
-};
-
-class WasmAstImport : public WasmAstNode
-{
- WasmName name_;
- WasmName module_;
- WasmName func_;
- uint32_t sigIndex_;
-
- public:
- WasmAstImport(WasmName name, WasmName module, WasmName func, uint32_t sigIndex)
- : name_(name), module_(module), func_(func), sigIndex_(sigIndex)
- {}
- WasmName name() const { return name_; }
- WasmName module() const { return module_; }
- WasmName func() const { return func_; }
- uint32_t sigIndex() const { return sigIndex_; }
-};
-
-enum class WasmAstExportKind { Func, Memory };
-
-class WasmAstExport : public WasmAstNode
-{
- WasmName name_;
- WasmAstExportKind kind_;
- WasmRef func_;
-
- public:
- WasmAstExport(WasmName name, WasmRef func)
- : name_(name), kind_(WasmAstExportKind::Func), func_(func)
- {}
- explicit WasmAstExport(WasmName name)
- : name_(name), kind_(WasmAstExportKind::Memory)
- {}
- WasmName name() const { return name_; }
- WasmAstExportKind kind() const { return kind_; }
- WasmRef& func() { return func_; }
-};
-
-typedef WasmAstVector<WasmRef> WasmAstTableElemVector;
-
-class WasmAstTable : public WasmAstNode
-{
- WasmAstTableElemVector elems_;
-
- public:
- explicit WasmAstTable(WasmAstTableElemVector&& elems) : elems_(Move(elems)) {}
- WasmAstTableElemVector& elems() { return elems_; }
-};
-
-class WasmAstSegment : public WasmAstNode
-{
- uint32_t offset_;
- WasmName text_;
-
- public:
- WasmAstSegment(uint32_t offset, WasmName text)
- : offset_(offset), text_(text)
- {}
- uint32_t offset() const { return offset_; }
- WasmName text() const { return text_; }
-};
-
-typedef WasmAstVector<WasmAstSegment*> WasmAstSegmentVector;
-
-class WasmAstMemory : public WasmAstNode
-{
- uint32_t initialSize_;
- Maybe<uint32_t> maxSize_;
- WasmAstSegmentVector segments_;
-
- public:
- explicit WasmAstMemory(uint32_t initialSize, Maybe<uint32_t> maxSize,
- WasmAstSegmentVector&& segments)
- : initialSize_(initialSize),
- maxSize_(maxSize),
- segments_(Move(segments))
- {}
- uint32_t initialSize() const { return initialSize_; }
- const Maybe<uint32_t>& maxSize() const { return maxSize_; }
- const WasmAstSegmentVector& segments() const { return segments_; }
-};
-
-class WasmAstModule : public WasmAstNode
-{
- typedef WasmAstVector<WasmAstFunc*> FuncVector;
- typedef WasmAstVector<WasmAstImport*> ImportVector;
- typedef WasmAstVector<WasmAstExport*> ExportVector;
- typedef WasmAstVector<WasmAstSig*> SigVector;
- typedef WasmAstHashMap<WasmAstSig*, uint32_t, WasmAstSig> SigMap;
-
- LifoAlloc& lifo_;
- WasmAstMemory* memory_;
- SigVector sigs_;
- SigMap sigMap_;
- ImportVector imports_;
- ExportVector exports_;
- WasmAstTable* table_;
- FuncVector funcs_;
-
- public:
- explicit WasmAstModule(LifoAlloc& lifo)
- : lifo_(lifo),
- memory_(nullptr),
- sigs_(lifo),
- sigMap_(lifo),
- imports_(lifo),
- exports_(lifo),
- table_(nullptr),
- funcs_(lifo)
- {}
- bool init() {
- return sigMap_.init();
- }
- bool setMemory(WasmAstMemory* memory) {
- if (memory_)
- return false;
- memory_ = memory;
- return true;
- }
- WasmAstMemory* maybeMemory() const {
- return memory_;
- }
- bool declare(WasmAstSig&& sig, uint32_t* sigIndex) {
- SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
- if (p) {
- *sigIndex = p->value();
- return true;
- }
- *sigIndex = sigs_.length();
- auto* lifoSig = new (lifo_) WasmAstSig(WasmName(), Move(sig));
- return lifoSig &&
- sigs_.append(lifoSig) &&
- sigMap_.add(p, sigs_.back(), *sigIndex);
- }
- bool append(WasmAstSig* sig) {
- uint32_t sigIndex = sigs_.length();
- if (!sigs_.append(sig))
- return false;
- SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
- return p || sigMap_.add(p, sig, sigIndex);
- }
- const SigVector& sigs() const {
- return sigs_;
- }
- bool append(WasmAstFunc* func) {
- return funcs_.append(func);
- }
- const FuncVector& funcs() const {
- return funcs_;
- }
- const ImportVector& imports() const {
- return imports_;
- }
- bool append(WasmAstImport* imp) {
- return imports_.append(imp);
- }
- bool append(WasmAstExport* exp) {
- return exports_.append(exp);
- }
- const ExportVector& exports() const {
- return exports_;
- }
- bool initTable(WasmAstTable* table) {
- if (table_)
- return false;
- table_ = table;
- return true;
- }
- WasmAstTable* maybeTable() const {
- return table_;
- }
-};
-
-class WasmAstUnaryOperator final : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* op_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::UnaryOperator;
- explicit WasmAstUnaryOperator(Expr expr, WasmAstExpr* op)
- : WasmAstExpr(Kind),
- expr_(expr), op_(op)
- {}
-
- Expr expr() const { return expr_; }
- WasmAstExpr* op() const { return op_; }
-};
-
-class WasmAstBinaryOperator final : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* lhs_;
- WasmAstExpr* rhs_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::BinaryOperator;
- explicit WasmAstBinaryOperator(Expr expr, WasmAstExpr* lhs, WasmAstExpr* rhs)
- : WasmAstExpr(Kind),
- expr_(expr), lhs_(lhs), rhs_(rhs)
- {}
-
- Expr expr() const { return expr_; }
- WasmAstExpr* lhs() const { return lhs_; }
- WasmAstExpr* rhs() const { return rhs_; }
-};
-
-class WasmAstTernaryOperator : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* op0_;
- WasmAstExpr* op1_;
- WasmAstExpr* op2_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::TernaryOperator;
- WasmAstTernaryOperator(Expr expr, WasmAstExpr* op0, WasmAstExpr* op1, WasmAstExpr* op2)
- : WasmAstExpr(Kind),
- expr_(expr), op0_(op0), op1_(op1), op2_(op2)
- {}
-
- Expr expr() const { return expr_; }
- WasmAstExpr* op0() const { return op0_; }
- WasmAstExpr* op1() const { return op1_; }
- WasmAstExpr* op2() const { return op2_; }
-};
-
-class WasmAstComparisonOperator final : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* lhs_;
- WasmAstExpr* rhs_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::ComparisonOperator;
- explicit WasmAstComparisonOperator(Expr expr, WasmAstExpr* lhs, WasmAstExpr* rhs)
- : WasmAstExpr(Kind),
- expr_(expr), lhs_(lhs), rhs_(rhs)
- {}
-
- Expr expr() const { return expr_; }
- WasmAstExpr* lhs() const { return lhs_; }
- WasmAstExpr* rhs() const { return rhs_; }
-};
-
-class WasmAstConversionOperator final : public WasmAstExpr
-{
- Expr expr_;
- WasmAstExpr* op_;
-
- public:
- static const WasmAstExprKind Kind = WasmAstExprKind::ConversionOperator;
- explicit WasmAstConversionOperator(Expr expr, WasmAstExpr* op)
- : WasmAstExpr(Kind),
- expr_(expr), op_(op)
- {}
-
- Expr expr() const { return expr_; }
- WasmAstExpr* op() const { return op_; }
-};
-
-} // end anonymous namespace
-
/*****************************************************************************/
// wasm text token stream
namespace {
class WasmToken
{
public:
@@ -926,25 +197,25 @@ class WasmToken
return kind_;
}
const char16_t* begin() const {
return begin_;
}
const char16_t* end() const {
return end_;
}
- WasmName text() const {
+ AstName text() const {
MOZ_ASSERT(kind_ == Text);
MOZ_ASSERT(begin_[0] == '"');
MOZ_ASSERT(end_[-1] == '"');
MOZ_ASSERT(end_ - begin_ >= 2);
- return WasmName(begin_ + 1, end_ - begin_ - 2);
+ return AstName(begin_ + 1, end_ - begin_ - 2);
}
- WasmName name() const {
- return WasmName(begin_, end_ - begin_);
+ AstName name() const {
+ return AstName(begin_, end_ - begin_);
}
uint32_t index() const {
MOZ_ASSERT(kind_ == Index);
return u.index_;
}
uint64_t uint() const {
MOZ_ASSERT(kind_ == UnsignedInteger);
return u.uint_;
@@ -1224,47 +495,47 @@ class WasmTokenStream
return false;
}
bool getIf(WasmToken::Kind kind) {
WasmToken token;
if (getIf(kind, &token))
return true;
return false;
}
- WasmName getIfName() {
+ AstName getIfName() {
WasmToken token;
if (getIf(WasmToken::Name, &token))
return token.name();
- return WasmName();
+ return AstName();
}
- bool getIfRef(WasmRef* ref) {
+ bool getIfRef(AstRef* ref) {
WasmToken token = peek();
if (token.kind() == WasmToken::Name || token.kind() == WasmToken::Index)
return matchRef(ref, nullptr);
return false;
}
bool match(WasmToken::Kind expect, WasmToken* token, UniqueChars* error) {
*token = get();
if (token->kind() == expect)
return true;
generateError(*token, error);
return false;
}
bool match(WasmToken::Kind expect, UniqueChars* error) {
WasmToken token;
return match(expect, &token, error);
}
- bool matchRef(WasmRef* ref, UniqueChars* error) {
+ bool matchRef(AstRef* ref, UniqueChars* error) {
WasmToken token = get();
switch (token.kind()) {
case WasmToken::Name:
- *ref = WasmRef(token.name(), WasmNoIndex);
+ *ref = AstRef(token.name(), AstNoIndex);
break;
case WasmToken::Index:
- *ref = WasmRef(WasmName(), token.index());
+ *ref = AstRef(AstName(), token.index());
break;
default:
generateError(token, error);
return false;
}
return true;
}
};
@@ -2075,138 +1346,138 @@ struct WasmParseContext
}
~WasmParseContext() {
DestroyDtoaState(dtoaState);
}
};
} // end anonymous namespace
-static WasmAstExpr*
+static AstExpr*
ParseExprInsideParens(WasmParseContext& c);
-static WasmAstExpr*
+static AstExpr*
ParseExpr(WasmParseContext& c)
{
if (!c.ts.match(WasmToken::OpenParen, c.error))
return nullptr;
- WasmAstExpr* expr = ParseExprInsideParens(c);
+ AstExpr* expr = ParseExprInsideParens(c);
if (!expr)
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
return expr;
}
-static WasmAstBlock*
+static AstBlock*
ParseBlock(WasmParseContext& c, Expr expr)
{
- WasmAstExprVector exprs(c.lifo);
-
- WasmName breakName = c.ts.getIfName();
-
- WasmName continueName;
+ AstExprVector exprs(c.lifo);
+
+ AstName breakName = c.ts.getIfName();
+
+ AstName continueName;
if (expr == Expr::Loop)
continueName = c.ts.getIfName();
while (c.ts.getIf(WasmToken::OpenParen)) {
- WasmAstExpr* expr = ParseExprInsideParens(c);
+ AstExpr* expr = ParseExprInsideParens(c);
if (!expr || !exprs.append(expr))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
- return new(c.lifo) WasmAstBlock(expr, breakName, continueName, Move(exprs));
+ return new(c.lifo) AstBlock(expr, breakName, continueName, Move(exprs));
}
-static WasmAstBranch*
+static AstBranch*
ParseBranch(WasmParseContext& c, Expr expr)
{
MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf);
- WasmRef target;
+ AstRef target;
if (!c.ts.matchRef(&target, c.error))
return nullptr;
- WasmAstExpr* value = nullptr;
+ AstExpr* value = nullptr;
if (c.ts.getIf(WasmToken::OpenParen)) {
value = ParseExprInsideParens(c);
if (!value)
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
- WasmAstExpr* cond = nullptr;
+ AstExpr* cond = nullptr;
if (expr == Expr::BrIf) {
if (c.ts.getIf(WasmToken::OpenParen)) {
cond = ParseExprInsideParens(c);
if (!cond)
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
} else {
cond = value;
value = nullptr;
}
}
- return new(c.lifo) WasmAstBranch(expr, cond, target, value);
+ return new(c.lifo) AstBranch(expr, cond, target, value);
}
static bool
-ParseArgs(WasmParseContext& c, WasmAstExprVector* args)
+ParseArgs(WasmParseContext& c, AstExprVector* args)
{
while (c.ts.getIf(WasmToken::OpenParen)) {
- WasmAstExpr* arg = ParseExprInsideParens(c);
+ AstExpr* arg = ParseExprInsideParens(c);
if (!arg || !args->append(arg))
return false;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return false;
}
return true;
}
-static WasmAstCall*
+static AstCall*
ParseCall(WasmParseContext& c, Expr expr)
{
MOZ_ASSERT(expr == Expr::Call || expr == Expr::CallImport);
- WasmRef func;
+ AstRef func;
if (!c.ts.matchRef(&func, c.error))
return nullptr;
- WasmAstExprVector args(c.lifo);
+ AstExprVector args(c.lifo);
if (!ParseArgs(c, &args))
return nullptr;
- return new(c.lifo) WasmAstCall(expr, func, Move(args));
+ return new(c.lifo) AstCall(expr, func, Move(args));
}
-static WasmAstCallIndirect*
+static AstCallIndirect*
ParseCallIndirect(WasmParseContext& c)
{
- WasmRef sig;
+ AstRef sig;
if (!c.ts.matchRef(&sig, c.error))
return nullptr;
- WasmAstExpr* index = ParseExpr(c);
+ AstExpr* index = ParseExpr(c);
if (!index)
return nullptr;
- WasmAstExprVector args(c.lifo);
+ AstExprVector args(c.lifo);
if (!ParseArgs(c, &args))
return nullptr;
- return new(c.lifo) WasmAstCallIndirect(sig, index, Move(args));
+ return new(c.lifo) AstCallIndirect(sig, index, Move(args));
}
static uint_fast8_t
CountLeadingZeroes4(uint8_t x)
{
MOZ_ASSERT((x & -0x10) == 0);
return CountLeadingZeroes32(x) - 28;
}
@@ -2465,201 +1736,201 @@ ParseFloatLiteral(WasmParseContext& c, W
}
if (isNegated)
*result = -*result;
return true;
}
-static WasmAstConst*
+static AstConst*
ParseConst(WasmParseContext& c, WasmToken constToken)
{
WasmToken val = c.ts.get();
switch (constToken.valueType()) {
case ValType::I32: {
switch (val.kind()) {
case WasmToken::Index:
- return new(c.lifo) WasmAstConst(Val(val.index()));
+ return new(c.lifo) AstConst(Val(val.index()));
case WasmToken::SignedInteger: {
CheckedInt<int32_t> sint = val.sint();
if (!sint.isValid())
break;
- return new(c.lifo) WasmAstConst(Val(uint32_t(sint.value())));
+ return new(c.lifo) AstConst(Val(uint32_t(sint.value())));
}
case WasmToken::NegativeZero:
- return new(c.lifo) WasmAstConst(Val(uint32_t(0)));
+ return new(c.lifo) AstConst(Val(uint32_t(0)));
default:
break;
}
break;
}
case ValType::I64: {
switch (val.kind()) {
case WasmToken::Index:
- return new(c.lifo) WasmAstConst(Val(uint64_t(val.index())));
+ return new(c.lifo) AstConst(Val(uint64_t(val.index())));
case WasmToken::UnsignedInteger:
- return new(c.lifo) WasmAstConst(Val(val.uint()));
+ return new(c.lifo) AstConst(Val(val.uint()));
case WasmToken::SignedInteger:
- return new(c.lifo) WasmAstConst(Val(uint64_t(val.sint())));
+ return new(c.lifo) AstConst(Val(uint64_t(val.sint())));
case WasmToken::NegativeZero:
- return new(c.lifo) WasmAstConst(Val(uint64_t(0)));
+ return new(c.lifo) AstConst(Val(uint64_t(0)));
default:
break;
}
break;
}
case ValType::F32: {
float result;
if (!ParseFloatLiteral(c, val, &result))
break;
- return new(c.lifo) WasmAstConst(Val(result));
+ return new(c.lifo) AstConst(Val(result));
}
case ValType::F64: {
double result;
if (!ParseFloatLiteral(c, val, &result))
break;
- return new(c.lifo) WasmAstConst(Val(result));
+ return new(c.lifo) AstConst(Val(result));
}
default:
break;
}
c.ts.generateError(constToken, c.error);
return nullptr;
}
-static WasmAstGetLocal*
+static AstGetLocal*
ParseGetLocal(WasmParseContext& c)
{
- WasmRef local;
+ AstRef local;
if (!c.ts.matchRef(&local, c.error))
return nullptr;
- return new(c.lifo) WasmAstGetLocal(local);
+ return new(c.lifo) AstGetLocal(local);
}
-static WasmAstSetLocal*
+static AstSetLocal*
ParseSetLocal(WasmParseContext& c)
{
- WasmRef local;
+ AstRef local;
if (!c.ts.matchRef(&local, c.error))
return nullptr;
- WasmAstExpr* value = ParseExpr(c);
+ AstExpr* value = ParseExpr(c);
if (!value)
return nullptr;
- return new(c.lifo) WasmAstSetLocal(local, *value);
+ return new(c.lifo) AstSetLocal(local, *value);
}
-static WasmAstReturn*
+static AstReturn*
ParseReturn(WasmParseContext& c)
{
- WasmAstExpr* maybeExpr = nullptr;
+ AstExpr* maybeExpr = nullptr;
if (c.ts.peek().kind() != WasmToken::CloseParen) {
maybeExpr = ParseExpr(c);
if (!maybeExpr)
return nullptr;
}
- return new(c.lifo) WasmAstReturn(maybeExpr);
+ return new(c.lifo) AstReturn(maybeExpr);
}
-static WasmAstUnaryOperator*
+static AstUnaryOperator*
ParseUnaryOperator(WasmParseContext& c, Expr expr)
{
- WasmAstExpr* op = ParseExpr(c);
+ AstExpr* op = ParseExpr(c);
if (!op)
return nullptr;
- return new(c.lifo) WasmAstUnaryOperator(expr, op);
+ return new(c.lifo) AstUnaryOperator(expr, op);
}
-static WasmAstBinaryOperator*
+static AstBinaryOperator*
ParseBinaryOperator(WasmParseContext& c, Expr expr)
{
- WasmAstExpr* lhs = ParseExpr(c);
+ AstExpr* lhs = ParseExpr(c);
if (!lhs)
return nullptr;
- WasmAstExpr* rhs = ParseExpr(c);
+ AstExpr* rhs = ParseExpr(c);
if (!rhs)
return nullptr;
- return new(c.lifo) WasmAstBinaryOperator(expr, lhs, rhs);
+ return new(c.lifo) AstBinaryOperator(expr, lhs, rhs);
}
-static WasmAstComparisonOperator*
+static AstComparisonOperator*
ParseComparisonOperator(WasmParseContext& c, Expr expr)
{
- WasmAstExpr* lhs = ParseExpr(c);
+ AstExpr* lhs = ParseExpr(c);
if (!lhs)
return nullptr;
- WasmAstExpr* rhs = ParseExpr(c);
+ AstExpr* rhs = ParseExpr(c);
if (!rhs)
return nullptr;
- return new(c.lifo) WasmAstComparisonOperator(expr, lhs, rhs);
+ return new(c.lifo) AstComparisonOperator(expr, lhs, rhs);
}
-static WasmAstTernaryOperator*
+static AstTernaryOperator*
ParseTernaryOperator(WasmParseContext& c, Expr expr)
{
- WasmAstExpr* op0 = ParseExpr(c);
+ AstExpr* op0 = ParseExpr(c);
if (!op0)
return nullptr;
- WasmAstExpr* op1 = ParseExpr(c);
+ AstExpr* op1 = ParseExpr(c);
if (!op1)
return nullptr;
- WasmAstExpr* op2 = ParseExpr(c);
+ AstExpr* op2 = ParseExpr(c);
if (!op2)
return nullptr;
- return new(c.lifo) WasmAstTernaryOperator(expr, op0, op1, op2);
+ return new(c.lifo) AstTernaryOperator(expr, op0, op1, op2);
}
-static WasmAstConversionOperator*
+static AstConversionOperator*
ParseConversionOperator(WasmParseContext& c, Expr expr)
{
- WasmAstExpr* op = ParseExpr(c);
+ AstExpr* op = ParseExpr(c);
if (!op)
return nullptr;
- return new(c.lifo) WasmAstConversionOperator(expr, op);
+ return new(c.lifo) AstConversionOperator(expr, op);
}
-static WasmAstIf*
+static AstIf*
ParseIf(WasmParseContext& c)
{
- WasmAstExpr* cond = ParseExpr(c);
+ AstExpr* cond = ParseExpr(c);
if (!cond)
return nullptr;
- WasmAstExpr* thenBranch = ParseExpr(c);
+ AstExpr* thenBranch = ParseExpr(c);
if (!thenBranch)
return nullptr;
- WasmAstExpr* elseBranch = nullptr;
+ AstExpr* elseBranch = nullptr;
if (c.ts.getIf(WasmToken::OpenParen)) {
elseBranch = ParseExprInsideParens(c);
if (!elseBranch)
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
- return new(c.lifo) WasmAstIf(cond, thenBranch, elseBranch);
+ return new(c.lifo) AstIf(cond, thenBranch, elseBranch);
}
static bool
-ParseLoadStoreAddress(WasmParseContext& c, int32_t* offset, uint32_t* alignLog2, WasmAstExpr** base)
+ParseLoadStoreAddress(WasmParseContext& c, int32_t* offset, uint32_t* alignLog2, AstExpr** base)
{
*offset = 0;
if (c.ts.getIf(WasmToken::Offset)) {
if (!c.ts.match(WasmToken::Equal, c.error))
return false;
WasmToken val = c.ts.get();
switch (val.kind()) {
case WasmToken::Index:
@@ -2692,22 +1963,22 @@ ParseLoadStoreAddress(WasmParseContext&
*base = ParseExpr(c);
if (!*base)
return false;
return true;
}
-static WasmAstLoad*
+static AstLoad*
ParseLoad(WasmParseContext& c, Expr expr)
{
int32_t offset;
uint32_t alignLog2;
- WasmAstExpr* base;
+ AstExpr* base;
if (!ParseLoadStoreAddress(c, &offset, &alignLog2, &base))
return nullptr;
if (alignLog2 == UINT32_MAX) {
switch (expr) {
case Expr::I32Load8S:
case Expr::I32Load8U:
case Expr::I64Load8S:
@@ -2732,25 +2003,25 @@ ParseLoad(WasmParseContext& c, Expr expr
break;
default:
MOZ_CRASH("Bad load expr");
}
}
uint32_t flags = alignLog2;
- return new(c.lifo) WasmAstLoad(expr, WasmAstLoadStoreAddress(base, flags, offset));
+ return new(c.lifo) AstLoad(expr, AstLoadStoreAddress(base, flags, offset));
}
-static WasmAstStore*
+static AstStore*
ParseStore(WasmParseContext& c, Expr expr)
{
int32_t offset;
uint32_t alignLog2;
- WasmAstExpr* base;
+ AstExpr* base;
if (!ParseLoadStoreAddress(c, &offset, &alignLog2, &base))
return nullptr;
if (alignLog2 == UINT32_MAX) {
switch (expr) {
case Expr::I32Store8:
case Expr::I64Store8:
alignLog2 = 0;
@@ -2768,70 +2039,70 @@ ParseStore(WasmParseContext& c, Expr exp
case Expr::F64Store:
alignLog2 = 3;
break;
default:
MOZ_CRASH("Bad load expr");
}
}
- WasmAstExpr* value = ParseExpr(c);
+ AstExpr* value = ParseExpr(c);
if (!value)
return nullptr;
uint32_t flags = alignLog2;
- return new(c.lifo) WasmAstStore(expr, WasmAstLoadStoreAddress(base, flags, offset), value);
+ return new(c.lifo) AstStore(expr, AstLoadStoreAddress(base, flags, offset), value);
}
-static WasmAstBranchTable*
+static AstBranchTable*
ParseBranchTable(WasmParseContext& c, WasmToken brTable)
{
- WasmRefVector table(c.lifo);
-
- WasmRef target;
+ AstRefVector table(c.lifo);
+
+ AstRef target;
while (c.ts.getIfRef(&target)) {
if (!table.append(target))
return nullptr;
}
if (table.empty()) {
c.ts.generateError(brTable, c.error);
return nullptr;
}
- WasmRef def = table.popCopy();
-
- WasmAstExpr* index = ParseExpr(c);
+ AstRef def = table.popCopy();
+
+ AstExpr* index = ParseExpr(c);
if (!index)
return nullptr;
- WasmAstExpr* value = nullptr;
+ AstExpr* value = nullptr;
if (c.ts.getIf(WasmToken::OpenParen)) {
value = index;
index = ParseExprInsideParens(c);
if (!index)
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
- return new(c.lifo) WasmAstBranchTable(*index, def, Move(table), value);
+ return new(c.lifo) AstBranchTable(*index, def, Move(table), value);
}
-static WasmAstExpr*
+static AstExpr*
ParseExprInsideParens(WasmParseContext& c)
{
WasmToken token = c.ts.get();
switch (token.kind()) {
case WasmToken::Nop:
- return new(c.lifo) WasmAstNop;
+ return new(c.lifo) AstNop;
case WasmToken::Unreachable:
- return new(c.lifo) WasmAstUnreachable;
+ return new(c.lifo) AstUnreachable;
case WasmToken::BinaryOpcode:
return ParseBinaryOperator(c, token.expr());
case WasmToken::Block:
return ParseBlock(c, Expr::Block);
case WasmToken::Br:
return ParseBranch(c, Expr::Br);
case WasmToken::BrIf:
return ParseBranch(c, Expr::BrIf);
@@ -2869,25 +2140,25 @@ ParseExprInsideParens(WasmParseContext&
return ParseUnaryOperator(c, token.expr());
default:
c.ts.generateError(token, c.error);
return nullptr;
}
}
static bool
-ParseValueType(WasmParseContext& c, WasmAstValTypeVector* vec)
+ParseValueType(WasmParseContext& c, AstValTypeVector* vec)
{
WasmToken token;
return c.ts.match(WasmToken::ValueType, &token, c.error) &&
vec->append(token.valueType());
}
static bool
-ParseValueTypeList(WasmParseContext& c, WasmAstValTypeVector* vec)
+ParseValueTypeList(WasmParseContext& c, AstValTypeVector* vec)
{
WasmToken token;
while (c.ts.getIf(WasmToken::ValueType, &token)) {
if (!vec->append(token.valueType()))
return false;
}
return true;
@@ -2905,56 +2176,56 @@ ParseResult(WasmParseContext& c, ExprTyp
if (!c.ts.match(WasmToken::ValueType, &token, c.error))
return false;
*result = ToExprType(token.valueType());
return true;
}
static bool
-ParseLocal(WasmParseContext& c, WasmNameVector* locals, WasmAstValTypeVector* localTypes)
+ParseLocal(WasmParseContext& c, AstNameVector* locals, AstValTypeVector* localTypes)
{
return locals->append(c.ts.getIfName()) &&
ParseValueType(c, localTypes);
}
static bool
-ParseParam(WasmParseContext& c, WasmNameVector* locals, WasmAstValTypeVector* args)
+ParseParam(WasmParseContext& c, AstNameVector* locals, AstValTypeVector* args)
{
if (c.ts.peek().kind() == WasmToken::Name)
return ParseLocal(c, locals, args);
- return locals->append(WasmName()) &&
+ return locals->append(AstName()) &&
ParseValueTypeList(c, args);
}
-static WasmAstFunc*
-ParseFunc(WasmParseContext& c, WasmAstModule* module)
+static AstFunc*
+ParseFunc(WasmParseContext& c, AstModule* module)
{
- WasmAstValTypeVector vars(c.lifo);
- WasmAstValTypeVector args(c.lifo);
- WasmNameVector locals(c.lifo);
-
- WasmName funcName = c.ts.getIfName();
-
- WasmRef sig;
+ AstValTypeVector vars(c.lifo);
+ AstValTypeVector args(c.lifo);
+ AstNameVector locals(c.lifo);
+
+ AstName funcName = c.ts.getIfName();
+
+ AstRef sig;
WasmToken openParen;
if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
if (c.ts.getIf(WasmToken::Type)) {
if (!c.ts.matchRef(&sig, c.error))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
} else {
c.ts.unget(openParen);
}
}
- WasmAstExprVector body(c.lifo);
+ AstExprVector body(c.lifo);
ExprType result = ExprType::Void;
while (c.ts.getIf(WasmToken::OpenParen)) {
WasmToken token = c.ts.get();
switch (token.kind()) {
case WasmToken::Local:
if (!ParseLocal(c, &locals, &vars))
return nullptr;
@@ -2968,39 +2239,39 @@ ParseFunc(WasmParseContext& c, WasmAstMo
return nullptr;
break;
case WasmToken::Result:
if (!ParseResult(c, &result))
return nullptr;
break;
default:
c.ts.unget(token);
- WasmAstExpr* expr = ParseExprInsideParens(c);
+ AstExpr* expr = ParseExprInsideParens(c);
if (!expr || !body.append(expr))
return nullptr;
break;
}
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
if (sig.isInvalid()) {
uint32_t sigIndex;
- if (!module->declare(WasmAstSig(Move(args), result), &sigIndex))
+ if (!module->declare(AstSig(Move(args), result), &sigIndex))
return nullptr;
sig.setIndex(sigIndex);
}
- return new(c.lifo) WasmAstFunc(funcName, sig, Move(vars), Move(locals), Move(body));
+ return new(c.lifo) AstFunc(funcName, sig, Move(vars), Move(locals), Move(body));
}
static bool
-ParseFuncType(WasmParseContext& c, WasmAstSig* sig)
+ParseFuncType(WasmParseContext& c, AstSig* sig)
{
- WasmAstValTypeVector args(c.lifo);
+ AstValTypeVector args(c.lifo);
ExprType result = ExprType::Void;
while (c.ts.getIf(WasmToken::OpenParen)) {
WasmToken token = c.ts.get();
switch (token.kind()) {
case WasmToken::Param:
if (!ParseValueTypeList(c, &args))
return false;
@@ -3012,205 +2283,205 @@ ParseFuncType(WasmParseContext& c, WasmA
default:
c.ts.generateError(token, c.error);
return false;
}
if (!c.ts.match(WasmToken::CloseParen, c.error))
return false;
}
- *sig = WasmAstSig(Move(args), result);
+ *sig = AstSig(Move(args), result);
return true;
}
-static WasmAstSig*
+static AstSig*
ParseTypeDef(WasmParseContext& c)
{
- WasmName name = c.ts.getIfName();
+ AstName name = c.ts.getIfName();
if (!c.ts.match(WasmToken::OpenParen, c.error))
return nullptr;
if (!c.ts.match(WasmToken::Func, c.error))
return nullptr;
- WasmAstSig sig(c.lifo);
+ AstSig sig(c.lifo);
if (!ParseFuncType(c, &sig))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
- return new(c.lifo) WasmAstSig(name, Move(sig));
+ return new(c.lifo) AstSig(name, Move(sig));
}
-static WasmAstSegment*
+static AstSegment*
ParseSegment(WasmParseContext& c)
{
if (!c.ts.match(WasmToken::Segment, c.error))
return nullptr;
WasmToken dstOffset;
if (!c.ts.match(WasmToken::Index, &dstOffset, c.error))
return nullptr;
WasmToken text;
if (!c.ts.match(WasmToken::Text, &text, c.error))
return nullptr;
- return new(c.lifo) WasmAstSegment(dstOffset.index(), text.text());
+ return new(c.lifo) AstSegment(dstOffset.index(), text.text());
}
-static WasmAstMemory*
+static AstMemory*
ParseMemory(WasmParseContext& c)
{
WasmToken initialSize;
if (!c.ts.match(WasmToken::Index, &initialSize, c.error))
return nullptr;
Maybe<uint32_t> maxSize;
WasmToken token;
if (c.ts.getIf(WasmToken::Index, &token))
maxSize.emplace(token.index());
- WasmAstSegmentVector segments(c.lifo);
+ AstSegmentVector segments(c.lifo);
while (c.ts.getIf(WasmToken::OpenParen)) {
- WasmAstSegment* segment = ParseSegment(c);
+ AstSegment* segment = ParseSegment(c);
if (!segment || !segments.append(segment))
return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
- return new(c.lifo) WasmAstMemory(initialSize.index(), maxSize, Move(segments));
+ return new(c.lifo) AstMemory(initialSize.index(), maxSize, Move(segments));
}
-static WasmAstImport*
-ParseImport(WasmParseContext& c, WasmAstModule* module)
+static AstImport*
+ParseImport(WasmParseContext& c, AstModule* module)
{
- WasmName name = c.ts.getIfName();
+ AstName name = c.ts.getIfName();
WasmToken moduleName;
if (!c.ts.match(WasmToken::Text, &moduleName, c.error))
return nullptr;
WasmToken funcName;
if (!c.ts.match(WasmToken::Text, &funcName, c.error))
return nullptr;
- WasmAstSig sig(c.lifo);
+ AstSig sig(c.lifo);
if (!ParseFuncType(c, &sig))
return nullptr;
uint32_t sigIndex;
if (!module->declare(Move(sig), &sigIndex))
return nullptr;
- return new(c.lifo) WasmAstImport(name, moduleName.text(), funcName.text(), sigIndex);
+ return new(c.lifo) AstImport(name, moduleName.text(), funcName.text(), sigIndex);
}
-static WasmAstExport*
+static AstExport*
ParseExport(WasmParseContext& c)
{
WasmToken name;
if (!c.ts.match(WasmToken::Text, &name, c.error))
return nullptr;
WasmToken exportee = c.ts.get();
switch (exportee.kind()) {
case WasmToken::Index:
- return new(c.lifo) WasmAstExport(name.text(), WasmRef(WasmName(), exportee.index()));
+ return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
case WasmToken::Name:
- return new(c.lifo) WasmAstExport(name.text(), WasmRef(exportee.name(), WasmNoIndex));
+ return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
case WasmToken::Memory:
- if (name.text() != WasmName(MOZ_UTF16("memory"), 6)) {
+ if (name.text() != AstName(MOZ_UTF16("memory"), 6)) {
c.ts.generateError(exportee, c.error);
return nullptr;
}
- return new(c.lifo) WasmAstExport(name.text());
+ return new(c.lifo) AstExport(name.text());
default:
break;
}
c.ts.generateError(exportee, c.error);
return nullptr;
}
-static WasmAstTable*
+static AstTable*
ParseTable(WasmParseContext& c)
{
- WasmAstTableElemVector elems(c.lifo);
-
- WasmRef elem;
+ AstTableElemVector elems(c.lifo);
+
+ AstRef elem;
while (c.ts.getIfRef(&elem)) {
if (!elems.append(elem))
return nullptr;
}
- return new(c.lifo) WasmAstTable(Move(elems));
+ return new(c.lifo) AstTable(Move(elems));
}
-static WasmAstModule*
+static AstModule*
ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
{
WasmParseContext c(text, lifo, error);
if (!c.ts.match(WasmToken::OpenParen, c.error))
return nullptr;
if (!c.ts.match(WasmToken::Module, c.error))
return nullptr;
- auto module = new(c.lifo) WasmAstModule(c.lifo);
+ auto module = new(c.lifo) AstModule(c.lifo);
if (!module || !module->init())
return nullptr;
while (c.ts.getIf(WasmToken::OpenParen)) {
WasmToken section = c.ts.get();
switch (section.kind()) {
case WasmToken::Type: {
- WasmAstSig* sig = ParseTypeDef(c);
+ AstSig* sig = ParseTypeDef(c);
if (!sig || !module->append(sig))
return nullptr;
break;
}
case WasmToken::Memory: {
- WasmAstMemory* memory = ParseMemory(c);
+ AstMemory* memory = ParseMemory(c);
if (!memory)
return nullptr;
if (!module->setMemory(memory)) {
c.ts.generateError(section, c.error);
return nullptr;
}
break;
}
case WasmToken::Import: {
- WasmAstImport* imp = ParseImport(c, module);
+ AstImport* imp = ParseImport(c, module);
if (!imp || !module->append(imp))
return nullptr;
break;
}
case WasmToken::Export: {
- WasmAstExport* exp = ParseExport(c);
+ AstExport* exp = ParseExport(c);
if (!exp || !module->append(exp))
return nullptr;
break;
}
case WasmToken::Table: {
- WasmAstTable* table = ParseTable(c);
+ AstTable* table = ParseTable(c);
if (!table)
return nullptr;
if (!module->initTable(table)) {
c.ts.generateError(section, c.error);
return nullptr;
}
break;
}
case WasmToken::Func: {
- WasmAstFunc* func = ParseFunc(c, module);
+ AstFunc* func = ParseFunc(c, module);
if (!func || !module->append(func))
return nullptr;
break;
}
default:
c.ts.generateError(section, c.error);
return nullptr;
}
@@ -3230,49 +2501,49 @@ ParseModule(const char16_t* text, LifoAl
/*****************************************************************************/
// wasm name resolution
namespace {
class Resolver
{
UniqueChars* error_;
- WasmNameMap varMap_;
- WasmNameMap sigMap_;
- WasmNameMap funcMap_;
- WasmNameMap importMap_;
- WasmNameVector targetStack_;
-
- bool registerName(WasmNameMap& map, WasmName name, size_t index) {
- WasmNameMap::AddPtr p = map.lookupForAdd(name);
+ AstNameMap varMap_;
+ AstNameMap sigMap_;
+ AstNameMap funcMap_;
+ AstNameMap importMap_;
+ AstNameVector targetStack_;
+
+ bool registerName(AstNameMap& map, AstName name, size_t index) {
+ AstNameMap::AddPtr p = map.lookupForAdd(name);
if (!p) {
if (!map.add(p, name, index))
return false;
} else {
return false;
}
return true;
}
- bool resolveName(WasmNameMap& map, WasmName name, size_t* index) {
- WasmNameMap::Ptr p = map.lookup(name);
+ bool resolveName(AstNameMap& map, AstName name, size_t* index) {
+ AstNameMap::Ptr p = map.lookup(name);
if (p) {
*index = p->value();
return true;
}
return false;
}
- bool resolveRef(WasmNameMap& map, WasmRef& ref) {
- WasmNameMap::Ptr p = map.lookup(ref.name());
+ bool resolveRef(AstNameMap& map, AstRef& ref) {
+ AstNameMap::Ptr p = map.lookup(ref.name());
if (p) {
ref.setIndex(p->value());
return true;
}
return false;
}
- bool failResolveLabel(const char* kind, WasmName name) {
+ bool failResolveLabel(const char* kind, AstName name) {
Vector<char16_t, 0, SystemAllocPolicy> nameWithNull;
if (!nameWithNull.append(name.begin(), name.length()))
return false;
if (!nameWithNull.append(0))
return false;
error_->reset(JS_smprintf("%s label '%hs' not found", kind, nameWithNull.begin()));
return false;
}
@@ -3288,57 +2559,57 @@ class Resolver
{}
bool init() {
return sigMap_.init() && funcMap_.init() && importMap_.init() && varMap_.init();
}
void beginFunc() {
varMap_.clear();
MOZ_ASSERT(targetStack_.empty());
}
- bool registerSigName(WasmName name, size_t index) {
+ bool registerSigName(AstName name, size_t index) {
return name.empty() || registerName(sigMap_, name, index);
}
- bool registerFuncName(WasmName name, size_t index) {
+ bool registerFuncName(AstName name, size_t index) {
return name.empty() || registerName(funcMap_, name, index);
}
- bool registerImportName(WasmName name, size_t index) {
+ bool registerImportName(AstName name, size_t index) {
return name.empty() || registerName(importMap_, name, index);
}
- bool registerVarName(WasmName name, size_t index) {
+ bool registerVarName(AstName name, size_t index) {
return name.empty() || registerName(varMap_, name, index);
}
- bool pushTarget(WasmName name) {
+ bool pushTarget(AstName name) {
return targetStack_.append(name);
}
- void popTarget(WasmName name) {
+ void popTarget(AstName name) {
MOZ_ASSERT(targetStack_.back() == name);
targetStack_.popBack();
}
- bool resolveSignature(WasmRef& ref) {
+ bool resolveSignature(AstRef& ref) {
if (!ref.name().empty() && !resolveRef(sigMap_, ref))
return failResolveLabel("signature", ref.name());
return true;
}
- bool resolveFunction(WasmRef& ref) {
+ bool resolveFunction(AstRef& ref) {
if (!ref.name().empty() && !resolveRef(funcMap_, ref))
return failResolveLabel("function", ref.name());
return true;
}
- bool resolveImport(WasmRef& ref) {
+ bool resolveImport(AstRef& ref) {
if (!ref.name().empty() && !resolveRef(importMap_, ref))
return failResolveLabel("import", ref.name());
return true;
}
- bool resolveLocal(WasmRef& ref) {
+ bool resolveLocal(AstRef& ref) {
if (!ref.name().empty() && !resolveRef(varMap_, ref))
return failResolveLabel("local", ref.name());
return true;
}
- bool resolveBranchTarget(WasmRef& ref) {
+ bool resolveBranchTarget(AstRef& ref) {
if (ref.name().empty())
return true;
for (size_t i = 0, e = targetStack_.length(); i < e; i++) {
if (targetStack_[e - i - 1] == ref.name()) {
ref.setIndex(i);
return true;
}
}
@@ -3349,20 +2620,20 @@ class Resolver
error_->reset(JS_smprintf("%s", message));
return false;
}
};
} // end anonymous namespace
static bool
-ResolveExpr(Resolver& r, WasmAstExpr& expr);
+ResolveExpr(Resolver& r, AstExpr& expr);
static bool
-ResolveBlock(Resolver& r, WasmAstBlock& b)
+ResolveBlock(Resolver& r, AstBlock& b)
{
if (!r.pushTarget(b.breakName()))
return false;
if (b.expr() == Expr::Loop) {
if (!r.pushTarget(b.continueName()))
return false;
}
@@ -3375,45 +2646,45 @@ ResolveBlock(Resolver& r, WasmAstBlock&
if (b.expr() == Expr::Loop)
r.popTarget(b.continueName());
r.popTarget(b.breakName());
return true;
}
static bool
-ResolveBranch(Resolver& r, WasmAstBranch& br)
+ResolveBranch(Resolver& r, AstBranch& br)
{
if (!r.resolveBranchTarget(br.target()))
return false;
if (br.maybeValue() && !ResolveExpr(r, *br.maybeValue()))
return false;
if (br.expr() == Expr::BrIf) {
if (!ResolveExpr(r, br.cond()))
return false;
}
return true;
}
static bool
-ResolveArgs(Resolver& r, const WasmAstExprVector& args)
+ResolveArgs(Resolver& r, const AstExprVector& args)
{
- for (WasmAstExpr* arg : args) {
+ for (AstExpr* arg : args) {
if (!ResolveExpr(r, *arg))
return false;
}
return true;
}
static bool
-ResolveCall(Resolver& r, WasmAstCall& c)
+ResolveCall(Resolver& r, AstCall& c)
{
if (!ResolveArgs(r, c.args()))
return false;
if (c.expr() == Expr::Call) {
if (!r.resolveFunction(c.func()))
return false;
} else {
@@ -3421,262 +2692,262 @@ ResolveCall(Resolver& r, WasmAstCall& c)
if (!r.resolveImport(c.func()))
return false;
}
return true;
}
static bool
-ResolveCallIndirect(Resolver& r, WasmAstCallIndirect& c)
+ResolveCallIndirect(Resolver& r, AstCallIndirect& c)
{
if (!ResolveExpr(r, *c.index()))
return false;
if (!ResolveArgs(r, c.args()))
return false;
if (!r.resolveSignature(c.sig()))
return false;
return true;
}
static bool
-ResolveGetLocal(Resolver& r, WasmAstGetLocal& gl)
+ResolveGetLocal(Resolver& r, AstGetLocal& gl)
{
return r.resolveLocal(gl.local());
}
static bool
-ResolveSetLocal(Resolver& r, WasmAstSetLocal& sl)
+ResolveSetLocal(Resolver& r, AstSetLocal& sl)
{
if (!ResolveExpr(r, sl.value()))
return false;
if (!r.resolveLocal(sl.local()))
return false;
return true;
}
static bool
-ResolveUnaryOperator(Resolver& r, WasmAstUnaryOperator& b)
+ResolveUnaryOperator(Resolver& r, AstUnaryOperator& b)
{
return ResolveExpr(r, *b.op());
}
static bool
-ResolveBinaryOperator(Resolver& r, WasmAstBinaryOperator& b)
+ResolveBinaryOperator(Resolver& r, AstBinaryOperator& b)
{
return ResolveExpr(r, *b.lhs()) &&
ResolveExpr(r, *b.rhs());
}
static bool
-ResolveTernaryOperator(Resolver& r, WasmAstTernaryOperator& b)
+ResolveTernaryOperator(Resolver& r, AstTernaryOperator& b)
{
return ResolveExpr(r, *b.op0()) &&
ResolveExpr(r, *b.op1()) &&
ResolveExpr(r, *b.op2());
}
static bool
-ResolveComparisonOperator(Resolver& r, WasmAstComparisonOperator& b)
+ResolveComparisonOperator(Resolver& r, AstComparisonOperator& b)
{
return ResolveExpr(r, *b.lhs()) &&
ResolveExpr(r, *b.rhs());
}
static bool
-ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b)
+ResolveConversionOperator(Resolver& r, AstConversionOperator& b)
{
return ResolveExpr(r, *b.op());
}
static bool
-ResolveIfElse(Resolver& r, WasmAstIf& i)
+ResolveIfElse(Resolver& r, AstIf& i)
{
if (!ResolveExpr(r, i.cond()))
return false;
- if (!r.pushTarget(WasmName()))
+ if (!r.pushTarget(AstName()))
return false;
if (!ResolveExpr(r, i.thenBranch()))
return false;
if (i.hasElse()) {
if (!ResolveExpr(r, i.elseBranch()))
return false;
}
- r.popTarget(WasmName());
+ r.popTarget(AstName());
return true;
}
static bool
-ResolveLoadStoreAddress(Resolver& r, const WasmAstLoadStoreAddress &address)
+ResolveLoadStoreAddress(Resolver& r, const AstLoadStoreAddress &address)
{
return ResolveExpr(r, address.base());
}
static bool
-ResolveLoad(Resolver& r, WasmAstLoad& l)
+ResolveLoad(Resolver& r, AstLoad& l)
{
return ResolveLoadStoreAddress(r, l.address());
}
static bool
-ResolveStore(Resolver& r, WasmAstStore& s)
+ResolveStore(Resolver& r, AstStore& s)
{
return ResolveLoadStoreAddress(r, s.address()) &&
ResolveExpr(r, s.value());
}
static bool
-ResolveReturn(Resolver& r, WasmAstReturn& ret)
+ResolveReturn(Resolver& r, AstReturn& ret)
{
return !ret.maybeExpr() || ResolveExpr(r, *ret.maybeExpr());
}
static bool
-ResolveBranchTable(Resolver& r, WasmAstBranchTable& bt)
+ResolveBranchTable(Resolver& r, AstBranchTable& bt)
{
if (!r.resolveBranchTarget(bt.def()))
return false;
- for (WasmRef& elem : bt.table()) {
+ for (AstRef& elem : bt.table()) {
if (!r.resolveBranchTarget(elem))
return false;
}
return ResolveExpr(r, bt.index());
}
static bool
-ResolveExpr(Resolver& r, WasmAstExpr& expr)
+ResolveExpr(Resolver& r, AstExpr& expr)
{
switch (expr.kind()) {
- case WasmAstExprKind::Nop:
- case WasmAstExprKind::Unreachable:
+ case AstExprKind::Nop:
+ case AstExprKind::Unreachable:
return true;
- case WasmAstExprKind::BinaryOperator:
- return ResolveBinaryOperator(r, expr.as<WasmAstBinaryOperator>());
- case WasmAstExprKind::Block:
- return ResolveBlock(r, expr.as<WasmAstBlock>());
- case WasmAstExprKind::Branch:
- return ResolveBranch(r, expr.as<WasmAstBranch>());
- case WasmAstExprKind::Call:
- return ResolveCall(r, expr.as<WasmAstCall>());
- case WasmAstExprKind::CallIndirect:
- return ResolveCallIndirect(r, expr.as<WasmAstCallIndirect>());
- case WasmAstExprKind::ComparisonOperator:
- return ResolveComparisonOperator(r, expr.as<WasmAstComparisonOperator>());
- case WasmAstExprKind::Const:
+ case AstExprKind::BinaryOperator:
+ return ResolveBinaryOperator(r, expr.as<AstBinaryOperator>());
+ case AstExprKind::Block:
+ return ResolveBlock(r, expr.as<AstBlock>());
+ case AstExprKind::Branch:
+ return ResolveBranch(r, expr.as<AstBranch>());
+ case AstExprKind::Call:
+ return ResolveCall(r, expr.as<AstCall>());
+ case AstExprKind::CallIndirect:
+ return ResolveCallIndirect(r, expr.as<AstCallIndirect>());
+ case AstExprKind::ComparisonOperator:
+ return ResolveComparisonOperator(r, expr.as<AstComparisonOperator>());
+ case AstExprKind::Const:
return true;
- case WasmAstExprKind::ConversionOperator:
- return ResolveConversionOperator(r, expr.as<WasmAstConversionOperator>());
- case WasmAstExprKind::GetLocal:
- return ResolveGetLocal(r, expr.as<WasmAstGetLocal>());
- case WasmAstExprKind::If:
- return ResolveIfElse(r, expr.as<WasmAstIf>());
- case WasmAstExprKind::Load:
- return ResolveLoad(r, expr.as<WasmAstLoad>());
- case WasmAstExprKind::Return:
- return ResolveReturn(r, expr.as<WasmAstReturn>());
- case WasmAstExprKind::SetLocal:
- return ResolveSetLocal(r, expr.as<WasmAstSetLocal>());
- case WasmAstExprKind::Store:
- return ResolveStore(r, expr.as<WasmAstStore>());
- case WasmAstExprKind::BranchTable:
- return ResolveBranchTable(r, expr.as<WasmAstBranchTable>());
- case WasmAstExprKind::TernaryOperator:
- return ResolveTernaryOperator(r, expr.as<WasmAstTernaryOperator>());
- case WasmAstExprKind::UnaryOperator:
- return ResolveUnaryOperator(r, expr.as<WasmAstUnaryOperator>());
+ case AstExprKind::ConversionOperator:
+ return ResolveConversionOperator(r, expr.as<AstConversionOperator>());
+ case AstExprKind::GetLocal:
+ return ResolveGetLocal(r, expr.as<AstGetLocal>());
+ case AstExprKind::If:
+ return ResolveIfElse(r, expr.as<AstIf>());
+ case AstExprKind::Load:
+ return ResolveLoad(r, expr.as<AstLoad>());
+ case AstExprKind::Return:
+ return ResolveReturn(r, expr.as<AstReturn>());
+ case AstExprKind::SetLocal:
+ return ResolveSetLocal(r, expr.as<AstSetLocal>());
+ case AstExprKind::Store:
+ return ResolveStore(r, expr.as<AstStore>());
+ case AstExprKind::BranchTable:
+ return ResolveBranchTable(r, expr.as<AstBranchTable>());
+ case AstExprKind::TernaryOperator:
+ return ResolveTernaryOperator(r, expr.as<AstTernaryOperator>());
+ case AstExprKind::UnaryOperator:
+ return ResolveUnaryOperator(r, expr.as<AstUnaryOperator>());
}
MOZ_CRASH("Bad expr kind");
}
static bool
-ResolveFunc(Resolver& r, WasmAstFunc& func)
+ResolveFunc(Resolver& r, AstFunc& func)
{
r.beginFunc();
size_t numVars = func.locals().length();
for (size_t i = 0; i < numVars; i++) {
if (!r.registerVarName(func.locals()[i], i))
return r.fail("duplicate var");
}
- for (WasmAstExpr* expr : func.body()) {
+ for (AstExpr* expr : func.body()) {
if (!ResolveExpr(r, *expr))
return false;
}
return true;
}
static bool
-ResolveModule(LifoAlloc& lifo, WasmAstModule* module, UniqueChars* error)
+ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
{
Resolver r(lifo, error);
if (!r.init())
return false;
size_t numSigs = module->sigs().length();
for (size_t i = 0; i < numSigs; i++) {
- WasmAstSig* sig = module->sigs()[i];
+ AstSig* sig = module->sigs()[i];
if (!r.registerSigName(sig->name(), i))
return r.fail("duplicate signature");
}
size_t numFuncs = module->funcs().length();
for (size_t i = 0; i < numFuncs; i++) {
- WasmAstFunc* func = module->funcs()[i];
+ AstFunc* func = module->funcs()[i];
if (!r.resolveSignature(func->sig()))
return false;
if (!r.registerFuncName(func->name(), i))
return r.fail("duplicate function");
}
if (module->maybeTable()) {
- for (WasmRef& ref : module->maybeTable()->elems()) {
+ for (AstRef& ref : module->maybeTable()->elems()) {
if (!r.resolveFunction(ref))
return false;
}
}
size_t numImports = module->imports().length();
for (size_t i = 0; i < numImports; i++) {
- WasmAstImport* imp = module->imports()[i];
+ AstImport* imp = module->imports()[i];
if (!r.registerImportName(imp->name(), i))
return r.fail("duplicate import");
}
- for (WasmAstExport* export_ : module->exports()) {
- if (export_->kind() != WasmAstExportKind::Func)
+ for (AstExport* export_ : module->exports()) {
+ if (export_->kind() != AstExportKind::Func)
continue;
if (!r.resolveFunction(export_->func()))
return false;
}
- for (WasmAstFunc* func : module->funcs()) {
+ for (AstFunc* func : module->funcs()) {
if (!ResolveFunc(r, *func))
return false;
}
return true;
}
/*****************************************************************************/
// wasm function body serialization
static bool
-EncodeExpr(Encoder& e, WasmAstExpr& expr);
+EncodeExpr(Encoder& e, AstExpr& expr);
static bool
-EncodeBlock(Encoder& e, WasmAstBlock& b)
+EncodeBlock(Encoder& e, AstBlock& b)
{
if (!e.writeExpr(b.expr()))
return false;
size_t numExprs = b.exprs().length();
for (size_t i = 0; i < numExprs; i++) {
if (!EncodeExpr(e, *b.exprs()[i]))
@@ -3685,17 +2956,17 @@ EncodeBlock(Encoder& e, WasmAstBlock& b)
if (!e.writeExpr(Expr::End))
return false;
return true;
}
static bool
-EncodeBranch(Encoder& e, WasmAstBranch& br)
+EncodeBranch(Encoder& e, AstBranch& br)
{
MOZ_ASSERT(br.expr() == Expr::Br || br.expr() == Expr::BrIf);
uint32_t arity = 0;
if (br.maybeValue()) {
arity = 1;
if (!EncodeExpr(e, *br.maybeValue()))
return false;
@@ -3714,28 +2985,28 @@ EncodeBranch(Encoder& e, WasmAstBranch&
if (!e.writeVarU32(br.target().index()))
return false;
return true;
}
static bool
-EncodeArgs(Encoder& e, const WasmAstExprVector& args)
+EncodeArgs(Encoder& e, const AstExprVector& args)
{
- for (WasmAstExpr* arg : args) {
+ for (AstExpr* arg : args) {
if (!EncodeExpr(e, *arg))
return false;
}
return true;
}
static bool
-EncodeCall(Encoder& e, WasmAstCall& c)
+EncodeCall(Encoder& e, AstCall& c)
{
if (!EncodeArgs(e, c.args()))
return false;
if (!e.writeExpr(c.expr()))
return false;
if (!e.writeVarU32(c.args().length()))
@@ -3743,17 +3014,17 @@ EncodeCall(Encoder& e, WasmAstCall& c)
if (!e.writeVarU32(c.func().index()))
return false;
return true;
}
static bool
-EncodeCallIndirect(Encoder& e, WasmAstCallIndirect& c)
+EncodeCallIndirect(Encoder& e, AstCallIndirect& c)
{
if (!EncodeExpr(e, *c.index()))
return false;
if (!EncodeArgs(e, c.args()))
return false;
if (!e.writeExpr(Expr::CallIndirect))
@@ -3764,17 +3035,17 @@ EncodeCallIndirect(Encoder& e, WasmAstCa
if (!e.writeVarU32(c.sig().index()))
return false;
return true;
}
static bool
-EncodeConst(Encoder& e, WasmAstConst& c)
+EncodeConst(Encoder& e, AstConst& c)
{
switch (c.val().type()) {
case ValType::I32:
return e.writeExpr(Expr::I32Const) &&
e.writeVarS32(c.val().i32());
case ValType::I64:
return e.writeExpr(Expr::I64Const) &&
e.writeVarS64(c.val().i64());
@@ -3786,113 +3057,113 @@ EncodeConst(Encoder& e, WasmAstConst& c)
e.writeFixedF64(c.val().f64());
default:
break;
}
MOZ_CRASH("Bad value type");
}
static bool
-EncodeGetLocal(Encoder& e, WasmAstGetLocal& gl)
+EncodeGetLocal(Encoder& e, AstGetLocal& gl)
{
return e.writeExpr(Expr::GetLocal) &&
e.writeVarU32(gl.local().index());
}
static bool
-EncodeSetLocal(Encoder& e, WasmAstSetLocal& sl)
+EncodeSetLocal(Encoder& e, AstSetLocal& sl)
{
return EncodeExpr(e, sl.value()) &&
e.writeExpr(Expr::SetLocal) &&
e.writeVarU32(sl.local().index());
}
static bool
-EncodeUnaryOperator(Encoder& e, WasmAstUnaryOperator& b)
+EncodeUnaryOperator(Encoder& e, AstUnaryOperator& b)
{
return EncodeExpr(e, *b.op()) &&
e.writeExpr(b.expr());
}
static bool
-EncodeBinaryOperator(Encoder& e, WasmAstBinaryOperator& b)
+EncodeBinaryOperator(Encoder& e, AstBinaryOperator& b)
{
return EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs()) &&
e.writeExpr(b.expr());
}
static bool
-EncodeTernaryOperator(Encoder& e, WasmAstTernaryOperator& b)
+EncodeTernaryOperator(Encoder& e, AstTernaryOperator& b)
{
return EncodeExpr(e, *b.op0()) &&
EncodeExpr(e, *b.op1()) &&
EncodeExpr(e, *b.op2()) &&
e.writeExpr(b.expr());
}
static bool
-EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b)
+EncodeComparisonOperator(Encoder& e, AstComparisonOperator& b)
{
return EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs()) &&
e.writeExpr(b.expr());
}
static bool
-EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
+EncodeConversionOperator(Encoder& e, AstConversionOperator& b)
{
return EncodeExpr(e, *b.op()) &&
e.writeExpr(b.expr());
}
static bool
-EmitIf(Encoder& e, WasmAstIf& i)
+EmitIf(Encoder& e, AstIf& i)
{
return EncodeExpr(e, i.cond()) &&
e.writeExpr(Expr::If) &&
EncodeExpr(e, i.thenBranch()) &&
(!i.hasElse() ||
(e.writeExpr(Expr::Else) &&
EncodeExpr(e, i.elseBranch()))) &&
e.writeExpr(Expr::End);
}
static bool
-EncodeLoadStoreAddress(Encoder &e, const WasmAstLoadStoreAddress &address)
+EncodeLoadStoreAddress(Encoder &e, const AstLoadStoreAddress &address)
{
return EncodeExpr(e, address.base());
}
static bool
-EncodeLoadStoreFlags(Encoder &e, const WasmAstLoadStoreAddress &address)
+EncodeLoadStoreFlags(Encoder &e, const AstLoadStoreAddress &address)
{
return e.writeVarU32(address.flags()) &&
e.writeVarU32(address.offset());
}
static bool
-EncodeLoad(Encoder& e, WasmAstLoad& l)
+EncodeLoad(Encoder& e, AstLoad& l)
{
return EncodeLoadStoreAddress(e, l.address()) &&
e.writeExpr(l.expr()) &&
EncodeLoadStoreFlags(e, l.address());
}
static bool
-EncodeStore(Encoder& e, WasmAstStore& s)
+EncodeStore(Encoder& e, AstStore& s)
{
return EncodeLoadStoreAddress(e, s.address()) &&
EncodeExpr(e, s.value()) &&
e.writeExpr(s.expr()) &&
EncodeLoadStoreFlags(e, s.address());
}
static bool
-EncodeReturn(Encoder& e, WasmAstReturn& r)
+EncodeReturn(Encoder& e, AstReturn& r)
{
uint32_t arity = 0;
if (r.maybeExpr()) {
arity = 1;
if (!EncodeExpr(e, *r.maybeExpr()))
return false;
}
@@ -3901,17 +3172,17 @@ EncodeReturn(Encoder& e, WasmAstReturn&
if (!e.writeVarU32(arity))
return false;
return true;
}
static bool
-EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt)
+EncodeBranchTable(Encoder& e, AstBranchTable& bt)
{
uint32_t arity = 0;
if (bt.maybeValue()) {
arity = 1;
if (!EncodeExpr(e, *bt.maybeValue()))
return false;
}
@@ -3922,90 +3193,90 @@ EncodeBranchTable(Encoder& e, WasmAstBra
return false;
if (!e.writeVarU32(arity))
return false;
if (!e.writeVarU32(bt.table().length()))
return false;
- for (const WasmRef& elem : bt.table()) {
+ for (const AstRef& elem : bt.table()) {
if (!e.writeFixedU32(elem.index()))
return false;
}
if (!e.writeFixedU32(bt.def().index()))
return false;
return true;
}
static bool
-EncodeExpr(Encoder& e, WasmAstExpr& expr)
+EncodeExpr(Encoder& e, AstExpr& expr)
{
switch (expr.kind()) {
- case WasmAstExprKind::Nop:
+ case AstExprKind::Nop:
return e.writeExpr(Expr::Nop);
- case WasmAstExprKind::Unreachable:
+ case AstExprKind::Unreachable:
return e.writeExpr(Expr::Unreachable);
- case WasmAstExprKind::BinaryOperator:
- return EncodeBinaryOperator(e, expr.as<WasmAstBinaryOperator>());
- case WasmAstExprKind::Block:
- return EncodeBlock(e, expr.as<WasmAstBlock>());
- case WasmAstExprKind::Branch:
- return EncodeBranch(e, expr.as<WasmAstBranch>());
- case WasmAstExprKind::Call:
- return EncodeCall(e, expr.as<WasmAstCall>());
- case WasmAstExprKind::CallIndirect:
- return EncodeCallIndirect(e, expr.as<WasmAstCallIndirect>());
- case WasmAstExprKind::ComparisonOperator:
- return EncodeComparisonOperator(e, expr.as<WasmAstComparisonOperator>());
- case WasmAstExprKind::Const:
- return EncodeConst(e, expr.as<WasmAstConst>());
- case WasmAstExprKind::ConversionOperator:
- return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
- case WasmAstExprKind::GetLocal:
- return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
- case WasmAstExprKind::If:
- return EmitIf(e, expr.as<WasmAstIf>());
- case WasmAstExprKind::Load:
- return EncodeLoad(e, expr.as<WasmAstLoad>());
- case WasmAstExprKind::Return:
- return EncodeReturn(e, expr.as<WasmAstReturn>());
- case WasmAstExprKind::SetLocal:
- return EncodeSetLocal(e, expr.as<WasmAstSetLocal>());
- case WasmAstExprKind::Store:
- return EncodeStore(e, expr.as<WasmAstStore>());
- case WasmAstExprKind::BranchTable:
- return EncodeBranchTable(e, expr.as<WasmAstBranchTable>());
- case WasmAstExprKind::TernaryOperator:
- return EncodeTernaryOperator(e, expr.as<WasmAstTernaryOperator>());
- case WasmAstExprKind::UnaryOperator:
- return EncodeUnaryOperator(e, expr.as<WasmAstUnaryOperator>());
+ case AstExprKind::BinaryOperator:
+ return EncodeBinaryOperator(e, expr.as<AstBinaryOperator>());
+ case AstExprKind::Block:
+ return EncodeBlock(e, expr.as<AstBlock>());
+ case AstExprKind::Branch:
+ return EncodeBranch(e, expr.as<AstBranch>());
+ case AstExprKind::Call:
+ return EncodeCall(e, expr.as<AstCall>());
+ case AstExprKind::CallIndirect:
+ return EncodeCallIndirect(e, expr.as<AstCallIndirect>());
+ case AstExprKind::ComparisonOperator:
+ return EncodeComparisonOperator(e, expr.as<AstComparisonOperator>());
+ case AstExprKind::Const:
+ return EncodeConst(e, expr.as<AstConst>());
+ case AstExprKind::ConversionOperator:
+ return EncodeConversionOperator(e, expr.as<AstConversionOperator>());
+ case AstExprKind::GetLocal:
+ return EncodeGetLocal(e, expr.as<AstGetLocal>());
+ case AstExprKind::If:
+ return EmitIf(e, expr.as<AstIf>());
+ case AstExprKind::Load:
+ return EncodeLoad(e, expr.as<AstLoad>());
+ case AstExprKind::Return:
+ return EncodeReturn(e, expr.as<AstReturn>());
+ case AstExprKind::SetLocal:
+ return EncodeSetLocal(e, expr.as<AstSetLocal>());
+ case AstExprKind::Store:
+ return EncodeStore(e, expr.as<AstStore>());
+ case AstExprKind::BranchTable:
+ return EncodeBranchTable(e, expr.as<AstBranchTable>());
+ case AstExprKind::TernaryOperator:
+ return EncodeTernaryOperator(e, expr.as<AstTernaryOperator>());
+ case AstExprKind::UnaryOperator:
+ return EncodeUnaryOperator(e, expr.as<AstUnaryOperator>());
}
MOZ_CRASH("Bad expr kind");
}
/*****************************************************************************/
// wasm AST binary serialization
static bool
-EncodeTypeSection(Encoder& e, WasmAstModule& module)
+EncodeTypeSection(Encoder& e, AstModule& module)
{
if (module.sigs().empty())
return true;
size_t offset;
if (!e.startSection(TypeSectionId, &offset))
return false;
if (!e.writeVarU32(module.sigs().length()))
return false;
- for (WasmAstSig* sig : module.sigs()) {
+ for (AstSig* sig : module.sigs()) {
if (!e.writeVarU32(uint32_t(TypeConstructor::Function)))
return false;
if (!e.writeVarU32(sig->args().length()))
return false;
for (ValType t : sig->args()) {
if (!e.writeValType(t))
@@ -4021,237 +3292,237 @@ EncodeTypeSection(Encoder& e, WasmAstMod
}
}
e.finishSection(offset);
return true;
}
static bool
-EncodeFunctionSection(Encoder& e, WasmAstModule& module)
+EncodeFunctionSection(Encoder& e, AstModule& module)
{
if (module.funcs().empty())
return true;
size_t offset;
if (!e.startSection(FunctionSectionId, &offset))
return false;
if (!e.writeVarU32(module.funcs().length()))
return false;
- for (WasmAstFunc* func : module.funcs()) {
+ for (AstFunc* func : module.funcs()) {
if (!e.writeVarU32(func->sig().index()))
return false;
}
e.finishSection(offset);
return true;
}
static bool
-EncodeBytes(Encoder& e, WasmName wasmName)
+EncodeBytes(Encoder& e, AstName wasmName)
{
TwoByteChars range(wasmName.begin(), wasmName.length());
UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, range).c_str());
return utf8 && e.writeBytes(utf8.get(), strlen(utf8.get()));
}
static bool
-EncodeImport(Encoder& e, WasmAstImport& imp)
+EncodeImport(Encoder& e, AstImport& imp)
{
if (!e.writeVarU32(imp.sigIndex()))
return false;
if (!EncodeBytes(e, imp.module()))
return false;
if (!EncodeBytes(e, imp.func()))
return false;
return true;
}
static bool
-EncodeImportSection(Encoder& e, WasmAstModule& module)
+EncodeImportSection(Encoder& e, AstModule& module)
{
if (module.imports().empty())
return true;
size_t offset;
if (!e.startSection(ImportSectionId, &offset))
return false;
if (!e.writeVarU32(module.imports().length()))
return false;
- for (WasmAstImport* imp : module.imports()) {
+ for (AstImport* imp : module.imports()) {
if (!EncodeImport(e, *imp))
return false;
}
e.finishSection(offset);
return true;
}
static bool
-EncodeMemorySection(Encoder& e, WasmAstModule& module)
+EncodeMemorySection(Encoder& e, AstModule& module)
{
if (!module.maybeMemory())
return true;
size_t offset;
if (!e.startSection(MemorySectionId, &offset))
return false;
- WasmAstMemory& memory = *module.maybeMemory();
+ AstMemory& memory = *module.maybeMemory();
if (!e.writeVarU32(memory.initialSize()))
return false;
uint32_t maxSize = memory.maxSize() ? *memory.maxSize() : memory.initialSize();
if (!e.writeVarU32(maxSize))
return false;
uint8_t exported = 0;
- for (WasmAstExport* exp : module.exports()) {
- if (exp->kind() == WasmAstExportKind::Memory) {
+ for (AstExport* exp : module.exports()) {
+ if (exp->kind() == AstExportKind::Memory) {
exported = 1;
break;
}
}
if (!e.writeFixedU8(exported))
return false;
e.finishSection(offset);
return true;
}
static bool
-EncodeFunctionExport(Encoder& e, WasmAstExport& exp)
+EncodeFunctionExport(Encoder& e, AstExport& exp)
{
if (!e.writeVarU32(exp.func().index()))
return false;
if (!EncodeBytes(e, exp.name()))
return false;
return true;
}
static bool
-EncodeExportSection(Encoder& e, WasmAstModule& module)
+EncodeExportSection(Encoder& e, AstModule& module)
{
uint32_t numFuncExports = 0;
- for (WasmAstExport* exp : module.exports()) {
- if (exp->kind() == WasmAstExportKind::Func)
+ for (AstExport* exp : module.exports()) {
+ if (exp->kind() == AstExportKind::Func)
numFuncExports++;
}
if (!numFuncExports)
return true;
size_t offset;
if (!e.startSection(ExportSectionId, &offset))
return false;
if (!e.writeVarU32(numFuncExports))
return false;
- for (WasmAstExport* exp : module.exports()) {
+ for (AstExport* exp : module.exports()) {
switch (exp->kind()) {
- case WasmAstExportKind::Func:
+ case AstExportKind::Func:
if (!EncodeFunctionExport(e, *exp))
return false;
break;
- case WasmAstExportKind::Memory:
+ case AstExportKind::Memory:
continue;
}
}
e.finishSection(offset);
return true;
}
static bool
-EncodeTableSection(Encoder& e, WasmAstModule& module)
+EncodeTableSection(Encoder& e, AstModule& module)
{
if (!module.maybeTable())
return true;
size_t offset;
if (!e.startSection(TableSectionId, &offset))
return false;
if (!e.writeVarU32(module.maybeTable()->elems().length()))
return false;
- for (WasmRef& ref : module.maybeTable()->elems()) {
+ for (AstRef& ref : module.maybeTable()->elems()) {
if (!e.writeVarU32(ref.index()))
return false;
}
e.finishSection(offset);
return true;
}
static bool
-EncodeFunctionBody(Encoder& e, WasmAstFunc& func)
+EncodeFunctionBody(Encoder& e, AstFunc& func)
{
size_t bodySizeAt;
if (!e.writePatchableVarU32(&bodySizeAt))
return false;
size_t beforeBody = e.currentOffset();
ValTypeVector varTypes;
if (!varTypes.appendAll(func.vars()))
return false;
if (!EncodeLocalEntries(e, varTypes))
return false;
- for (WasmAstExpr* expr : func.body()) {
+ for (AstExpr* expr : func.body()) {
if (!EncodeExpr(e, *expr))
return false;
}
e.patchVarU32(bodySizeAt, e.currentOffset() - beforeBody);
return true;
}
static bool
-EncodeCodeSection(Encoder& e, WasmAstModule& module)
+EncodeCodeSection(Encoder& e, AstModule& module)
{
if (module.funcs().empty())
return true;
size_t offset;
if (!e.startSection(CodeSectionId, &offset))
return false;
if (!e.writeVarU32(module.funcs().length()))
return false;
- for (WasmAstFunc* func : module.funcs()) {
+ for (AstFunc* func : module.funcs()) {
if (!EncodeFunctionBody(e, *func))
return false;
}
e.finishSection(offset);
return true;
}
static bool
-EncodeDataSegment(Encoder& e, WasmAstSegment& segment)
+EncodeDataSegment(Encoder& e, AstSegment& segment)
{
if (!e.writeVarU32(segment.offset()))
return false;
- WasmName text = segment.text();
+ AstName text = segment.text();
Vector<uint8_t, 0, SystemAllocPolicy> bytes;
if (!bytes.reserve(text.length()))
return false;
const char16_t* cur = text.begin();
const char16_t* end = text.end();
while (cur != end) {
@@ -4262,41 +3533,41 @@ EncodeDataSegment(Encoder& e, WasmAstSeg
if (!e.writeBytes(bytes.begin(), bytes.length()))
return false;
return true;
}
static bool
-EncodeDataSection(Encoder& e, WasmAstModule& module)
+EncodeDataSection(Encoder& e, AstModule& module)
{
if (!module.maybeMemory() || module.maybeMemory()->segments().empty())
return true;
- const WasmAstSegmentVector& segments = module.maybeMemory()->segments();
+ const AstSegmentVector& segments = module.maybeMemory()->segments();
size_t offset;
if (!e.startSection(DataSectionId, &offset))
return false;
if (!e.writeVarU32(segments.length()))
return false;
- for (WasmAstSegment* segment : segments) {
+ for (AstSegment* segment : segments) {
if (!EncodeDataSegment(e, *segment))
return false;
}
e.finishSection(offset);
return true;
}
static bool
-EncodeModule(WasmAstModule& module, Bytes* bytes)
+EncodeModule(AstModule& module, Bytes* bytes)
{
Encoder e(*bytes);
if (!e.writeFixedU32(MagicNumber))
return false;
if (!e.writeFixedU32(EncodingVersion))
return false;
@@ -4329,17 +3600,17 @@ EncodeModule(WasmAstModule& module, Byte
}
/*****************************************************************************/
bool
wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
{
LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
- WasmAstModule* module = ParseModule(text, lifo, error);
+ AstModule* module = ParseModule(text, lifo, error);
if (!module)
return false;
if (!ResolveModule(lifo, module, error))
return false;
return EncodeModule(*module, bytes);
}
--- a/js/src/jit-test/tests/wasm/totext1.js
+++ b/js/src/jit-test/tests/wasm/totext1.js
@@ -1,14 +1,11 @@
if (!wasmIsSupported())
quit();
-// FIXME: Enable this test once binary-to-text is implemented again.
-quit();
-
load(libdir + "asserts.js");
var caught = false;
try {
wasmBinaryToText(new Int8Array(1));
} catch (e) {
caught = true;
}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -152,16 +152,17 @@ EXPORTS.js += [
'../public/WeakMapPtr.h',
]
UNIFIED_SOURCES += [
'asmjs/AsmJS.cpp',
'asmjs/Wasm.cpp',
'asmjs/WasmBinary.cpp',
'asmjs/WasmBinaryIterator.cpp',
+ 'asmjs/WasmBinaryToAST.cpp',
'asmjs/WasmBinaryToText.cpp',
'asmjs/WasmFrameIterator.cpp',
'asmjs/WasmGenerator.cpp',
'asmjs/WasmIonCompile.cpp',
'asmjs/WasmModule.cpp',
'asmjs/WasmSignalHandlers.cpp',
'asmjs/WasmStubs.cpp',
'asmjs/WasmTextToBinary.cpp',