blob: 2b2876a27b1df98c02f0512b09e72bfb58741396 [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_WASM_H_
#define RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_WASM_H_
#include "vm/compiler/backend/sexpression.h"
#include "vm/datastream.h"
namespace wasm {
void WasmTrace(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
// Forward declarations.
#define FOR_ALL_WASM_CONSTRUCTS(M) \
M(Type) \
M(ValueType) \
M(NumType) \
M(RefType) \
M(HeapType) \
M(Rtt) \
M(Field) \
M(FieldType) \
M(DefType) \
M(FuncType) \
M(StructType) \
M(ArrayType) \
M(Instruction) \
M(LocalGet) \
M(LocalSet) \
M(GlobalGet) \
M(IntOp) \
M(IntConstant) \
M(Int32WrapInt64) \
M(StructuredInstr) \
M(Block) \
M(Loop) \
M(If) \
M(Br) \
M(RttCanon) \
M(RttSub) \
M(StructGet) \
M(StructSet) \
M(StructNewWithRtt) \
M(Call) \
M(CallIndirect) \
M(Drop) \
M(Return) \
M(RefNull) \
M(RefEq) \
M(RefCast) \
M(Table) \
M(SingleElemSegment) \
M(Local) \
M(Global) \
M(InstructionList) \
M(Function) \
M(WasmModuleBuilder)
#define FORWARD_DECLARATION(type) class type;
FOR_ALL_WASM_CONSTRUCTS(FORWARD_DECLARATION)
#undef FORWARD_DECLARATION
// Note: all abstract types syntax is adapted from https://bit.ly/3cWcm6Q
// and https://github.com/WebAssembly/gc/blob/master/proposals/gc/MVP.md.
// Abstract base class for Wasm types representing a value.
// - Abstract syntax:
// value_type ::= <num_type> | <ref_type> | rtt <depth> <heap_type>
class ValueType : public dart::ZoneAllocated {
public:
virtual dart::SExpression* Serialize(dart::Zone* zone) = 0;
virtual void OutputBinary(dart::WriteStream* stream) = 0;
virtual ~ValueType() = default;
virtual RefType* AsRefType() { return nullptr; }
protected:
ValueType() {}
private:
DISALLOW_COPY_AND_ASSIGN(ValueType);
};
// Class for Wasm numeric types: integers and floting points.
// - Abstract syntax:
// num_type ::= i32 | i64 | f32 | f64 | v128
class NumType : public ValueType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
enum class Kind { kI32, kI64, kF32, kF64, kV128 };
NumType(Kind kind) : kind_(kind) {}
const Kind kind_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(NumType);
};
// Class for Wasm reference types.
// - Abstract syntax:
// ref_type ::= (ref null? <heap_type>)
// - Representation details:
// heap_type_ should not be nullptr.
// Observe that one can not define a reference to an unboxed, say, i32.
class RefType : public ValueType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
RefType* AsRefType() override { return this; }
HeapType* heap_type() const { return heap_type_; }
private:
RefType(bool nullable, HeapType* heap_type)
: nullable_(nullable), heap_type_(ASSERT_NOTNULL(heap_type)) {}
const bool nullable_;
HeapType* const heap_type_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RefType);
};
// Class for Wasm heap types.
// - Syntax:
// heap_type ::= func | extern | <typeidx> | any | eq | i31
// - Representation details:
// The six options are distinguished by the variable kind_.
// Either kind_ is kTypeidx, in which case def_type_ should point
// to an appropriate defined type, or kind_ is not kTypeidx, in
// which case def_type_ should be nullptr.
// Observe how typeids are not stored explicitly, but rather through
// the pointer def_type_ to the corresponding defined type.
class HeapType : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
private:
// Note: V8 doesn't support any/anyref yet.
// Reference: https://github.com/v8/v8/blob/master/src/wasm/wasm-constants.h
enum class Kind { kFunc, kExtern, kTypeidx, kAny, kEq, kI31 };
// Constructor for <typeidx> case of heap_type.
HeapType(DefType* def_type)
: kind_(Kind::kTypeidx), def_type_(ASSERT_NOTNULL(def_type)) {}
// Constructor for the other cases of heap_type.
HeapType(Kind kind) : kind_(kind), def_type_(nullptr) {
ASSERT(kind != Kind::kTypeidx);
}
const Kind kind_;
DefType* const def_type_;
friend class WasmModuleBuilder; // For private constructor.
friend class RefType; // For access to Kind and kind_.
DISALLOW_COPY_AND_ASSIGN(HeapType);
};
// Class for Wasm runtime types.
class Rtt : public ValueType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
intptr_t depth() const { return depth_; }
HeapType* heap_type() const { return heap_type_; }
private:
Rtt(intptr_t depth, HeapType* heap_type)
: depth_(depth), heap_type_(heap_type) {}
const intptr_t depth_;
HeapType* const heap_type_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Rtt);
};
// Class for a Wasm field of a struct type.
// It consists of a FieldType and an index of the field in the enclosing struct.
class Field : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
Field(const Field& field)
: struct_type_(field.struct_type_),
field_type_(field.field_type_),
index_(field.index_) {}
StructType* struct_type() const { return struct_type_; }
void set_struct_type_(StructType* struct_type) { struct_type_ = struct_type; }
uint32_t index() const { return index_; }
private:
Field(StructType* struct_type, FieldType* field_type, uint32_t index)
: struct_type_(struct_type), field_type_(field_type), index_(index) {}
StructType* struct_type_;
FieldType* const field_type_;
const uint32_t index_;
friend class StructType; // For private constructor.
};
// Class for Wasm field types. Fields are used inside both struct and
// array types. Esssentially, a combined <field_type> + <storage_type> +
// <packed_type> from the spec.
// - Abstract syntax:
// field_type ::= <storage_type> | (mut <storage_type>)
// storage_type ::= <value_type> | <packed_type>
// packed_type ::= i8 | i16
// - Representation details:
// mut_ represents whether the field is mutable or not.
// value_type_ and packed_type_ collectively represent the
// storage_type, as follows: either packed_type_ is kNoType
// and value_type_ is not nullptr, or packed_type_ is not
// kNoType and value_type_ is nullptr.
class FieldType : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
private:
enum class PackedType { kNoType, kI8, kI16 };
// Constructor for <value_type> case of storage_type.
FieldType(ValueType* value_type, bool mut)
: value_type_(ASSERT_NOTNULL(value_type)),
packed_type_(PackedType::kNoType),
mut_(mut) {}
// Constructor for <packed_type> case of storage_type.
FieldType(PackedType packed_type, bool mut)
: value_type_(nullptr), packed_type_(packed_type), mut_(mut) {
ASSERT(packed_type_ != PackedType::kNoType);
}
ValueType* const value_type_;
const PackedType packed_type_;
const bool mut_;
friend class WasmModuleBuilder; // For private constructor.
friend class StructType; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(FieldType);
};
// Class for Wasm defined types, which appear in the types section.
// - Abstract syntax:
// def_type = <func_type> | <struct_type> | <array_type>
// - Representation details:
// Each defined type stores in index_ its index in the types section.
class DefType : public dart::ZoneAllocated {
public:
virtual dart::SExpression* Serialize(dart::Zone* zone) = 0;
virtual void OutputBinary(dart::WriteStream* stream) = 0;
virtual ~DefType() = default;
uint32_t index() const { return index_; }
protected:
DefType(dart::Zone* zone, uint32_t index) : zone_(zone), index_(index) {}
dart::Zone* const zone_;
private:
// All defined types have an index in the module.
const uint32_t index_;
DISALLOW_COPY_AND_ASSIGN(DefType);
};
// Class for Wasm function types.
// Notably, parameters are not named.
class FuncType : public DefType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
void AddParam(ValueType* param_type);
void AddResult(ValueType* result_type);
intptr_t NumParams() const { return param_types_.length(); }
ValueType* ParamTypeAt(intptr_t index) {
ASSERT(0 <= index && index < NumParams());
return param_types_.At(index);
}
intptr_t NumResults() const { return result_types_.length(); }
ValueType* ResultTypeAt(intptr_t index) {
ASSERT(0 <= index && index < NumResults());
return result_types_.At(index);
}
private:
FuncType(dart::Zone* zone, int index);
dart::GrowableArray<ValueType*> param_types_;
dart::GrowableArray<ValueType*> result_types_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(FuncType);
};
// Class for Wasm struct types.
class StructType : public DefType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
// Copy fields of struct to a given destination struct. The enclosing
// struct of the copied fields is set to point to dest.
void CopyFieldsTo(StructType* dest);
Field* AddField(FieldType* field_type);
Field* AddField(ValueType* value_type, bool mut);
Field* AddField(FieldType::PackedType packed_type, bool mut);
dart::GrowableArray<Field*>& fields() { return fields_; }
private:
StructType(dart::Zone* zone, int index);
dart::GrowableArray<Field*> fields_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(StructType);
};
// Class for Wasm array types.
class ArrayType : public DefType {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
ArrayType(dart::Zone* zone, int index, FieldType* field_type)
: DefType(zone, index), field_type_(field_type) {}
FieldType* const field_type_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(ArrayType);
};
// Abstract base class for Wasm instructions.
class Instruction : public dart::ZoneAllocated {
public:
virtual dart::SExpression* Serialize(dart::Zone* zone) = 0;
virtual void OutputBinary(dart::WriteStream* stream) = 0;
virtual ~Instruction() = default;
protected:
Instruction() {}
private:
DISALLOW_COPY_AND_ASSIGN(Instruction);
};
// Wasm local.get instruction.
class LocalGet : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
LocalGet(Local* local) : local_(local) {}
Local* const local_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(LocalGet);
};
// Wasm local.set instruction.
class LocalSet : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
LocalSet(Local* local) : local_(local) {}
Local* const local_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(LocalSet);
};
// Wasm global.get instruction.
class GlobalGet : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
GlobalGet(Global* global) : global_(global) {}
Global* const global_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(GlobalGet);
};
// Wasm i{32/64} signed operations.
class IntOp : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
enum class IntegerKind { kI32, kI64 };
enum class OpKind {
kAdd, // +
kSub, // -
kMult, // *
kDiv, // ~/
kMod, // %
kAnd, // &
kOr, // |
kXor, // ^
kEq, // ==
kNeq, // !=
kLt, // <
kGt, // >
kLe, // <=
kGe // >=
};
static OpKind NegateOpKind(OpKind op_kind);
private:
IntOp(IntegerKind int_kind, OpKind op_kind)
: int_kind_(int_kind), op_kind_(op_kind) {}
const IntegerKind int_kind_;
const OpKind op_kind_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(IntOp);
};
// Wasm i{32/64}.const instruction.
class IntConstant : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
enum class Kind { kI32, kI64 };
IntConstant(Kind kind, uint64_t value) : kind_(kind), value_(value) {}
const Kind kind_;
const uint64_t value_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(IntConstant);
};
// Wasm i32.wrap_i64 instruction.
class Int32WrapInt64 : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
Int32WrapInt64() {}
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Int32WrapInt64);
};
// Abstract base class for Wasm block, loop and if instructions.
class StructuredInstr : public Instruction {
public:
virtual dart::SExpression* Serialize(dart::Zone* zone) = 0;
virtual void OutputBinary(dart::WriteStream* stream) = 0;
virtual ~StructuredInstr() = default;
virtual InstructionList* body() = 0;
protected:
explicit StructuredInstr(FuncType* const block_type)
: block_type_(block_type) {}
FuncType* const block_type_;
private:
DISALLOW_COPY_AND_ASSIGN(StructuredInstr);
};
// Wasm block construct.
class Block : public StructuredInstr {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
InstructionList* body() override { return body_; }
private:
Block(FuncType* const block_type, dart::Zone* zone);
InstructionList* const body_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Block);
};
// Wasm loop construct.
class Loop : public StructuredInstr {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
InstructionList* body() override { return body_; }
private:
Loop(FuncType* const block_type, dart::Zone* zone);
InstructionList* const body_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Loop);
};
// Wasm if-then-else construct.
// The block type constrains possible combinations of then/else branches by
// requiring that they have the same type; i.e. consume the same number of
// arguments of the same types from the operand stack and likewise push back
// the same number or values of the same types.
class If : public StructuredInstr {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
InstructionList* then() { return then_; }
InstructionList* otherwise() { return otherwise_; }
InstructionList* body() override { UNREACHABLE(); }
private:
If(FuncType* const block_type, dart::Zone* zone);
InstructionList* const then_;
InstructionList* const otherwise_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(If);
};
// Wasm br/br_if instructions.
class Br : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
Br(bool is_if, const uint32_t label) : is_if_(is_if), label_(label) {}
const bool is_if_; // true for br_if, false otherwise.
const uint32_t label_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Br);
};
// Wasm GC extension rtt.canon instruction.
class RttCanon : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
explicit RttCanon(HeapType* type) : type_(type) {}
HeapType* const type_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RttCanon);
};
// Wasm GC extension rtt.sub instruction.
class RttSub : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
RttSub(intptr_t depth, HeapType* supertype, HeapType* type)
: depth_(depth), supertype_(supertype), type_(type) {}
const intptr_t depth_;
HeapType* const supertype_;
HeapType* const type_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RttSub);
};
// Wasm GC extension struct.get instruction.
class StructGet : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
StructGet(StructType* struct_type, Field* field)
: struct_type_(struct_type), field_(field) {}
StructType* const struct_type_;
// This might be a field from a struct which struct_type inherits from.
// Due to structural prefix subtyping in Wasm, their <fieldidx> agree,
// meaning that they can be used interchangeably for output purposes.
Field* const field_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(StructGet);
};
// Wasm GC extension struct.set instruction.
class StructSet : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
StructSet(StructType* struct_type, Field* field)
: struct_type_(struct_type), field_(field) {}
StructType* const struct_type_;
// This might be a field from a struct which struct_type inherits from.
// Due to structural prefix subtyping in Wasm, their <fieldidx> agree,
// meaning that they can be used interchangeably for output purposes.
Field* const field_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(StructSet);
};
// Wasm struct.new_with_rtt/new_default_with_rtt instructions.
class StructNewWithRtt : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
StructNewWithRtt(StructType* struct_type, bool def)
: struct_type_(struct_type), def_(def) {}
StructType* const struct_type_;
const bool def_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(StructNewWithRtt);
};
// Wasm call instruction.
class Call : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
Call(Function* function) : function_(function) {}
Function* const function_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Call);
};
// Wasm call_indirect instruction.
class CallIndirect : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
CallIndirect(FuncType* func_type) : func_type_(func_type) {}
FuncType* const func_type_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(CallIndirect);
};
// Wasm drop instruction.
class Drop : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
Drop() {}
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Drop);
};
// Wasm return instruction.
class Return : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
Return() {}
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Return);
};
// Wasm GC extension ref.null instruction.
class RefNull : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
explicit RefNull(HeapType* type) : type_(type) {}
HeapType* const type_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RefNull);
};
// Wasm GC extension ref.eq instruction.
class RefEq : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
RefEq() {}
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RefEq);
};
// Wasm GC extension ref.cast instruction.
class RefCast : public Instruction {
public:
dart::SExpression* Serialize(dart::Zone* zone) override;
void OutputBinary(dart::WriteStream* stream) override;
private:
RefCast(HeapType* from_type, HeapType* to_type)
: from_type_(from_type), to_type_(to_type) {}
HeapType* const from_type_;
HeapType* const to_type_;
friend InstructionList; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(RefCast);
};
// Wasm Table.
class Table : public dart::ZoneAllocated {
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
private:
Table(uint32_t min_size, uint32_t max_size)
: min_size_(min_size), max_size_(max_size) {}
const uint32_t min_size_;
const uint32_t max_size_; // In our implementation, we
// require an explicit maximum size.
friend WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Table);
};
// Wasm single element table initialization segment.
class SingleElemSegment : public dart::ZoneAllocated {
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
private:
SingleElemSegment(uint32_t offset, Function* function)
: offset_(offset), function_(function) {}
// In the current Wasm specification, there can only be one table.
// Table* const table_;
// The Wasm specification gives this as an initializer expression.
const uint32_t offset_;
// The Wasm specification allows initializing more than a single table
// position per segment. Our use case doesn't require this additional
// feature, and hence the prefix 'Single' in the name of this class.
Function* const function_;
friend WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(SingleElemSegment);
};
// Wasm function locals: local and param declarations used in function
// definitions. The two concepts have not been separated because in Wasm
// parameters and locals share the same indexing space of their containing
// function.
class Local : public dart::ZoneAllocated {
public:
enum class Kind { kLocal, kParam };
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
Function* function() const { return function_; }
const char* name() const { return name_; }
uint32_t index() const { return index_; }
Kind kind() const { return kind_; }
ValueType* type() const { return type_; }
private:
Local(Function* function,
Kind kind,
ValueType* type,
const char* name,
int index)
: function_(function),
name_(name),
index_(index),
kind_(kind),
type_(type) {}
Function* const function_;
const char* name_;
const uint32_t index_;
const Kind kind_;
ValueType* const type_;
friend class Function; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Local);
};
// Class for Wasm globals, which can be either mutable or immutable,
// and are initialized by a constant initializer expression.
class Global : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
InstructionList* init() const { return init_; }
uint32_t index() const { return index_; }
private:
Global(dart::Zone* zone, ValueType* type, bool mut, uint32_t index);
ValueType* const type_;
const bool mut_;
InstructionList* const init_;
uint32_t index_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Global);
};
// Wasm instruction list.
class InstructionList : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
// One method for creating each type of Wasm instruction.
// This abstracts away the need to allocate the
// instructions in the correct zone.
LocalGet* AddLocalGet(Local* local);
LocalSet* AddLocalSet(Local* local);
GlobalGet* AddGlobalGet(Global* global);
IntOp* AddIntOp(IntOp::IntegerKind integer_kind, IntOp::OpKind op_kind);
IntConstant* AddI32Constant(uint32_t value);
IntConstant* AddI64Constant(uint64_t value);
Int32WrapInt64* AddInt32WrapInt64();
Block* AddBlock(FuncType* block_type);
Loop* AddLoop(FuncType* block_type);
If* AddIf(FuncType* block_type);
RttCanon* AddRttCanon(HeapType* type);
RttSub* AddRttSub(uint32_t depth, HeapType* supertype, HeapType* type);
StructGet* AddStructGet(StructType* struct_type, Field* field);
StructSet* AddStructSet(StructType* struct_type, Field* field);
StructNewWithRtt* AddStructNewWithRtt(StructType* struct_type);
StructNewWithRtt* AddStructNewDefaultWithRtt(StructType* struct_type);
Call* AddCall(Function* function);
CallIndirect* AddCallIndirect(FuncType* function_type);
Drop* AddDrop();
Return* AddReturn();
Br* AddBr(uint32_t label);
Br* AddBrIf(uint32_t label);
RefNull* AddRefNull(HeapType* type);
RefEq* AddRefEq();
RefCast* AddRefCast(HeapType* from_type, HeapType* to_type);
dart::GrowableArray<Instruction*>& instructions() { return instructions_; }
private:
explicit InstructionList(dart::Zone* zone);
dart::Zone* const zone_;
dart::GrowableArray<Instruction*> instructions_;
friend class Function; // For private constructor.
friend class Block; // For private constructor.
friend class Loop; // For private constructor.
friend class If; // For private constructor.
friend class Global; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(InstructionList);
};
// Wasm function. Its body is represented as an InstructionList.
// When imported_module_name_ is not null the function is imported from JS.
// In that case, the function is also body-less and will not be part of binary
// or serialization output. Imported functions need to precede all other
// functions, as per the Wasm specification.
class Function : public dart::ZoneAllocated {
public:
dart::SExpression* Serialize(dart::Zone* zone);
// Outputs the body of the function, as part of the Wasm Code section.
// Note that this skips outputing type_, since that goes into the Function
// section of binary Wasm.
void OutputBinary(dart::WriteStream* stream);
Local* AddLocal(Local::Kind kind, ValueType* type, const char* name);
Local* GetLocalByName(const char* name);
Local* GetLocalByIndex(int id);
InstructionList* MakeNewBodyAndClearLocals();
uint32_t index() const { return index_; }
FuncType* type() const { return type_; }
void set_type(FuncType* type) { type_ = type; }
InstructionList* body() const { return body_; }
bool IsImported() const { return imported_module_name_ != nullptr; }
private:
Function(dart::Zone* zone,
const char* module_name,
const char* name,
uint32_t index,
FuncType* type);
dart::Zone* const zone_;
const char* imported_module_name_;
const char* name_;
const uint32_t index_;
FuncType* type_;
dart::GrowableArray<Local*> locals_;
InstructionList* body_;
friend class WasmModuleBuilder; // For private constructor.
DISALLOW_COPY_AND_ASSIGN(Function);
};
// Provides higher level methods for building a Wasm module and
// serializing it. Instantiated as a field of the Precompiler.
class WasmModuleBuilder : public dart::ValueObject {
public:
WasmModuleBuilder(dart::Zone* zone);
// After we add conversion straight to binary format, this will no longer
// serve as the main way of outputting Wasm. Instead, it will be used as a
// means of debugging. Consequently, it's not entirely compliant with actual
// text format. Applies to all other Serialize() methods.
dart::SExpression* Serialize(dart::Zone* zone);
void OutputBinary(dart::WriteStream* stream);
// Used to specify a field type, for use in array/struct field construction.
FieldType* MakeFieldType(ValueType* value_type, bool mut);
FieldType* MakeFieldType(FieldType::PackedType packed_type, bool mut);
// Wrap a defined type into a heap type.
HeapType* MakeHeapType(DefType* def_type);
// Wrap a heap type into a reference type.
RefType* MakeRefType(bool nullable, HeapType* heap_type);
// Make a reference to a user-defined type.
RefType* MakeRefType(bool nullable, DefType* def_type);
// Convenience methods for defining the tree structure of rtts.
Global* MakeRttCanon(StructType* type);
Global* MakeRttChild(StructType* type, Global* parent_global);
// Create defined types (push to the types_ array as a side effect).
FuncType* MakeFuncType();
StructType* MakeStructType();
ArrayType* MakeArrayType(FieldType* field_type);
ArrayType* MakeArrayType(ValueType* value_type, bool mut);
ArrayType* MakeArrayType(FieldType::PackedType packed_type, bool mut);
// Create global definition.
Global* AddGlobal(ValueType* type, bool mut);
// Create function with the given name and function type.
Function* AddFunction(const char* name, FuncType* type);
// Create an imported function with the given name, module name and
// function type.
Function* AddImportedFunction(const char* module_name,
const char* name,
FuncType* type);
Function* start_function() const { return start_function_; }
void set_start_function(Function* function) { start_function_ = function; }
// Create table in the table section. Can be called at most once per module.
Table* AddFunctionsTable(uint32_t min_size, uint32_t max_size);
// Set table value at the given offset to point to the given function.
// Requires the table to have been created beforehand.
SingleElemSegment* AddElemTableInitializer(uint32_t offset,
Function* function);
// Builtin types.
NumType* i32() { return &i32_; }
NumType* i64() { return &i64_; }
NumType* f32() { return &f32_; }
NumType* f64() { return &f64_; }
RefType* funcref() { return &funcref_; }
RefType* externref() { return &externref_; }
RefType* anyref() { return &anyref_; }
RefType* eqref() { return &eqref_; }
RefType* i31ref() { return &i31ref_; }
HeapType* func() { return &func_; }
HeapType* ext() { return &ext_; }
HeapType* any() { return &any_; }
HeapType* eq() { return &eq_; }
HeapType* i31() { return &i31_; }
dart::Zone* zone() const { return zone_; }
private:
// Type section consists of a list of user-defined type definitions.
void OutputTypeSection(dart::WriteStream* stream);
// Import section consists of a list of imported functions, tables, memories,
// and globals.
void OutputImportSection(dart::WriteStream* stream);
// Function section consists of a list of the types of all user-defined
// functions. Note that actual code for the functions resides in the
// Code section.
void OutputFunctionSection(dart::WriteStream* stream);
// Table section declares the global function references table, if present.
// Its initialization is done in the Element section.
void OutputTableSection(dart::WriteStream* stream);
// Global section consists of a list of global variable definitions.
// Each global can be either mutable or immutable, and is initialized
// by a constant initializer expression.
void OutputGlobalSection(dart::WriteStream* stream);
// Start section consists of the index of the start function, if any.
void OutputStartSection(dart::WriteStream* stream);
// Element section consists of initializers for the Table section.
void OutputElementSection(dart::WriteStream* stream);
// Code section consists of a list with one entry per user-defined function.
// Each entry consists of a description of the function locals (consisting
// of the type for each local) and the contents of the function body.
void OutputCodeSection(dart::WriteStream* stream);
NumType i32_;
NumType i64_;
NumType f32_;
NumType f64_;
HeapType func_;
HeapType ext_;
HeapType any_;
HeapType eq_;
HeapType i31_;
RefType funcref_; // Type alias: funcref = (ref null func).
RefType externref_; // Type alias: externref = (ref null extern).
RefType anyref_; // Type alias: anyref = (ref null any).
RefType eqref_; // Type alias: eqref = (ref null eq).
RefType i31ref_; // Type alias: i31ref = (ref i31).
Function* start_function_;
intptr_t num_imported_functions_;
intptr_t num_non_imported_functions_;
dart::Zone* const zone_;
dart::GrowableArray<DefType*> types_;
dart::GrowableArray<Function*> functions_;
// The Wasm Core specification restricts the number of tables to at most one.
// (see https://webassembly.github.io/spec/core/syntax/types#table-types).
Table* table_;
dart::GrowableArray<Global*> globals_;
dart::GrowableArray<SingleElemSegment*> elem_segments_;
friend class PushBytecountFrontScope; // For access to replacing the
// current binary_output_stream_.
DISALLOW_COPY_AND_ASSIGN(WasmModuleBuilder);
};
} // namespace wasm
#endif // RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_WASM_H_