summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/c-writer.cc297
-rw-r--r--src/template/wasm2c.declarations.c81
-rw-r--r--src/template/wasm2c.includes.c1
-rw-r--r--src/tools/wasm2c.cc1
4 files changed, 313 insertions, 67 deletions
diff --git a/src/c-writer.cc b/src/c-writer.cc
index 0c201b12..1270b716 100644
--- a/src/c-writer.cc
+++ b/src/c-writer.cc
@@ -278,6 +278,8 @@ class CWriter {
void WriteTables();
void WriteTable(const std::string&);
void WriteTablePtr(const std::string&);
+ void WriteDataInstances();
+ void WriteElemInstances();
void WriteGlobalInitializers();
void WriteDataInitializers();
void WriteElemInitializers();
@@ -996,6 +998,7 @@ void CWriter::WriteFuncTypes() {
Writef("static u32 func_types[%" PRIzd "];", module_->types.size());
Write(Newline());
}
+ Write(Newline());
Write("static void init_func_types(void) ", OpenBrace());
if (!module_->types.size()) {
Write(CloseBrace(), Newline());
@@ -1285,6 +1288,8 @@ void CWriter::WriteModuleInstance() {
WriteGlobals();
WriteMemories();
WriteTables();
+ WriteDataInstances();
+ WriteElemInstances();
// C forbids an empty struct
if (module_->globals.empty() && module_->memories.empty() &&
@@ -1382,24 +1387,38 @@ void CWriter::WriteGlobalInitializers() {
}
++global_index;
}
- Write(CloseBrace(), Newline());
+ Write(CloseBrace(), Newline(), Newline());
}
-void CWriter::WriteDataInitializers() {
- const Memory* memory = nullptr;
- Index data_segment_index = 0;
+static inline bool is_droppable(const DataSegment* data_segment) {
+ return (data_segment->kind == SegmentKind::Passive) &&
+ (!data_segment->data.empty());
+}
+
+static inline bool is_droppable(const ElemSegment* elem_segment) {
+ return (elem_segment->kind == SegmentKind::Passive) &&
+ (!elem_segment->elem_exprs.empty());
+}
+void CWriter::WriteDataInstances() {
+ for (const DataSegment* data_segment : module_->data_segments) {
+ DefineGlobalScopeName(data_segment->name);
+ if (is_droppable(data_segment)) {
+ Write("bool ", "data_segment_dropped_", GetGlobalName(data_segment->name),
+ " : 1;", Newline());
+ }
+ }
+}
+
+void CWriter::WriteDataInitializers() {
if (!module_->memories.empty()) {
if (module_->data_segments.empty()) {
Write(Newline());
} else {
for (const DataSegment* data_segment : module_->data_segments) {
- if (!data_segment->data.size()) {
- Write(Newline(), "static const u8* data_segment_data_",
- data_segment_index, " = NULL;", Newline());
- } else {
+ if (data_segment->data.size()) {
Write(Newline(), "static const u8 data_segment_data_",
- data_segment_index, "[] = ", OpenBrace());
+ GetGlobalName(data_segment->name), "[] = ", OpenBrace());
size_t i = 0;
for (uint8_t x : data_segment->data) {
Writef("0x%02x, ", x);
@@ -1410,11 +1429,8 @@ void CWriter::WriteDataInitializers() {
Write(Newline());
Write(CloseBrace(), ";", Newline());
}
- ++data_segment_index;
}
}
-
- memory = module_->memories[0];
}
Write("static void init_memory(", ModuleInstanceTypeName(), "* instance) ",
@@ -1422,83 +1438,140 @@ void CWriter::WriteDataInitializers() {
if (module_->memories.size() > module_->num_memory_imports) {
Index memory_idx = module_->num_memory_imports;
for (Index i = memory_idx; i < module_->memories.size(); i++) {
- memory = module_->memories[i];
+ const Memory* memory = module_->memories[i];
uint32_t max =
memory->page_limits.has_max ? memory->page_limits.max : 65536;
Write("wasm_rt_allocate_memory(", ExternalInstancePtr(memory->name), ", ",
memory->page_limits.initial, ", ", max, ");", Newline());
}
}
- data_segment_index = 0;
for (const DataSegment* data_segment : module_->data_segments) {
+ if (data_segment->kind != SegmentKind::Active) {
+ continue;
+ }
+ const Memory* memory =
+ module_->memories[module_->GetMemoryIndex(data_segment->memory_var)];
Write("LOAD_DATA(", ExternalInstanceRef(memory->name), ", ");
WriteInitExpr(data_segment->offset);
- Write(", data_segment_data_", data_segment_index, ", ",
- data_segment->data.size());
+ if (data_segment->data.empty()) {
+ Write(", NULL, 0");
+ } else {
+ Write(", data_segment_data_", GetGlobalName(data_segment->name), ", ",
+ data_segment->data.size());
+ }
Write(");", Newline());
- ++data_segment_index;
}
Write(CloseBrace(), Newline());
+
+ Write(Newline(), "static void init_data_instances(", ModuleInstanceTypeName(),
+ " *instance) ", OpenBrace());
+
+ for (const DataSegment* data_segment : module_->data_segments) {
+ if (is_droppable(data_segment)) {
+ Write("instance->data_segment_dropped_",
+ GetGlobalName(data_segment->name), " = false;", Newline());
+ }
+ }
+
+ Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteElemInstances() {
+ for (const ElemSegment* elem_segment : module_->elem_segments) {
+ DefineGlobalScopeName(elem_segment->name);
+ if (is_droppable(elem_segment)) {
+ Write("bool ", "elem_segment_dropped_", GetGlobalName(elem_segment->name),
+ " : 1;", Newline());
+ }
+ }
}
void CWriter::WriteElemInitializers() {
- Write(Newline(), "static void init_table(", ModuleInstanceTypeName(),
- "* instance) ", OpenBrace());
+ for (const ElemSegment* elem_segment : module_->elem_segments) {
+ if (elem_segment->elem_exprs.empty()) {
+ continue;
+ }
- if (!module_->types.size()) {
- // If there are no types there cannot be any table entries either.
- for (const ElemSegment* elem_segment : module_->elem_segments) {
- assert(elem_segment->elem_exprs.size() == 0);
+ Write(Newline(),
+ "static const wasm_elem_segment_expr_t elem_segment_exprs_",
+ GetGlobalName(elem_segment->name), "[] = ", OpenBrace());
+
+ for (const ExprList& elem_expr : elem_segment->elem_exprs) {
+ assert(elem_expr.size() == 1);
+ const Expr& expr = elem_expr.front();
+ switch (expr.type()) {
+ case ExprType::RefFunc: {
+ const Func* func = module_->GetFunc(cast<RefFuncExpr>(&expr)->var);
+ const Index func_type_index =
+ module_->GetFuncTypeIndex(func->decl.type_var);
+ Write("{", func_type_index, ", ");
+ Write("(wasm_rt_funcref_t)", ExternalPtr(func->name), ", ");
+ const bool is_import = import_module_sym_map_.count(func->name) != 0;
+ if (is_import) {
+ Write("offsetof(", ModuleInstanceTypeName(), ", ",
+ MangleModuleInstanceName(import_module_sym_map_[func->name]),
+ ")");
+ } else {
+ Write("0");
+ }
+ Write("}, ", Newline());
+ } break;
+ case ExprType::RefNull:
+ Write("{0, NULL, 0}, ", Newline());
+ break;
+ default:
+ WABT_UNREACHABLE;
+ }
}
- Write(CloseBrace(), Newline());
- return;
+ Write(CloseBrace(), ";", Newline());
}
+
+ Write(Newline(), "static void init_table(", ModuleInstanceTypeName(),
+ "* instance) ", OpenBrace());
+
const Table* table = module_->tables.empty() ? nullptr : module_->tables[0];
- Write("uint32_t offset;", Newline());
if (table && module_->num_table_imports == 0) {
uint32_t max =
table->elem_limits.has_max ? table->elem_limits.max : UINT32_MAX;
Write("wasm_rt_allocate_table(", ExternalInstancePtr(table->name), ", ",
table->elem_limits.initial, ", ", max, ");", Newline());
}
- Index elem_segment_index = 0;
for (const ElemSegment* elem_segment : module_->elem_segments) {
- if (elem_segment->kind == SegmentKind::Passive) {
+ if (elem_segment->kind != SegmentKind::Active) {
continue;
}
- Write("offset = ");
+
+ Write("table_init(", ExternalInstancePtr(table->name), ", ");
+ if (elem_segment->elem_exprs.empty()) {
+ Write("NULL, 0, ");
+ } else {
+ Write("elem_segment_exprs_", GetGlobalName(elem_segment->name), ", ",
+ elem_segment->elem_exprs.size(), ", ");
+ }
WriteInitExpr(elem_segment->offset);
- Write(";", Newline());
+ if (elem_segment->elem_exprs.empty()) {
+ // It's mandatory to handle the case of a zero-length elem segment
+ // (even in a module with no types). This must trap if the offset
+ // is out of bounds.
+ Write(", 0, 0, instance, NULL);", Newline());
+ } else {
+ Write(", 0, ", elem_segment->elem_exprs.size(),
+ ", instance, func_types);", Newline());
+ }
+ }
- size_t i = 0;
- for (const ExprList& elem_expr : elem_segment->elem_exprs) {
- // We don't support the bulk-memory proposal here, so we know that we
- // don't have any passive segments (where ref.null can be used).
- assert(elem_expr.size() == 1);
- const Expr* expr = &elem_expr.front();
- assert(expr->type() == ExprType::RefFunc);
- const Func* func = module_->GetFunc(cast<RefFuncExpr>(expr)->var);
- Index func_type_index = module_->GetFuncTypeIndex(func->decl.type_var);
-
- bool is_import = import_module_sym_map_.count(func->name) != 0;
- if (is_import) {
- Write(ExternalInstanceRef(table->name), ".data[offset + ", i,
- "] = (wasm_rt_elem_t){func_types[", func_type_index,
- "], (wasm_rt_funcref_t)", ExternalPtr(func->name),
- ", (void*)(instance->",
- MangleModuleInstanceName(import_module_sym_map_[func->name]),
- ")};", Newline());
- } else {
- Write(ExternalInstanceRef(table->name), ".data[offset + ", i,
- "] = (wasm_rt_elem_t){func_types[", func_type_index,
- "], (wasm_rt_funcref_t)", ExternalPtr(func->name),
- ", (void*)instance};", Newline());
- }
- ++i;
+ Write(CloseBrace(), Newline());
+
+ Write(Newline(), "static void init_elem_instances(", ModuleInstanceTypeName(),
+ " *instance) ", OpenBrace());
+
+ for (const ElemSegment* elem_segment : module_->elem_segments) {
+ if (is_droppable(elem_segment)) {
+ Write("instance->elem_segment_dropped_",
+ GetGlobalName(elem_segment->name), " = false;", Newline());
}
- ++elem_segment_index;
}
Write(CloseBrace(), Newline());
@@ -1652,6 +1725,8 @@ void CWriter::WriteInit() {
Write("init_globals(instance);", Newline());
Write("init_memory(instance);", Newline());
Write("init_table(instance);", Newline());
+ Write("init_data_instances(instance);", Newline());
+ Write("init_elem_instances(instance);", Newline());
for (Var* var : module_->starts) {
Write(ExternalRef(module_->GetFunc(*var)->name));
bool is_import =
@@ -1715,8 +1790,7 @@ void CWriter::WriteFree() {
Write(Newline(), "void " + module_prefix_ + "_free(",
ModuleInstanceTypeName(), "* instance) ", OpenBrace());
- if (module_->types.size()) {
- // If there are no types there cannot be any table entries either.
+ {
assert(module_->tables.size() <= 1);
Index table_index = 0;
for (const Table* table : module_->tables) {
@@ -2340,13 +2414,104 @@ void CWriter::Write(const ExprList& exprs) {
break;
}
- case ExprType::MemoryCopy:
- case ExprType::DataDrop:
- case ExprType::MemoryInit:
- case ExprType::MemoryFill:
- case ExprType::TableCopy:
- case ExprType::ElemDrop:
- case ExprType::TableInit:
+ case ExprType::MemoryFill: {
+ const auto inst = cast<MemoryFillExpr>(&expr);
+ Memory* memory =
+ module_->memories[module_->GetMemoryIndex(inst->memidx)];
+ Write("memory_fill(", ExternalInstancePtr(memory->name), ", ",
+ StackVar(2), ", ", StackVar(1), ", ", StackVar(0), ");",
+ Newline());
+ DropTypes(3);
+ } break;
+
+ case ExprType::MemoryCopy: {
+ const auto inst = cast<MemoryCopyExpr>(&expr);
+ Memory* dest_memory =
+ module_->memories[module_->GetMemoryIndex(inst->destmemidx)];
+ const Memory* src_memory = module_->GetMemory(inst->srcmemidx);
+ Write("memory_copy(", ExternalInstancePtr(dest_memory->name), ", ",
+ ExternalInstancePtr(src_memory->name), ", ", StackVar(2), ", ",
+ StackVar(1), ", ", StackVar(0), ");", Newline());
+ DropTypes(3);
+ } break;
+
+ case ExprType::MemoryInit: {
+ const auto inst = cast<MemoryInitExpr>(&expr);
+ Memory* dest_memory =
+ module_->memories[module_->GetMemoryIndex(inst->memidx)];
+ const DataSegment* src_data = module_->GetDataSegment(inst->var);
+ Write("memory_init(", ExternalInstancePtr(dest_memory->name), ", ");
+ if (src_data->data.empty()) {
+ Write("NULL, 0");
+ } else {
+ Write("data_segment_data_", GetGlobalName(src_data->name), ", ");
+ if (is_droppable(src_data)) {
+ Write("(", "instance->data_segment_dropped_",
+ GetGlobalName(src_data->name),
+ " ? 0 : ", src_data->data.size(), ")");
+ } else {
+ Write("0");
+ }
+ }
+
+ Write(", ", StackVar(2), ", ", StackVar(1), ", ", StackVar(0), ");",
+ Newline());
+ DropTypes(3);
+ } break;
+
+ case ExprType::TableInit: {
+ const auto inst = cast<TableInitExpr>(&expr);
+ Table* dest_table =
+ module_->tables[module_->GetTableIndex(inst->table_index)];
+ const ElemSegment* src_segment =
+ module_->GetElemSegment(inst->segment_index);
+ Write("table_init(", ExternalInstancePtr(dest_table->name), ", ");
+ if (src_segment->elem_exprs.empty()) {
+ Write("NULL, 0");
+ } else {
+ Write("elem_segment_exprs_", GetGlobalName(src_segment->name), ", ");
+ if (is_droppable(src_segment)) {
+ Write("(instance->elem_segment_dropped_",
+ GetGlobalName(src_segment->name),
+ " ? 0 : ", src_segment->elem_exprs.size(), ")");
+ } else {
+ Write("0");
+ }
+ }
+
+ Write(", ", StackVar(2), ", ", StackVar(1), ", ", StackVar(0));
+ Write(", instance, func_types);", Newline());
+ DropTypes(3);
+ } break;
+
+ case ExprType::DataDrop: {
+ const auto inst = cast<DataDropExpr>(&expr);
+ const DataSegment* data = module_->GetDataSegment(inst->var);
+ if (is_droppable(data)) {
+ Write("instance->data_segment_dropped_", GetGlobalName(data->name),
+ " = true;", Newline());
+ }
+ } break;
+
+ case ExprType::ElemDrop: {
+ const auto inst = cast<ElemDropExpr>(&expr);
+ const ElemSegment* seg = module_->GetElemSegment(inst->var);
+ if (is_droppable(seg)) {
+ Write("instance->elem_segment_dropped_", GetGlobalName(seg->name),
+ " = true;", Newline());
+ }
+ } break;
+
+ case ExprType::TableCopy: {
+ const auto inst = cast<TableCopyExpr>(&expr);
+ Table* dest_table =
+ module_->tables[module_->GetTableIndex(inst->dst_table)];
+ const Table* src_table = module_->GetTable(inst->src_table);
+ Write("table_copy(", ExternalInstancePtr(dest_table->name), ", ",
+ ExternalInstancePtr(src_table->name), ", ", StackVar(2), ", ",
+ StackVar(1), ", ", StackVar(0), ");", Newline());
+ } break;
+
case ExprType::TableGet:
case ExprType::TableSet:
case ExprType::TableGrow:
@@ -3180,10 +3345,10 @@ void CWriter::WriteCSource() {
WriteTagTypes();
WriteTags();
WriteFuncDeclarations();
- WriteFuncs();
WriteGlobalInitializers();
WriteDataInitializers();
WriteElemInitializers();
+ WriteFuncs();
WriteExports(WriteExportsKind::Definitions);
WriteInitInstanceImport();
WriteInit();
diff --git a/src/template/wasm2c.declarations.c b/src/template/wasm2c.declarations.c
index 4459790f..8e1e1d3c 100644
--- a/src/template/wasm2c.declarations.c
+++ b/src/template/wasm2c.declarations.c
@@ -444,4 +444,85 @@ static float wasm_sqrtf(float x) {
return sqrtf(x);
}
+static inline void memory_fill(wasm_rt_memory_t* mem, u32 d, u32 val, u32 n) {
+ RANGE_CHECK(mem, d, n);
+ memset(mem->data + d, val, n);
+}
+
+static inline void memory_copy(wasm_rt_memory_t* dest,
+ const wasm_rt_memory_t* src,
+ u32 dest_addr,
+ u32 src_addr,
+ u32 n) {
+ RANGE_CHECK(dest, dest_addr, n);
+ RANGE_CHECK(src, src_addr, n);
+ memmove(dest->data + dest_addr, src->data + src_addr, n);
+}
+
+static inline void memory_init(wasm_rt_memory_t* dest,
+ const u8* src,
+ u32 src_size,
+ u32 dest_addr,
+ u32 src_addr,
+ u32 n) {
+ if (UNLIKELY(src_addr + (uint64_t)n > src_size))
+ TRAP(OOB);
+ LOAD_DATA((*dest), dest_addr, src + src_addr, n);
+}
+
+typedef struct {
+ uint32_t func_type_index;
+ wasm_rt_funcref_t func;
+ size_t module_offset;
+} wasm_elem_segment_expr_t;
+
+static inline void table_init(wasm_rt_table_t* dest,
+ const wasm_elem_segment_expr_t* src,
+ u32 src_size,
+ u32 dest_addr,
+ u32 src_addr,
+ u32 n,
+ void* module_instance,
+ const u32* func_types) {
+ if (UNLIKELY(src_addr + (uint64_t)n > src_size))
+ TRAP(OOB);
+ if (UNLIKELY(dest_addr + (uint64_t)n > dest->size))
+ TRAP(OOB);
+ for (u32 i = 0; i < n; i++) {
+ const wasm_elem_segment_expr_t* src_expr = &src[src_addr + i];
+ dest->data[dest_addr + i] =
+ (wasm_rt_elem_t){func_types[src_expr->func_type_index], src_expr->func,
+ (char*)module_instance + src_expr->module_offset};
+ }
+}
+
+static inline void table_copy(wasm_rt_table_t* dest,
+ const wasm_rt_table_t* src,
+ u32 dest_addr,
+ u32 src_addr,
+ u32 n) {
+ if (UNLIKELY(dest_addr + (uint64_t)n > dest->size))
+ TRAP(OOB);
+ if (UNLIKELY(src_addr + (uint64_t)n > src->size))
+ TRAP(OOB);
+
+ if (n == 0) {
+ return;
+ }
+
+ if (dest->data + dest_addr == src->data + src_addr) {
+ return;
+ }
+
+ if (dest->data + dest_addr < src->data + src_addr) {
+ for (u32 i = 0; i < n; i++) {
+ dest->data[dest_addr + i] = src->data[src_addr + i];
+ }
+ } else {
+ for (u32 i = n; i > 0; i--) {
+ dest->data[dest_addr + i - 1] = src->data[src_addr + i - 1];
+ }
+ }
+}
+
static bool s_module_initialized = false;
diff --git a/src/template/wasm2c.includes.c b/src/template/wasm2c.includes.c
index 59def29c..d89a9475 100644
--- a/src/template/wasm2c.includes.c
+++ b/src/template/wasm2c.includes.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <math.h>
+#include <stddef.h>
#include <string.h>
#if defined(_MSC_VER)
#include <intrin.h>
diff --git a/src/tools/wasm2c.cc b/src/tools/wasm2c.cc
index 7ed745f4..3dd14483 100644
--- a/src/tools/wasm2c.cc
+++ b/src/tools/wasm2c.cc
@@ -109,7 +109,6 @@ static void ParseOptions(int argc, char** argv) {
"wasm2c currently only supports a limited set of features.\n");
exit(1);
}
- s_features.disable_bulk_memory();
}
// TODO(binji): copied from binary-writer-spec.cc, probably should share.