mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Create type declarations for extern functions and write the 'import' section
This commit is contained in:
parent
300ebbd560
commit
aa3e0ff454
@ -253,6 +253,20 @@ pub fn section(val: Section) u8 {
|
|||||||
return @enumToInt(val);
|
return @enumToInt(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of the type when importing or exporting to/from the host environment
|
||||||
|
/// https://webassembly.github.io/spec/core/syntax/modules.html
|
||||||
|
pub const ExternalKind = enum(u8) {
|
||||||
|
function,
|
||||||
|
table,
|
||||||
|
memory,
|
||||||
|
global,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns the integer value of a given `ExternalKind`
|
||||||
|
pub fn kind(val: ExternalKind) u8 {
|
||||||
|
return @enumToInt(val);
|
||||||
|
}
|
||||||
|
|
||||||
// types
|
// types
|
||||||
pub const element_type: u8 = 0x70;
|
pub const element_type: u8 = 0x70;
|
||||||
pub const function_type: u8 = 0x60;
|
pub const function_type: u8 = 0x60;
|
||||||
|
|||||||
@ -163,13 +163,18 @@ pub const Context = struct {
|
|||||||
try self.genFunctype();
|
try self.genFunctype();
|
||||||
const writer = self.code.writer();
|
const writer = self.code.writer();
|
||||||
|
|
||||||
// Reserve space to write the size after generating the code as well as space for locals count
|
|
||||||
try self.code.resize(10);
|
|
||||||
|
|
||||||
// Write instructions
|
// Write instructions
|
||||||
// TODO: check for and handle death of instructions
|
// TODO: check for and handle death of instructions
|
||||||
const tv = self.decl.typed_value.most_recent.typed_value;
|
const tv = self.decl.typed_value.most_recent.typed_value;
|
||||||
const mod_fn = tv.val.castTag(.function).?.data;
|
const mod_fn = blk: {
|
||||||
|
if (tv.val.castTag(.function)) |func| break :blk func.data;
|
||||||
|
if (tv.val.castTag(.extern_fn)) |ext_fn| return; // don't need codegen for extern functions
|
||||||
|
return self.fail(self.decl.src(), "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reserve space to write the size after generating the code as well as space for locals count
|
||||||
|
try self.code.resize(10);
|
||||||
|
|
||||||
try self.genBody(mod_fn.body);
|
try self.genBody(mod_fn.body);
|
||||||
|
|
||||||
// finally, write our local types at the 'offset' position
|
// finally, write our local types at the 'offset' position
|
||||||
@ -239,9 +244,16 @@ pub const Context = struct {
|
|||||||
|
|
||||||
fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
|
fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
|
||||||
const func_inst = inst.func.castTag(.constant).?;
|
const func_inst = inst.func.castTag(.constant).?;
|
||||||
const func = func_inst.val.castTag(.function).?.data;
|
const func_val = inst.func.value().?;
|
||||||
const target = func.owner_decl;
|
|
||||||
const target_ty = target.typed_value.most_recent.typed_value.ty;
|
const target = blk: {
|
||||||
|
if (func_val.castTag(.function)) |func| {
|
||||||
|
break :blk func.data.owner_decl;
|
||||||
|
} else if (func_val.castTag(.extern_fn)) |ext_fn| {
|
||||||
|
break :blk ext_fn.data;
|
||||||
|
}
|
||||||
|
return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()});
|
||||||
|
};
|
||||||
|
|
||||||
for (inst.args) |arg| {
|
for (inst.args) |arg| {
|
||||||
const arg_val = self.resolveInst(arg);
|
const arg_val = self.resolveInst(arg);
|
||||||
@ -495,7 +507,7 @@ pub const Context = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
|
fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
|
||||||
// of operand has codegen bits we should break with a value
|
// if operand has codegen bits we should break with a value
|
||||||
if (br.operand.ty.hasCodeGenBits()) {
|
if (br.operand.ty.hasCodeGenBits()) {
|
||||||
const operand = self.resolveInst(br.operand);
|
const operand = self.resolveInst(br.operand);
|
||||||
try self.emitWValue(operand);
|
try self.emitWValue(operand);
|
||||||
|
|||||||
@ -85,8 +85,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
|
|||||||
const typed_value = decl.typed_value.most_recent.typed_value;
|
const typed_value = decl.typed_value.most_recent.typed_value;
|
||||||
if (typed_value.ty.zigTypeTag() != .Fn)
|
if (typed_value.ty.zigTypeTag() != .Fn)
|
||||||
return error.TODOImplementNonFnDeclsForWasm;
|
return error.TODOImplementNonFnDeclsForWasm;
|
||||||
if (typed_value.val.tag() == .extern_fn)
|
|
||||||
return error.TODOImplementExternFnDeclsForWasm;
|
|
||||||
|
|
||||||
if (decl.fn_link.wasm) |*fn_data| {
|
if (decl.fn_link.wasm) |*fn_data| {
|
||||||
fn_data.functype.items.len = 0;
|
fn_data.functype.items.len = 0;
|
||||||
@ -184,17 +182,63 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import section
|
||||||
|
{
|
||||||
|
// TODO: implement non-functions imports
|
||||||
|
const header_offset = try reserveVecSectionHeader(file);
|
||||||
|
const writer = file.writer();
|
||||||
|
var count: u32 = 0;
|
||||||
|
for (self.funcs.items) |decl, typeidx| {
|
||||||
|
if (decl.typed_value.most_recent.typed_value.val.tag() != .extern_fn) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: can we set/save the module name somewhere?
|
||||||
|
// For now, emit "env" like LLVM does
|
||||||
|
const module_name = "env";
|
||||||
|
try leb.writeULEB128(writer, @intCast(u32, module_name.len));
|
||||||
|
try writer.writeAll(module_name);
|
||||||
|
|
||||||
|
// wasm requires the length of the import name and doesn't require a null-termination
|
||||||
|
const decl_len = mem.len(decl.name);
|
||||||
|
try leb.writeULEB128(writer, @intCast(u32, decl_len));
|
||||||
|
try writer.writeAll(decl.name[0..decl_len]);
|
||||||
|
|
||||||
|
// emit kind and the function type
|
||||||
|
try writer.writeByte(wasm.kind(.function));
|
||||||
|
try leb.writeULEB128(writer, @intCast(u32, typeidx));
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try writeVecSectionHeader(
|
||||||
|
file,
|
||||||
|
header_offset,
|
||||||
|
.import,
|
||||||
|
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
||||||
|
count,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Function section
|
// Function section
|
||||||
{
|
{
|
||||||
const header_offset = try reserveVecSectionHeader(file);
|
const header_offset = try reserveVecSectionHeader(file);
|
||||||
const writer = file.writer();
|
const writer = file.writer();
|
||||||
for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx));
|
var count: u32 = 0;
|
||||||
|
for (self.funcs.items) |decl, typeidx| {
|
||||||
|
// Extern functions only have a type, so skip the function signature section
|
||||||
|
if (decl.typed_value.most_recent.typed_value.val.tag() != .function) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try leb.writeULEB128(writer, @intCast(u32, typeidx));
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
try writeVecSectionHeader(
|
try writeVecSectionHeader(
|
||||||
file,
|
file,
|
||||||
header_offset,
|
header_offset,
|
||||||
.function,
|
.function,
|
||||||
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
||||||
@intCast(u32, self.funcs.items.len),
|
count,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +258,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
|||||||
// Type of the export
|
// Type of the export
|
||||||
try writer.writeByte(0x00);
|
try writer.writeByte(0x00);
|
||||||
// Exported function index
|
// Exported function index
|
||||||
try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?);
|
try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).? + 1);
|
||||||
},
|
},
|
||||||
else => return error.TODOImplementNonFnDeclsForWasm,
|
else => return error.TODOImplementNonFnDeclsForWasm,
|
||||||
}
|
}
|
||||||
@ -235,7 +279,13 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
|||||||
{
|
{
|
||||||
const header_offset = try reserveVecSectionHeader(file);
|
const header_offset = try reserveVecSectionHeader(file);
|
||||||
const writer = file.writer();
|
const writer = file.writer();
|
||||||
|
var count: u32 = 0;
|
||||||
for (self.funcs.items) |decl| {
|
for (self.funcs.items) |decl| {
|
||||||
|
// Do not emit any code for extern functions
|
||||||
|
if (decl.typed_value.most_recent.typed_value.val.tag() != .function) {
|
||||||
|
std.debug.print("Skipping decl: {s}\n", .{decl.name});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const fn_data = &decl.fn_link.wasm.?;
|
const fn_data = &decl.fn_link.wasm.?;
|
||||||
|
|
||||||
// Write the already generated code to the file, inserting
|
// Write the already generated code to the file, inserting
|
||||||
@ -247,18 +297,20 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
|||||||
// Use a fixed width here to make calculating the code size
|
// Use a fixed width here to make calculating the code size
|
||||||
// in codegen.wasm.gen() simpler.
|
// in codegen.wasm.gen() simpler.
|
||||||
var buf: [5]u8 = undefined;
|
var buf: [5]u8 = undefined;
|
||||||
leb.writeUnsignedFixed(5, &buf, self.getFuncidx(idx_ref.decl).?);
|
std.debug.print("idx_ref: {s} - {d}\n", .{ idx_ref.decl.name, self.getFuncidx(idx_ref.decl).? });
|
||||||
|
leb.writeUnsignedFixed(5, &buf, self.getFuncidx(idx_ref.decl).? - 1);
|
||||||
try writer.writeAll(&buf);
|
try writer.writeAll(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(fn_data.code.items[current..]);
|
try writer.writeAll(fn_data.code.items[current..]);
|
||||||
|
count += 1;
|
||||||
}
|
}
|
||||||
try writeVecSectionHeader(
|
try writeVecSectionHeader(
|
||||||
file,
|
file,
|
||||||
header_offset,
|
header_offset,
|
||||||
.code,
|
.code,
|
||||||
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
||||||
@intCast(u32, self.funcs.items.len),
|
count,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user