diff options
Diffstat (limited to 'js/src/wasm/WasmAST.h')
-rw-r--r-- | js/src/wasm/WasmAST.h | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/js/src/wasm/WasmAST.h b/js/src/wasm/WasmAST.h new file mode 100644 index 000000000..d442fa19a --- /dev/null +++ b/js/src/wasm/WasmAST.h @@ -0,0 +1,1038 @@ +/* -*- 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 "ds/LifoAlloc.h" +#include "js/HashTable.h" +#include "js/Vector.h" +#include "wasm/WasmTypes.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: + template <size_t Length> + explicit AstName(const char16_t (&str)[Length]) : begin_(str), end_(str + Length - 1) { + MOZ_ASSERT(str[Length - 1] == u'\0'); + } + + 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()); + } + explicit AstRef(AstName name) : name_(name), index_(AstNoIndex) { + MOZ_ASSERT(!isInvalid()); + } + explicit AstRef(uint32_t index) : index_(index) { + 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_) + {} + 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; + } +}; + +const uint32_t AstNodeUnknownOffset = 0; + +class AstNode : public AstBase +{ + uint32_t offset_; // if applicable, offset in the binary format file + + public: + AstNode() : offset_(AstNodeUnknownOffset) {} + + uint32_t offset() const { return offset_; } + void setOffset(uint32_t offset) { offset_ = offset; } +}; + +enum class AstExprKind +{ + BinaryOperator, + Block, + Branch, + BranchTable, + Call, + CallIndirect, + ComparisonOperator, + Const, + ConversionOperator, + CurrentMemory, + Drop, + First, + GetGlobal, + GetLocal, + GrowMemory, + If, + Load, + Nop, + Pop, + Return, + SetGlobal, + SetLocal, + TeeLocal, + Store, + TernaryOperator, + UnaryOperator, + Unreachable +}; + +class AstExpr : public AstNode +{ + const AstExprKind kind_; + ExprType type_; + + protected: + AstExpr(AstExprKind kind, ExprType type) + : kind_(kind), type_(type) + {} + + public: + AstExprKind kind() const { return kind_; } + + bool isVoid() const { return IsVoid(type_); } + + // Note that for nodes other than blocks and block-like things, this + // may return ExprType::Limit for nodes with non-void types. + ExprType type() const { return type_; } + + 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, ExprType::Void) + {} +}; + +struct AstUnreachable : AstExpr +{ + static const AstExprKind Kind = AstExprKind::Unreachable; + AstUnreachable() + : AstExpr(AstExprKind::Unreachable, ExprType::Void) + {} +}; + +class AstDrop : public AstExpr +{ + AstExpr& value_; + + public: + static const AstExprKind Kind = AstExprKind::Drop; + explicit AstDrop(AstExpr& value) + : AstExpr(AstExprKind::Drop, ExprType::Void), + value_(value) + {} + AstExpr& value() const { + return value_; + } +}; + +class AstConst : public AstExpr +{ + const Val val_; + + public: + static const AstExprKind Kind = AstExprKind::Const; + explicit AstConst(Val val) + : AstExpr(Kind, ExprType::Limit), + 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, ExprType::Limit), + 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, ExprType::Void), + local_(local), + value_(value) + {} + AstRef& local() { + return local_; + } + AstExpr& value() const { + return value_; + } +}; + +class AstGetGlobal : public AstExpr +{ + AstRef global_; + + public: + static const AstExprKind Kind = AstExprKind::GetGlobal; + explicit AstGetGlobal(AstRef global) + : AstExpr(Kind, ExprType::Limit), + global_(global) + {} + AstRef& global() { + return global_; + } +}; + +class AstSetGlobal : public AstExpr +{ + AstRef global_; + AstExpr& value_; + + public: + static const AstExprKind Kind = AstExprKind::SetGlobal; + AstSetGlobal(AstRef global, AstExpr& value) + : AstExpr(Kind, ExprType::Void), + global_(global), + value_(value) + {} + AstRef& global() { + return global_; + } + AstExpr& value() const { + return value_; + } +}; + +class AstTeeLocal : public AstExpr +{ + AstRef local_; + AstExpr& value_; + + public: + static const AstExprKind Kind = AstExprKind::TeeLocal; + AstTeeLocal(AstRef local, AstExpr& value) + : AstExpr(Kind, ExprType::Limit), + local_(local), + value_(value) + {} + AstRef& local() { + return local_; + } + AstExpr& value() const { + return value_; + } +}; + +class AstBlock : public AstExpr +{ + Op op_; + AstName name_; + AstExprVector exprs_; + + public: + static const AstExprKind Kind = AstExprKind::Block; + explicit AstBlock(Op op, ExprType type, AstName name, AstExprVector&& exprs) + : AstExpr(Kind, type), + op_(op), + name_(name), + exprs_(Move(exprs)) + {} + + Op op() const { return op_; } + AstName name() const { return name_; } + const AstExprVector& exprs() const { return exprs_; } +}; + +class AstBranch : public AstExpr +{ + Op op_; + AstExpr* cond_; + AstRef target_; + AstExpr* value_; + + public: + static const AstExprKind Kind = AstExprKind::Branch; + explicit AstBranch(Op op, ExprType type, + AstExpr* cond, AstRef target, AstExpr* value) + : AstExpr(Kind, type), + op_(op), + cond_(cond), + target_(target), + value_(value) + {} + + Op op() const { return op_; } + AstRef& target() { return target_; } + AstExpr& cond() const { MOZ_ASSERT(cond_); return *cond_; } + AstExpr* maybeValue() const { return value_; } +}; + +class AstCall : public AstExpr +{ + Op op_; + AstRef func_; + AstExprVector args_; + + public: + static const AstExprKind Kind = AstExprKind::Call; + AstCall(Op op, ExprType type, AstRef func, AstExprVector&& args) + : AstExpr(Kind, type), op_(op), func_(func), args_(Move(args)) + {} + + Op op() const { return op_; } + AstRef& func() { return func_; } + const AstExprVector& args() const { return args_; } +}; + +class AstCallIndirect : public AstExpr +{ + AstRef sig_; + AstExprVector args_; + AstExpr* index_; + + public: + static const AstExprKind Kind = AstExprKind::CallIndirect; + AstCallIndirect(AstRef sig, ExprType type, AstExprVector&& args, AstExpr* index) + : AstExpr(Kind, type), sig_(sig), args_(Move(args)), index_(index) + {} + AstRef& sig() { return sig_; } + const AstExprVector& args() const { return args_; } + AstExpr* index() const { return index_; } +}; + +class AstReturn : public AstExpr +{ + AstExpr* maybeExpr_; + + public: + static const AstExprKind Kind = AstExprKind::Return; + explicit AstReturn(AstExpr* maybeExpr) + : AstExpr(Kind, ExprType::Void), + maybeExpr_(maybeExpr) + {} + AstExpr* maybeExpr() const { return maybeExpr_; } +}; + +class AstIf : public AstExpr +{ + AstExpr* cond_; + AstName name_; + AstExprVector thenExprs_; + AstExprVector elseExprs_; + + public: + static const AstExprKind Kind = AstExprKind::If; + AstIf(ExprType type, AstExpr* cond, AstName name, + AstExprVector&& thenExprs, AstExprVector&& elseExprs) + : AstExpr(Kind, type), + cond_(cond), + name_(name), + thenExprs_(Move(thenExprs)), + elseExprs_(Move(elseExprs)) + {} + + AstExpr& cond() const { return *cond_; } + const AstExprVector& thenExprs() const { return thenExprs_; } + bool hasElse() const { return elseExprs_.length(); } + const AstExprVector& elseExprs() const { MOZ_ASSERT(hasElse()); return elseExprs_; } + AstName name() const { return name_; } +}; + +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 +{ + Op op_; + AstLoadStoreAddress address_; + + public: + static const AstExprKind Kind = AstExprKind::Load; + explicit AstLoad(Op op, const AstLoadStoreAddress &address) + : AstExpr(Kind, ExprType::Limit), + op_(op), + address_(address) + {} + + Op op() const { return op_; } + const AstLoadStoreAddress& address() const { return address_; } +}; + +class AstStore : public AstExpr +{ + Op op_; + AstLoadStoreAddress address_; + AstExpr* value_; + + public: + static const AstExprKind Kind = AstExprKind::Store; + explicit AstStore(Op op, const AstLoadStoreAddress &address, AstExpr* value) + : AstExpr(Kind, ExprType::Void), + op_(op), + address_(address), + value_(value) + {} + + Op op() const { return op_; } + const AstLoadStoreAddress& address() const { return address_; } + AstExpr& value() const { return *value_; } +}; + +class AstCurrentMemory final : public AstExpr +{ + public: + static const AstExprKind Kind = AstExprKind::CurrentMemory; + explicit AstCurrentMemory() + : AstExpr(Kind, ExprType::I32) + {} +}; + +class AstGrowMemory final : public AstExpr +{ + AstExpr* operand_; + + public: + static const AstExprKind Kind = AstExprKind::GrowMemory; + explicit AstGrowMemory(AstExpr* operand) + : AstExpr(Kind, ExprType::I32), operand_(operand) + {} + + AstExpr* operand() const { return operand_; } +}; + +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, ExprType::Void), + 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 AstGlobal : public AstNode +{ + AstName name_; + bool isMutable_; + ValType type_; + Maybe<AstExpr*> init_; + + public: + AstGlobal() : isMutable_(false), type_(ValType(TypeCode::Limit)) + {} + + explicit AstGlobal(AstName name, ValType type, bool isMutable, + Maybe<AstExpr*> init = Maybe<AstExpr*>()) + : name_(name), isMutable_(isMutable), type_(type), init_(init) + {} + + AstName name() const { return name_; } + bool isMutable() const { return isMutable_; } + ValType type() const { return type_; } + + bool hasInit() const { return !!init_; } + AstExpr& init() const { MOZ_ASSERT(hasInit()); return **init_; } +}; + +typedef AstVector<AstGlobal*> AstGlobalVector; + +class AstImport : public AstNode +{ + AstName name_; + AstName module_; + AstName field_; + DefinitionKind kind_; + + AstRef funcSig_; + Limits limits_; + AstGlobal global_; + + public: + AstImport(AstName name, AstName module, AstName field, AstRef funcSig) + : name_(name), module_(module), field_(field), kind_(DefinitionKind::Function), funcSig_(funcSig) + {} + AstImport(AstName name, AstName module, AstName field, DefinitionKind kind, Limits limits) + : name_(name), module_(module), field_(field), kind_(kind), limits_(limits) + {} + AstImport(AstName name, AstName module, AstName field, AstGlobal global) + : name_(name), module_(module), field_(field), kind_(DefinitionKind::Global), global_(global) + {} + + AstName name() const { return name_; } + AstName module() const { return module_; } + AstName field() const { return field_; } + + DefinitionKind kind() const { return kind_; } + AstRef& funcSig() { + MOZ_ASSERT(kind_ == DefinitionKind::Function); + return funcSig_; + } + Limits limits() const { + MOZ_ASSERT(kind_ == DefinitionKind::Memory || kind_ == DefinitionKind::Table); + return limits_; + } + const AstGlobal& global() const { + MOZ_ASSERT(kind_ == DefinitionKind::Global); + return global_; + } +}; + +class AstExport : public AstNode +{ + AstName name_; + DefinitionKind kind_; + AstRef ref_; + + public: + AstExport(AstName name, DefinitionKind kind, AstRef ref) + : name_(name), kind_(kind), ref_(ref) + {} + explicit AstExport(AstName name, DefinitionKind kind) + : name_(name), kind_(kind) + {} + AstName name() const { return name_; } + DefinitionKind kind() const { return kind_; } + AstRef& ref() { return ref_; } +}; + +class AstDataSegment : public AstNode +{ + AstExpr* offset_; + AstNameVector fragments_; + + public: + AstDataSegment(AstExpr* offset, AstNameVector&& fragments) + : offset_(offset), fragments_(Move(fragments)) + {} + + AstExpr* offset() const { return offset_; } + const AstNameVector& fragments() const { return fragments_; } +}; + +typedef AstVector<AstDataSegment*> AstDataSegmentVector; + +class AstElemSegment : public AstNode +{ + AstExpr* offset_; + AstRefVector elems_; + + public: + AstElemSegment(AstExpr* offset, AstRefVector&& elems) + : offset_(offset), elems_(Move(elems)) + {} + + AstExpr* offset() const { return offset_; } + AstRefVector& elems() { return elems_; } + const AstRefVector& elems() const { return elems_; } +}; + +typedef AstVector<AstElemSegment*> AstElemSegmentVector; + +class AstStartFunc : public AstNode +{ + AstRef func_; + + public: + explicit AstStartFunc(AstRef func) + : func_(func) + {} + + AstRef& func() { + return func_; + } +}; + +struct AstResizable +{ + AstName name; + Limits limits; + bool imported; + + AstResizable(Limits limits, bool imported, AstName name = AstName()) + : name(name), + limits(limits), + imported(imported) + {} +}; + +class AstModule : public AstNode +{ + public: + typedef AstVector<AstFunc*> FuncVector; + typedef AstVector<AstImport*> ImportVector; + typedef AstVector<AstExport*> ExportVector; + typedef AstVector<AstSig*> SigVector; + typedef AstVector<AstName> NameVector; + typedef AstVector<AstResizable> AstResizableVector; + + private: + typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap; + + LifoAlloc& lifo_; + SigVector sigs_; + SigMap sigMap_; + ImportVector imports_; + NameVector funcImportNames_; + AstResizableVector tables_; + AstResizableVector memories_; + ExportVector exports_; + Maybe<AstStartFunc> startFunc_; + FuncVector funcs_; + AstDataSegmentVector dataSegments_; + AstElemSegmentVector elemSegments_; + AstGlobalVector globals_; + + public: + explicit AstModule(LifoAlloc& lifo) + : lifo_(lifo), + sigs_(lifo), + sigMap_(lifo), + imports_(lifo), + funcImportNames_(lifo), + tables_(lifo), + memories_(lifo), + exports_(lifo), + funcs_(lifo), + dataSegments_(lifo), + elemSegments_(lifo), + globals_(lifo) + {} + bool init() { + return sigMap_.init(); + } + bool addMemory(AstName name, Limits memory) { + return memories_.append(AstResizable(memory, false, name)); + } + bool hasMemory() const { + return !!memories_.length(); + } + const AstResizableVector& memories() const { + return memories_; + } + bool addTable(AstName name, Limits table) { + return tables_.append(AstResizable(table, false, name)); + } + bool hasTable() const { + return !!tables_.length(); + } + const AstResizableVector& tables() const { + return tables_; + } + bool append(AstDataSegment* seg) { + return dataSegments_.append(seg); + } + const AstDataSegmentVector& dataSegments() const { + return dataSegments_; + } + bool append(AstElemSegment* seg) { + return elemSegments_.append(seg); + } + const AstElemSegmentVector& elemSegments() const { + return elemSegments_; + } + bool hasStartFunc() const { + return !!startFunc_; + } + bool setStartFunc(AstStartFunc startFunc) { + if (startFunc_) + return false; + startFunc_.emplace(startFunc); + return true; + } + AstStartFunc& startFunc() { + return *startFunc_; + } + 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_; + } + bool append(AstImport* imp) { + switch (imp->kind()) { + case DefinitionKind::Function: + if (!funcImportNames_.append(imp->name())) + return false; + break; + case DefinitionKind::Table: + if (!tables_.append(AstResizable(imp->limits(), true))) + return false; + break; + case DefinitionKind::Memory: + if (!memories_.append(AstResizable(imp->limits(), true))) + return false; + break; + case DefinitionKind::Global: + break; + } + + return imports_.append(imp); + } + const ImportVector& imports() const { + return imports_; + } + const NameVector& funcImportNames() const { + return funcImportNames_; + } + size_t numFuncImports() const { + return funcImportNames_.length(); + } + bool append(AstExport* exp) { + return exports_.append(exp); + } + const ExportVector& exports() const { + return exports_; + } + bool append(AstGlobal* glob) { + return globals_.append(glob); + } + const AstGlobalVector& globals() const { + return globals_; + } +}; + +class AstUnaryOperator final : public AstExpr +{ + Op op_; + AstExpr* operand_; + + public: + static const AstExprKind Kind = AstExprKind::UnaryOperator; + explicit AstUnaryOperator(Op op, AstExpr* operand) + : AstExpr(Kind, ExprType::Limit), + op_(op), operand_(operand) + {} + + Op op() const { return op_; } + AstExpr* operand() const { return operand_; } +}; + +class AstBinaryOperator final : public AstExpr +{ + Op op_; + AstExpr* lhs_; + AstExpr* rhs_; + + public: + static const AstExprKind Kind = AstExprKind::BinaryOperator; + explicit AstBinaryOperator(Op op, AstExpr* lhs, AstExpr* rhs) + : AstExpr(Kind, ExprType::Limit), + op_(op), lhs_(lhs), rhs_(rhs) + {} + + Op op() const { return op_; } + AstExpr* lhs() const { return lhs_; } + AstExpr* rhs() const { return rhs_; } +}; + +class AstTernaryOperator : public AstExpr +{ + Op op_; + AstExpr* op0_; + AstExpr* op1_; + AstExpr* op2_; + + public: + static const AstExprKind Kind = AstExprKind::TernaryOperator; + AstTernaryOperator(Op op, AstExpr* op0, AstExpr* op1, AstExpr* op2) + : AstExpr(Kind, ExprType::Limit), + op_(op), op0_(op0), op1_(op1), op2_(op2) + {} + + Op op() const { return op_; } + AstExpr* op0() const { return op0_; } + AstExpr* op1() const { return op1_; } + AstExpr* op2() const { return op2_; } +}; + +class AstComparisonOperator final : public AstExpr +{ + Op op_; + AstExpr* lhs_; + AstExpr* rhs_; + + public: + static const AstExprKind Kind = AstExprKind::ComparisonOperator; + explicit AstComparisonOperator(Op op, AstExpr* lhs, AstExpr* rhs) + : AstExpr(Kind, ExprType::Limit), + op_(op), lhs_(lhs), rhs_(rhs) + {} + + Op op() const { return op_; } + AstExpr* lhs() const { return lhs_; } + AstExpr* rhs() const { return rhs_; } +}; + +class AstConversionOperator final : public AstExpr +{ + Op op_; + AstExpr* operand_; + + public: + static const AstExprKind Kind = AstExprKind::ConversionOperator; + explicit AstConversionOperator(Op op, AstExpr* operand) + : AstExpr(Kind, ExprType::Limit), + op_(op), operand_(operand) + {} + + Op op() const { return op_; } + AstExpr* operand() const { return operand_; } +}; + +// This is an artificial AST node which can fill operand slots in an AST +// constructed from parsing or decoding stack-machine code that doesn't have +// an inherent AST structure. +class AstPop final : public AstExpr +{ + public: + static const AstExprKind Kind = AstExprKind::Pop; + AstPop() + : AstExpr(Kind, ExprType::Void) + {} +}; + +// This is an artificial AST node which can be used to represent some forms +// of stack-machine code in an AST form. It is similar to Block, but returns the +// value of its first operand, rather than the last. +class AstFirst : public AstExpr +{ + AstExprVector exprs_; + + public: + static const AstExprKind Kind = AstExprKind::First; + explicit AstFirst(AstExprVector&& exprs) + : AstExpr(Kind, ExprType::Limit), + exprs_(Move(exprs)) + {} + + AstExprVector& exprs() { return exprs_; } + const AstExprVector& exprs() const { return exprs_; } +}; + +} // end wasm namespace +} // end js namespace + +#endif // namespace wasmast_h |