Skip to content

Commit

Permalink
start on the debugger
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexicon226 committed Jun 30, 2024
1 parent e70d127 commit eac8ad4
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 48 deletions.
2 changes: 2 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ pub fn build(b: *std.Build) !void {
const tracer_dep = b.dependency("tracer", .{ .optimize = optimize, .target = target });
const libgc_dep = b.dependency("libgc", .{ .optimize = optimize, .target = target });
const cpython_dep = b.dependency("cpython", .{ .optimize = optimize, .target = target });
const libvaxis = b.dependency("libvaxis", .{ .optimize = optimize, .target = target });

exe.root_module.addImport("tracer", tracer_dep.module("tracer"));
exe.root_module.addImport("gc", libgc_dep.module("gc"));
exe.root_module.addImport("cpython", cpython_dep.module("cpython"));
exe.root_module.addImport("vaxis", libvaxis.module("vaxis"));

exe_options.addOption([]const u8, "lib_path", "../python/Lib");

Expand Down
4 changes: 4 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@
.url = "https://github.com/Rexicon226/zig-libgc/archive/1ea12e140ec1471af5d15dae71b225764c9747ba.tar.gz",
.hash = "12209ad7282d9422973afe3e468e2f867bb102d04fa446a1d1c94f900bda94b7c68e",
},
.libvaxis = .{
.url = "https://github.com/rockorager/libvaxis/archive/c213919849114ce03def64806af546b9fc391859.tar.gz",
.hash = "12206f2265ca2262f919ec125ff7fe15fa6f3be622806e211d7a9bd3055ba51a0908",
},
},
}
2 changes: 1 addition & 1 deletion graph/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def read_graph_binary(filename):

node_colors = ['green' if node == first_node else 'red' if node in nodes_with_no_successors else 'skyblue' for node in G_filtered.nodes]

pos = nx.nx_agraph.graphviz_layout(G_filtered, prog='neato')
pos = nx.nx_agraph.graphviz_layout(G_filtered, prog='dot')
plt.figure(figsize=(15, 10))
nx.draw(G_filtered, pos, with_labels=True, labels=nx.get_node_attributes(G_filtered, 'label'), node_color=node_colors, node_size=3000, font_size=10, font_color='black', font_weight='bold', edge_color='gray')

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/CodeObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub fn hash(
hasher.update(std.mem.asBytes(&co.stacksize));
hasher.update(std.mem.asBytes(&co.consts));
hasher.update(std.mem.asBytes(&co.names));
hasher.update(std.mem.asBytes(&co.varnames));
hasher.update(std.mem.sliceAsBytes(co.varnames));
hasher.update(std.mem.asBytes(co.instructions.?)); // CodeObject should be processed before hashing

// we don't hash the index on purpose as it has nothing to do with the unique contents of the object
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/Instruction.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ fn format2(
.LOAD_NAME,
.STORE_NAME,
.IMPORT_NAME,
.LOAD_METHOD,
=> try writer.print("{d} ({s})", .{ extra, co.getName(extra) }),
.CALL_FUNCTION,
.CALL_METHOD,
=> try writer.print("{d}", .{extra}),
.MAKE_FUNCTION,
=> {
Expand Down
18 changes: 16 additions & 2 deletions src/crash_report.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

const std = @import("std");
const CodeObject = @import("compiler/CodeObject.zig");
const print_co = @import("print_co.zig");

const builtin = @import("builtin");
const build_options = @import("options");
Expand Down Expand Up @@ -123,6 +122,21 @@ pub fn prepVmContext(current_co: CodeObject) VmContext {
} else .{};
}

pub fn print_co(writer: anytype, data: struct { co: CodeObject, index: ?usize }) !void {
const co = data.co;
const maybe_index = data.index;

try writer.print("{}", .{co});

const instructions = co.instructions.?; // should have already been processed
try writer.writeAll("Instructions:\n");
for (instructions, 0..) |inst, i| {
if (maybe_index) |index| if (index == i) try writer.print("(#{d}) -> ", .{index});
if (maybe_index == null or maybe_index.? != i) try writer.writeAll("\t");
try writer.print("{d}\t{}\n", .{ i * 2, inst.fmt(co) });
}
}

var buffer: [10 * 1024]u8 = undefined;

fn dumpObjectTrace() !void {
Expand All @@ -134,7 +148,7 @@ fn dumpObjectTrace() !void {
var current_co = state.current_co;
try current_co.process(allocator);

try print_co.print_co(stderr, .{
try print_co(stderr, .{
.co = current_co,
.index = state.index,
});
Expand Down
9 changes: 6 additions & 3 deletions src/frontend/Python.zig
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ pub fn parse(
try writer.writeInt(u32, @intCast(source.len), .little);
try writer.writeAll(pyc_bytes);

helpers.DecRef(bytecode);
helpers.Finalize();
externs.Py_DecRef(bytecode);
externs.Py_Finalize();

return bytes;
}
Expand Down Expand Up @@ -86,7 +86,10 @@ pub fn Initialize(
);
_ = externs.PyConfig_Read(&config);

const utf32_path = try utf8ToUtf32Z("../python/Lib", allocator);
const utf32_path = try utf8ToUtf32Z(
"/home/dr/Zython/osmium/zig-out/python/Lib",
allocator,
);

config.module_search_paths_set = 1;
_ = externs.PyWideStringList_Append(
Expand Down
12 changes: 10 additions & 2 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const builtin = @import("builtin");
const Graph = @import("graph/Graph.zig");
const Python = @import("frontend/Python.zig");
const Marshal = @import("compiler/Marshal.zig");
const Vm = @import("vm/Vm.zig");
const crash_report = @import("crash_report.zig");
const Vm = @import("vm/Vm.zig");
const Object = @import("vm/Object.zig");
const debug = @import("vm/debug.zig");

const build_options = @import("options");

Expand Down Expand Up @@ -70,6 +71,7 @@ pub fn log(

const Args = struct {
make_graph: bool,
run_debug: bool,
run: bool,
};

Expand Down Expand Up @@ -105,6 +107,7 @@ pub fn main() !u8 {
var file_path: ?[:0]const u8 = null;
var options: Args = .{
.make_graph = false,
.run_debug = false,
.run = true,
};

Expand All @@ -131,6 +134,9 @@ pub fn main() !u8 {
options.make_graph = true;
} else if (std.mem.eql(u8, arg, "--no-run")) {
options.run = false;
} else if (std.mem.eql(u8, arg, "--debug")) {
options.run_debug = true;
options.run = false;
}
}

Expand All @@ -156,6 +162,7 @@ fn usage() void {
\\ Debug Options:
\\ --no-run Doesn't run the VM, useful for debugging Osmium
\\ --graph, Creates a "graph.bin" which contains CFG information
\\ --debug, Runs a interactable debug mode to debug the VM
;

const stdout = std.io.getStdOut().writer();
Expand Down Expand Up @@ -217,13 +224,14 @@ pub fn run_file(
try graph.dump();
}

var vm = try Vm.init(gc_allocator, file_name, seed);
var vm = try Vm.init(gc_allocator, seed);
defer vm.deinit();
{
var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const source_file_path = try std.os.getFdPath(source_file.handle, &dir_path_buf);
try vm.initBuiltinMods(source_file_path);
}
if (options.run_debug) try debug.run(&vm, gc_allocator);
if (options.run) try vm.run();

main_log.debug("Run stats:", .{});
Expand Down
8 changes: 6 additions & 2 deletions src/modules/builtins.zig
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ fn __import__(vm: *Vm, args: []const Object, maybe_kw: ?KW_Type) BuiltinError!vo
const object = try marshal.parse();

// create a new vm to evaluate the global scope of the module
var mod_vm = try Vm.init(vm.allocator, absolute_path, object);
var mod_vm = try Vm.init(vm.allocator, object);
mod_vm.initBuiltinMods(absolute_path) catch |err| {
return vm.fail("failed init evaulte module {s} with error {s}", .{ absolute_path, @errorName(err) });
};
Expand Down Expand Up @@ -390,5 +390,9 @@ fn __build_class__(vm: *Vm, args: []const Object, maybe_kw: ?KW_Type) BuiltinErr
assert(func_obj.tag == .function);
assert(name_obj.tag == .string);

std.debug.panic("TODO: implement __build_class__", .{});
const class = try vm.createObject(.class, .{
.name = name_obj.get(.string),
.under_func = func_obj,
});
try vm.stack.append(vm.allocator, class);
}
23 changes: 0 additions & 23 deletions src/print_co.zig

This file was deleted.

42 changes: 37 additions & 5 deletions src/vm/Object.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ pub const Tag = enum(usize) {
list,
set,

/// A builtin Zig defined function.
zig_function,

codeobject,
function,

module,

class,

pub fn PayloadType(comptime t: Tag) type {
assert(@intFromEnum(t) >= Tag.first_payload);

Expand All @@ -72,8 +73,10 @@ pub const Tag = enum(usize) {
.function => Payload.PythonFunction,

.module => Payload.Module,
.class => Payload.Class,

.none => unreachable,

else => @compileError("TODO: PayloadType " ++ @tagName(t)),
};
}
Expand Down Expand Up @@ -306,6 +309,18 @@ pub fn getMemberFunction(object: *const Object, name: []const u8, allocator: All
}
break :blk try list.toOwnedSlice();
},
.class => {
var list = std.ArrayList(std.meta.Child(Payload.MemberFuncTy)).init(allocator);
const class = object.get(.class);
_ = &list;

const under_func = class.under_func;
const under_co = under_func.get(.codeobject);

std.debug.print("Name: {s}\n", .{under_co.name});

unreachable;
},
else => std.debug.panic("{s} has no member functions", .{@tagName(object.tag)}),
};
for (member_list) |func| {
Expand Down Expand Up @@ -356,6 +371,7 @@ pub const Payload = union(enum) {
list: List,
codeobject: CodeObject,
function: PythonFunction,
class: Class,

pub const Int = BigIntManaged;
pub const String = []u8;
Expand Down Expand Up @@ -525,6 +541,16 @@ pub const Payload = union(enum) {
};
}
};

pub const Class = struct {
name: []const u8,
under_func: Object,

pub fn deinit(class: *Class, allocator: std.mem.Allocator) void {
allocator.free(class.name);
class.under_func.deinit(allocator);
}
};
};

pub fn format(
Expand Down Expand Up @@ -606,10 +632,10 @@ pub fn format(
@intFromPtr(&function.co),
});
},
// .codeobject => {
// const co = object.get(.codeobject);
// try writer.print("{}", .{co.*});
// },
.codeobject => {
const co = object.get(.codeobject);
try writer.print("co({s})", .{co.name});
},

else => try writer.print("TODO: Object.format '{s}'", .{@tagName(object.tag)}),
}
Expand Down Expand Up @@ -670,6 +696,12 @@ pub const Context = struct {
const payload = obj.get(.zig_function);
std.hash.autoHash(&hasher, payload);
},
.class => {
const payload = obj.get(.class);

hasher.update(payload.name);
hasher.update(std.mem.asBytes(&ctx.hash(payload.under_func)));
},
inline else => |t| {
const payload = obj.get(t);
std.hash.autoHashStrat(&hasher, payload, .Deep);
Expand Down
26 changes: 17 additions & 9 deletions src/vm/Vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ depth: u32 = 0,
/// VM State
is_running: bool,

/// Name of the python file being executed.
///
/// TODO: this should be taken from the current codeobject,
/// however that doesn't seem to be working right now.
name: [:0]const u8,

stack: std.ArrayListUnmanaged(Object),
scopes: std.ArrayListUnmanaged(std.StringHashMapUnmanaged(Object)) = .{},

Expand All @@ -62,15 +56,14 @@ crash_info: crash_report.VmContext,
builtin_mods: std.StringHashMapUnmanaged(Object.Payload.Module) = .{},

/// Takes ownership of `co`.
pub fn init(allocator: Allocator, name: [:0]const u8, co: CodeObject) !Vm {
pub fn init(allocator: Allocator, co: CodeObject) !Vm {
const t = tracer.trace(@src(), "", .{});
defer t.end();

return .{
.allocator = allocator,
.is_running = false,
.co = co,
.name = name,
.crash_info = crash_report.prepVmContext(co),
.stack = try std.ArrayListUnmanaged(Object).initCapacity(allocator, co.stacksize),
};
Expand Down Expand Up @@ -142,7 +135,7 @@ pub fn run(
log.debug(
"{s} - {s}: {s} (stack_size={}, pc={}/{}, depth={}, heap={})",
.{
vm.name,
vm.co.filename,
vm.co.name,
@tagName(instruction.op),
vm.stack.items.len,
Expand Down Expand Up @@ -314,6 +307,7 @@ fn execStoreName(vm: *Vm, inst: Instruction) !void {
const name = vm.co.getName(inst.extra);
// NOTE: STORE_NAME does NOT pop the stack, it only stores the TOS.
const tos = vm.stack.items[vm.stack.items.len - 1];
std.debug.print("STORE_NAME: {}\n", .{tos});
try vm.scopes.items[vm.depth].put(vm.allocator, name, tos);
}

Expand Down Expand Up @@ -409,6 +403,20 @@ fn execCallFunction(vm: *Vm, inst: Instruction) !void {
}
vm.depth += 1;
},
.class => {
const class = func_object.get(.class);
const under_func = class.under_func;

const func = under_func.get(.function);

try vm.scopes.append(vm.allocator, .{});
try vm.co_stack.append(vm.allocator, vm.co);
vm.setNewCo(func.co);
for (args, 0..) |arg, i| {
vm.co.varnames[i] = arg;
}
vm.depth += 1;
},
else => unreachable,
}
}
Expand Down
Loading

0 comments on commit eac8ad4

Please sign in to comment.