mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
wasm linker: flush implemented up to the export section
This commit is contained in:
parent
e21a42723b
commit
bf88059591
@ -404,7 +404,7 @@ pub const SymbolFlags = packed struct(u32) {
|
||||
/// Zig-specific. Data segments only.
|
||||
alignment: Alignment = .none,
|
||||
/// Zig-specific. Globals only.
|
||||
global_type: Global.Type = .zero,
|
||||
global_type: GlobalType4 = .zero,
|
||||
/// Zig-specific. Tables only.
|
||||
limits_has_max: bool = false,
|
||||
/// Zig-specific. Tables only.
|
||||
@ -481,6 +481,48 @@ pub const SymbolFlags = packed struct(u32) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const GlobalType4 = packed struct(u4) {
|
||||
valtype: Valtype3,
|
||||
mutable: bool,
|
||||
|
||||
pub const zero: GlobalType4 = @bitCast(@as(u4, 0));
|
||||
|
||||
pub fn to(gt: GlobalType4) Global.Type {
|
||||
return .{
|
||||
.valtype = gt.valtype.to(),
|
||||
.mutable = gt.mutable,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Valtype3 = enum(u3) {
|
||||
i32,
|
||||
i64,
|
||||
f32,
|
||||
f64,
|
||||
v128,
|
||||
|
||||
pub fn from(v: std.wasm.Valtype) Valtype3 {
|
||||
return switch (v) {
|
||||
.i32 => .i32,
|
||||
.i64 => .i64,
|
||||
.f32 => .f32,
|
||||
.f64 => .f64,
|
||||
.v128 => .v128,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn to(v: Valtype3) std.wasm.Valtype {
|
||||
return switch (v) {
|
||||
.i32 => .i32,
|
||||
.i64 => .i64,
|
||||
.f32 => .f32,
|
||||
.f64 => .f64,
|
||||
.v128 => .v128,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const NavObj = extern struct {
|
||||
code: DataSegment.Payload,
|
||||
/// Empty if not emitting an object.
|
||||
@ -591,7 +633,7 @@ pub const FunctionImport = extern struct {
|
||||
__zig_error_names,
|
||||
object_function: ObjectFunctionIndex,
|
||||
nav_exe: NavExe.Index,
|
||||
nav_obj: NavExe.Index,
|
||||
nav_obj: NavObj.Index,
|
||||
};
|
||||
|
||||
pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
|
||||
@ -649,6 +691,20 @@ pub const FunctionImport = extern struct {
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn typeIndex(r: Resolution, wasm: *const Wasm) FunctionType.Index {
|
||||
return switch (unpack(r, wasm)) {
|
||||
.unresolved => unreachable,
|
||||
.__wasm_apply_global_tls_relocs => @panic("TODO"),
|
||||
.__wasm_call_ctors => @panic("TODO"),
|
||||
.__wasm_init_memory => @panic("TODO"),
|
||||
.__wasm_init_tls => @panic("TODO"),
|
||||
.__zig_error_names => @panic("TODO"),
|
||||
.object_function => |i| i.ptr(wasm).type_index,
|
||||
.nav_exe => @panic("TODO"),
|
||||
.nav_obj => @panic("TODO"),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `object_function_imports`.
|
||||
@ -731,11 +787,13 @@ pub const GlobalImport = extern struct {
|
||||
pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked {
|
||||
return switch (r) {
|
||||
.unresolved => .unresolved,
|
||||
.__wasm_apply_global_tls_relocs => .__wasm_apply_global_tls_relocs,
|
||||
.__wasm_call_ctors => .__wasm_call_ctors,
|
||||
.__wasm_init_memory => .__wasm_init_memory,
|
||||
.__wasm_init_tls => .__wasm_init_tls,
|
||||
.__zig_error_names => .__zig_error_names,
|
||||
.__heap_base => .__heap_base,
|
||||
.__heap_end => .__heap_end,
|
||||
.__stack_pointer => .__stack_pointer,
|
||||
.__tls_align => .__tls_align,
|
||||
.__tls_base => .__tls_base,
|
||||
.__tls_size => .__tls_size,
|
||||
.__zig_error_name_table => .__zig_error_name_table,
|
||||
_ => {
|
||||
const i: u32 = @intFromEnum(r);
|
||||
const object_global_index = i - first_object_global;
|
||||
@ -780,12 +838,28 @@ pub const GlobalImport = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `object_global_imports`.
|
||||
/// Index into `Wasm.object_global_imports`.
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: Index, wasm: *const Wasm) *GlobalImport {
|
||||
return &wasm.object_global_imports.items[@intFromEnum(index)];
|
||||
pub fn key(index: Index, wasm: *const Wasm) *String {
|
||||
return &wasm.object_global_imports.keys()[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
pub fn value(index: Index, wasm: *const Wasm) *GlobalImport {
|
||||
return &wasm.object_global_imports.values()[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
pub fn name(index: Index, wasm: *const Wasm) String {
|
||||
return index.key(wasm).*;
|
||||
}
|
||||
|
||||
pub fn moduleName(index: Index, wasm: *const Wasm) String {
|
||||
return index.value(wasm).module_name;
|
||||
}
|
||||
|
||||
pub fn globalType(index: Index, wasm: *const Wasm) Global.Type {
|
||||
return value(index, wasm).flags.global_type.to();
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -796,39 +870,9 @@ pub const Global = extern struct {
|
||||
flags: SymbolFlags,
|
||||
expr: Expr,
|
||||
|
||||
pub const Type = packed struct(u4) {
|
||||
valtype: Valtype,
|
||||
pub const Type = struct {
|
||||
valtype: std.wasm.Valtype,
|
||||
mutable: bool,
|
||||
|
||||
pub const zero: Type = @bitCast(@as(u4, 0));
|
||||
};
|
||||
|
||||
pub const Valtype = enum(u3) {
|
||||
i32,
|
||||
i64,
|
||||
f32,
|
||||
f64,
|
||||
v128,
|
||||
|
||||
pub fn from(v: std.wasm.Valtype) Valtype {
|
||||
return switch (v) {
|
||||
.i32 => .i32,
|
||||
.i64 => .i64,
|
||||
.f32 => .f32,
|
||||
.f64 => .f64,
|
||||
.v128 => .v128,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn to(v: Valtype) std.wasm.Valtype {
|
||||
return switch (v) {
|
||||
.i32 => .i32,
|
||||
.i64 => .i64,
|
||||
.f32 => .f32,
|
||||
.f64 => .f64,
|
||||
.v128 => .v128,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -865,6 +909,38 @@ pub const TableImport = extern struct {
|
||||
__indirect_function_table,
|
||||
// Next, index into `object_tables`.
|
||||
_,
|
||||
|
||||
const first_object_table = @intFromEnum(Resolution.__indirect_function_table) + 1;
|
||||
|
||||
pub const Unpacked = union(enum) {
|
||||
unresolved,
|
||||
__indirect_function_table,
|
||||
object_table: ObjectTableIndex,
|
||||
};
|
||||
|
||||
pub fn unpack(r: Resolution) Unpacked {
|
||||
return switch (r) {
|
||||
.unresolved => .unresolved,
|
||||
.__indirect_function_table => .__indirect_function_table,
|
||||
_ => .{ .object_table = @enumFromInt(@intFromEnum(r) - first_object_table) },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
|
||||
return switch (unpack(r)) {
|
||||
.unresolved => unreachable,
|
||||
.__indirect_function_table => @panic("TODO"),
|
||||
.object_table => |i| i.ptr(wasm).flags.ref_type.to(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn limits(r: Resolution, wasm: *const Wasm) std.wasm.Limits {
|
||||
return switch (unpack(r)) {
|
||||
.unresolved => unreachable,
|
||||
.__indirect_function_table => @panic("TODO"),
|
||||
.object_table => |i| i.ptr(wasm).limits(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `object_table_imports`.
|
||||
@ -878,7 +954,26 @@ pub const TableImport = extern struct {
|
||||
pub fn value(index: Index, wasm: *const Wasm) *TableImport {
|
||||
return &wasm.object_table_imports.values()[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
pub fn name(index: Index, wasm: *const Wasm) String {
|
||||
return index.key(wasm).*;
|
||||
}
|
||||
|
||||
pub fn moduleName(index: Index, wasm: *const Wasm) String {
|
||||
return index.value(wasm).module_name;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn limits(ti: *const TableImport) std.wasm.Limits {
|
||||
return .{
|
||||
.flags = .{
|
||||
.has_max = ti.flags.limits_has_max,
|
||||
.is_shared = ti.flags.limits_is_shared,
|
||||
},
|
||||
.min = ti.limits_min,
|
||||
.max = ti.limits_max,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Table = extern struct {
|
||||
@ -887,6 +982,17 @@ pub const Table = extern struct {
|
||||
flags: SymbolFlags,
|
||||
limits_min: u32,
|
||||
limits_max: u32,
|
||||
|
||||
pub fn limits(t: *const Table) std.wasm.Limits {
|
||||
return .{
|
||||
.flags = .{
|
||||
.has_max = t.flags.limits_has_max,
|
||||
.is_shared = t.flags.limits_is_shared,
|
||||
},
|
||||
.min = t.limits_min,
|
||||
.max = t.limits_max,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Uniquely identifies a section across all objects. By subtracting
|
||||
@ -910,9 +1016,13 @@ pub const GlobalImportIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// Index into `object_globals`.
|
||||
/// Index into `Wasm.object_globals`.
|
||||
pub const ObjectGlobalIndex = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global {
|
||||
return &wasm.object_globals.items[@intFromEnum(index)];
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `Wasm.object_memories`.
|
||||
@ -992,6 +1102,16 @@ pub const CustomSegment = extern struct {
|
||||
/// An index into string_bytes where a wasm expression is found.
|
||||
pub const Expr = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const end = @intFromEnum(std.wasm.Opcode.end);
|
||||
|
||||
pub fn slice(index: Expr, wasm: *const Wasm) [:end]const u8 {
|
||||
const start_slice = wasm.string_bytes.items[@intFromEnum(index)..];
|
||||
const end_pos = Object.exprEndPos(start_slice, 0) catch |err| switch (err) {
|
||||
error.InvalidInitOpcode => unreachable,
|
||||
};
|
||||
return start_slice[0..end_pos :end];
|
||||
}
|
||||
};
|
||||
|
||||
pub const FunctionType = extern struct {
|
||||
@ -1162,6 +1282,12 @@ pub const ZcuImportIndex = enum(u32) {
|
||||
const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
|
||||
return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;
|
||||
}
|
||||
|
||||
pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) Global.Type {
|
||||
_ = index;
|
||||
_ = wasm;
|
||||
unreachable; // Zig has no way to create Wasm globals yet.
|
||||
}
|
||||
};
|
||||
|
||||
/// 0. Index into `object_function_imports`.
|
||||
@ -1274,6 +1400,24 @@ pub const GlobalImportId = enum(u32) {
|
||||
.zcu_import => return .zig_object_nofile, // TODO give a better source location
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(id: GlobalImportId, wasm: *const Wasm) String {
|
||||
return switch (unpack(id, wasm)) {
|
||||
inline .object_global_import, .zcu_import => |i| i.name(wasm),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) String {
|
||||
return switch (unpack(id, wasm)) {
|
||||
inline .object_global_import, .zcu_import => |i| i.moduleName(wasm),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn globalType(id: GlobalImportId, wasm: *Wasm) Global.Type {
|
||||
return switch (unpack(id, wasm)) {
|
||||
inline .object_global_import, .zcu_import => |i| i.globalType(wasm),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `Wasm.symbol_table`.
|
||||
@ -1384,6 +1528,17 @@ pub const MemoryImport = extern struct {
|
||||
limits_has_max: bool,
|
||||
limits_is_shared: bool,
|
||||
padding: [2]u8 = .{ 0, 0 },
|
||||
|
||||
pub fn limits(mi: *const MemoryImport) std.wasm.Limits {
|
||||
return .{
|
||||
.flags = .{
|
||||
.has_max = mi.limits_has_max,
|
||||
.is_shared = mi.limits_is_shared,
|
||||
},
|
||||
.min = mi.limits_min,
|
||||
.max = mi.limits_max,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Alignment = InternPool.Alignment;
|
||||
|
||||
@ -335,8 +335,6 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
log.debug("maximum memory pages: {?d}", .{wasm.memories.limits.max});
|
||||
}
|
||||
|
||||
// Size of each section header
|
||||
const header_size = 5 + 1;
|
||||
var section_index: u32 = 0;
|
||||
// Index of the code section. Used to tell relocation table where the section lives.
|
||||
var code_section_index: ?u32 = null;
|
||||
@ -369,54 +367,50 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
}
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.type,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.func_types.entries.len),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(wasm.func_types.entries.len));
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// Import section
|
||||
const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len +
|
||||
wasm.table_imports.entries.len + wasm.object_memory_imports.items.len + @intFromBool(import_memory);
|
||||
|
||||
if (total_imports_len > 0) {
|
||||
{
|
||||
var total_imports: usize = 0;
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
|
||||
for (wasm.function_imports.values()) |*function_import| {
|
||||
const module_name = function_import.moduleName(wasm).slice(wasm);
|
||||
for (wasm.function_imports.values()) |id| {
|
||||
const module_name = id.moduleName(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
|
||||
try binary_writer.writeAll(module_name);
|
||||
|
||||
const name = function_import.name(wasm).slice(wasm);
|
||||
const name = id.name(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
|
||||
try binary_writer.writeAll(name);
|
||||
|
||||
try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(function_import.functionType(wasm)));
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(id.functionType(wasm)));
|
||||
}
|
||||
total_imports += wasm.function_imports.entries.len;
|
||||
|
||||
for (wasm.table_imports.values()) |*table_import| {
|
||||
const module_name = table_import.moduleName(wasm).slice(wasm);
|
||||
for (wasm.table_imports.values()) |id| {
|
||||
const table_import = id.value(wasm);
|
||||
const module_name = table_import.module_name.slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
|
||||
try binary_writer.writeAll(module_name);
|
||||
|
||||
const name = table_import.name(wasm).slice(wasm);
|
||||
const name = id.key(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
|
||||
try binary_writer.writeAll(name);
|
||||
|
||||
try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table));
|
||||
try leb.writeUleb128(binary_writer, std.wasm.reftype(table_import.reftype));
|
||||
try emitLimits(binary_writer, table_import.limits);
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));
|
||||
try emitLimits(gpa, binary_bytes, table_import.limits());
|
||||
}
|
||||
total_imports += wasm.table_imports.entries.len;
|
||||
|
||||
for (wasm.object_memory_imports.items) |*memory_import| {
|
||||
try emitMemoryImport(wasm, binary_writer, memory_import);
|
||||
try emitMemoryImport(wasm, binary_bytes, memory_import);
|
||||
total_imports += 1;
|
||||
} else if (import_memory) {
|
||||
try emitMemoryImport(wasm, binary_writer, &.{
|
||||
try emitMemoryImport(wasm, binary_bytes, &.{
|
||||
.module_name = wasm.host_name,
|
||||
.name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory,
|
||||
.limits_min = wasm.memories.limits.min,
|
||||
@ -424,100 +418,87 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
.limits_has_max = wasm.memories.limits.flags.has_max,
|
||||
.limits_is_shared = wasm.memories.limits.flags.is_shared,
|
||||
});
|
||||
total_imports += 1;
|
||||
}
|
||||
|
||||
for (wasm.global_imports.values()) |*global_import| {
|
||||
const module_name = global_import.module_name.slice(wasm);
|
||||
for (wasm.global_imports.values()) |id| {
|
||||
const module_name = id.moduleName(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
|
||||
try binary_writer.writeAll(module_name);
|
||||
|
||||
const name = global_import.name.slice(wasm);
|
||||
const name = id.name(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
|
||||
try binary_writer.writeAll(name);
|
||||
|
||||
try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global));
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(global_import.valtype));
|
||||
try binary_writer.writeByte(@intFromBool(global_import.mutable));
|
||||
const global_type = id.globalType(wasm);
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
|
||||
try binary_writer.writeByte(@intFromBool(global_type.mutable));
|
||||
}
|
||||
total_imports += wasm.global_imports.entries.len;
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.import,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(total_imports_len),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// Function section
|
||||
if (wasm.functions.count() != 0) {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
for (wasm.functions.values()) |function| {
|
||||
try leb.writeUleb128(binary_writer, function.func.type_index);
|
||||
for (wasm.functions.keys()) |function| {
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(function.typeIndex(wasm)));
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.function,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.functions.count()),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// Table section
|
||||
if (wasm.tables.items.len > 0) {
|
||||
if (wasm.tables.entries.len > 0) {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
|
||||
for (wasm.tables.items) |table| {
|
||||
try leb.writeUleb128(binary_writer, std.wasm.reftype(table.reftype));
|
||||
try emitLimits(binary_writer, table.limits);
|
||||
for (wasm.tables.keys()) |table| {
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm))));
|
||||
try emitLimits(gpa, binary_bytes, table.limits(wasm));
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.table,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.tables.items.len),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .table, @intCast(wasm.tables.entries.len));
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// Memory section
|
||||
// Memory section. wasm currently only supports 1 linear memory segment.
|
||||
if (!import_memory) {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
|
||||
try emitLimits(binary_writer, wasm.memories.limits);
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.memory,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
1, // wasm currently only supports 1 linear memory segment
|
||||
);
|
||||
try emitLimits(gpa, binary_bytes, wasm.memories.limits);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .memory, 1);
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// Global section (used to emit stack pointer)
|
||||
if (wasm.output_globals.items.len > 0) {
|
||||
if (wasm.globals.entries.len > 0) {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
|
||||
for (wasm.output_globals.items) |global| {
|
||||
try binary_writer.writeByte(@intFromEnum(global.global_type.valtype));
|
||||
try binary_writer.writeByte(@intFromBool(global.global_type.mutable));
|
||||
try emitInit(binary_writer, global.init);
|
||||
for (wasm.globals.keys()) |global_resolution| {
|
||||
switch (global_resolution.unpack(wasm)) {
|
||||
.unresolved => unreachable,
|
||||
.__heap_base => @panic("TODO"),
|
||||
.__heap_end => @panic("TODO"),
|
||||
.__stack_pointer => @panic("TODO"),
|
||||
.__tls_align => @panic("TODO"),
|
||||
.__tls_base => @panic("TODO"),
|
||||
.__tls_size => @panic("TODO"),
|
||||
.__zig_error_name_table => @panic("TODO"),
|
||||
.object_global => |i| {
|
||||
const global = i.ptr(wasm);
|
||||
try binary_writer.writeByte(@intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())));
|
||||
try binary_writer.writeByte(@intFromBool(global.flags.global_type.mutable));
|
||||
try emitExpr(wasm, binary_bytes, global.expr);
|
||||
},
|
||||
.nav_exe => @panic("TODO"),
|
||||
.nav_obj => @panic("TODO"),
|
||||
}
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.global,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.output_globals.items.len),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .global, @intCast(wasm.globals.entries.len));
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
@ -540,25 +521,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
try leb.writeUleb128(binary_writer, @as(u32, 0));
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.@"export",
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.exports.items.len + @intFromBool(export_memory)),
|
||||
);
|
||||
const n_items: u32 = @intCast(wasm.exports.items.len + @intFromBool(export_memory));
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .@"export", n_items);
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
if (wasm.entry) |entry_index| {
|
||||
if (Wasm.FunctionIndex.fromResolution(wasm.entry_resolution)) |entry_index| {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.start,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
entry_index,
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(entry_index));
|
||||
}
|
||||
|
||||
// element section (function table)
|
||||
@ -586,26 +556,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
try leb.writeUleb128(binary_writer, sym.index);
|
||||
}
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.element,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
1,
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
// When the shared-memory option is enabled, we *must* emit the 'data count' section.
|
||||
if (f.data_segment_groups.items.len > 0 and shared_memory) {
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.data_count,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(f.data_segment_groups.items.len),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));
|
||||
}
|
||||
|
||||
// Code section.
|
||||
@ -636,13 +594,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
},
|
||||
};
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.code,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
@intCast(wasm.functions.count()),
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len));
|
||||
code_section_index = section_index;
|
||||
section_index += 1;
|
||||
}
|
||||
@ -682,13 +634,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
|
||||
}
|
||||
assert(group_index == f.data_segment_groups.items.len);
|
||||
|
||||
try writeVecSectionHeader(
|
||||
binary_bytes.items,
|
||||
header_offset,
|
||||
.data,
|
||||
@intCast(binary_bytes.items.len - header_offset - header_size),
|
||||
group_index,
|
||||
);
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .data, group_index);
|
||||
data_section_index = section_index;
|
||||
section_index += 1;
|
||||
}
|
||||
@ -768,7 +714,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), arena
|
||||
};
|
||||
|
||||
var globals: std.MultiArrayList(NamedIndex) = .empty;
|
||||
try globals.ensureTotalCapacityPrecise(arena, wasm.output_globals.items.len + wasm.global_imports.items.len);
|
||||
try globals.ensureTotalCapacityPrecise(arena, wasm.globals.items.len + wasm.global_imports.items.len);
|
||||
|
||||
var segments: std.MultiArrayList(NamedIndex) = .empty;
|
||||
try segments.ensureTotalCapacityPrecise(arena, wasm.data_segments.count());
|
||||
@ -844,10 +790,8 @@ fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void {
|
||||
}
|
||||
|
||||
fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
|
||||
// unlike regular section, we don't emit the count
|
||||
const header_size = 1 + 5;
|
||||
try bytes.appendNTimes(gpa, 0, header_size);
|
||||
return @intCast(bytes.items.len - header_size);
|
||||
try bytes.appendNTimes(gpa, 0, section_header_size);
|
||||
return @intCast(bytes.items.len - section_header_size);
|
||||
}
|
||||
|
||||
fn emitNameSubsection(
|
||||
@ -1106,38 +1050,57 @@ fn wantSegmentMerge(wasm: *const Wasm, a_index: Wasm.DataSegment.Index, b_index:
|
||||
return a_prefix.len > 0 and mem.eql(u8, a_prefix, b_prefix);
|
||||
}
|
||||
|
||||
/// section id + fixed leb contents size + fixed leb vector length
|
||||
const section_header_reserve_size = 1 + 5 + 5;
|
||||
const section_header_size = 5 + 1;
|
||||
|
||||
fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {
|
||||
// section id + fixed leb contents size + fixed leb vector length
|
||||
const header_size = 1 + 5 + 5;
|
||||
try bytes.appendNTimes(gpa, 0, header_size);
|
||||
return @intCast(bytes.items.len - header_size);
|
||||
try bytes.appendNTimes(gpa, 0, section_header_reserve_size);
|
||||
return @intCast(bytes.items.len - section_header_reserve_size);
|
||||
}
|
||||
|
||||
fn writeVecSectionHeader(buffer: []u8, offset: u32, section: std.wasm.Section, size: u32, items: u32) !void {
|
||||
var buf: [1 + 5 + 5]u8 = undefined;
|
||||
buf[0] = @intFromEnum(section);
|
||||
leb.writeUnsignedFixed(5, buf[1..6], size);
|
||||
leb.writeUnsignedFixed(5, buf[6..], items);
|
||||
buffer[offset..][0..buf.len].* = buf;
|
||||
fn replaceVecSectionHeader(
|
||||
bytes: *std.ArrayListUnmanaged(u8),
|
||||
offset: u32,
|
||||
section: std.wasm.Section,
|
||||
n_items: u32,
|
||||
) void {
|
||||
const size: u32 = @intCast(bytes.items.len - offset - section_header_size);
|
||||
var buf: [section_header_reserve_size]u8 = undefined;
|
||||
var fbw = std.io.fixedBufferStream(&buf);
|
||||
const w = fbw.writer();
|
||||
w.writeByte(@intFromEnum(section)) catch unreachable;
|
||||
leb.writeUleb128(w, size) catch unreachable;
|
||||
leb.writeUleb128(w, n_items) catch unreachable;
|
||||
bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten());
|
||||
}
|
||||
|
||||
fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
|
||||
try writer.writeByte(limits.flags);
|
||||
try leb.writeUleb128(writer, limits.min);
|
||||
if (limits.flags.has_max) try leb.writeUleb128(writer, limits.max);
|
||||
fn emitLimits(
|
||||
gpa: Allocator,
|
||||
binary_bytes: *std.ArrayListUnmanaged(u8),
|
||||
limits: std.wasm.Limits,
|
||||
) Allocator.Error!void {
|
||||
try binary_bytes.append(gpa, @bitCast(limits.flags));
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), limits.min);
|
||||
if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max);
|
||||
}
|
||||
|
||||
fn emitMemoryImport(wasm: *Wasm, writer: anytype, memory_import: *const Wasm.MemoryImport) Allocator.Error!void {
|
||||
fn emitMemoryImport(
|
||||
wasm: *Wasm,
|
||||
binary_bytes: *std.ArrayListUnmanaged(u8),
|
||||
memory_import: *const Wasm.MemoryImport,
|
||||
) Allocator.Error!void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const module_name = memory_import.module_name.slice(wasm);
|
||||
try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
|
||||
try writer.writeAll(module_name);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len)));
|
||||
try binary_bytes.appendSlice(gpa, module_name);
|
||||
|
||||
const name = memory_import.name.slice(wasm);
|
||||
try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));
|
||||
try writer.writeAll(name);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
|
||||
try binary_bytes.appendSlice(gpa, name);
|
||||
|
||||
try writer.writeByte(@intFromEnum(std.wasm.ExternalKind.memory));
|
||||
try emitLimits(writer, memory_import.limits());
|
||||
try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
|
||||
try emitLimits(gpa, binary_bytes, memory_import.limits());
|
||||
}
|
||||
|
||||
pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
|
||||
@ -1166,6 +1129,12 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
|
||||
try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));
|
||||
}
|
||||
|
||||
pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const slice = expr.slice(wasm);
|
||||
try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode
|
||||
}
|
||||
|
||||
//fn emitLinkSection(
|
||||
// wasm: *Wasm,
|
||||
// binary_bytes: *std.ArrayListUnmanaged(u8),
|
||||
|
||||
@ -1040,9 +1040,9 @@ fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usi
|
||||
return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos };
|
||||
}
|
||||
|
||||
fn skipInit(bytes: []const u8, pos: usize) !usize {
|
||||
pub fn exprEndPos(bytes: []const u8, pos: usize) error{InvalidInitOpcode}!usize {
|
||||
const opcode = bytes[pos];
|
||||
const end_pos = switch (@as(std.wasm.Opcode, @enumFromInt(opcode))) {
|
||||
return switch (@as(std.wasm.Opcode, @enumFromInt(opcode))) {
|
||||
.i32_const => readLeb(i32, bytes, pos + 1)[1],
|
||||
.i64_const => readLeb(i64, bytes, pos + 1)[1],
|
||||
.f32_const => pos + 5,
|
||||
@ -1050,6 +1050,10 @@ fn skipInit(bytes: []const u8, pos: usize) !usize {
|
||||
.global_get => readLeb(u32, bytes, pos + 1)[1],
|
||||
else => return error.InvalidInitOpcode,
|
||||
};
|
||||
}
|
||||
|
||||
fn skipInit(bytes: []const u8, pos: usize) !usize {
|
||||
const end_pos = try exprEndPos(bytes, pos);
|
||||
const op, const final_pos = readEnum(std.wasm.Opcode, bytes, end_pos);
|
||||
if (op != .end) return error.InitExprMissingEnd;
|
||||
return final_pos;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user