Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vm): Do list and map initialization in less op codes #283

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 25 additions & 41 deletions src/Codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -260,37 +260,6 @@ pub fn patchTryOrJit(self: *Self, offset: usize) void {
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(jump));
}

pub fn emitList(
self: *Self,
location: Ast.TokenIndex,
) !usize {
try self.emitCodeArg(location, .OP_LIST, 0xffffff);

return self.currentCode() - 1;
}

pub fn patchList(self: *Self, offset: usize, constant: u24) !void {
const original: u32 = self.current.?.function.?.chunk.code.items[offset];
const instruction: u8 = @intCast(original >> 24);

self.current.?.function.?.chunk.code.items[offset] =
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(constant));
}

pub fn emitMap(self: *Self, location: Ast.TokenIndex) !usize {
try self.emitCodeArg(location, .OP_MAP, 0xffffff);

return self.currentCode() - 1;
}

pub fn patchMap(self: *Self, offset: usize, map_type_constant: u24) !void {
const original: u32 = self.current.?.function.?.chunk.code.items[offset];
const instruction: u8 = @intCast(original >> 24);

self.current.?.function.?.chunk.code.items[offset] =
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(map_type_constant));
}

pub fn emitReturn(self: *Self, location: Ast.TokenIndex) !void {
try self.emitOpCode(location, .OP_VOID);
try self.emitOpCode(location, .OP_RETURN);
Expand Down Expand Up @@ -2623,7 +2592,12 @@ fn generateList(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize
const type_defs = self.ast.nodes.items(.type_def);

const item_type = type_defs[node].?.resolved_type.?.List.item_type;
const list_offset = try self.emitList(locations[node]);

try self.emitCodeArg(
locations[node],
.OP_LIST,
try self.makeConstant(Value.fromObj(type_defs[node].?.toObj())),
);

for (components.items) |item| {
if (item_type.def_type == .Placeholder) {
Expand All @@ -2639,13 +2613,16 @@ fn generateList(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize
);
} else {
_ = try self.generateNode(item, breaks);

try self.emitOpCode(locations[item], .OP_LIST_APPEND);
}
}

const list_type_constant = try self.makeConstant(Value.fromObj(type_defs[node].?.toObj()));
try self.patchList(list_offset, list_type_constant);
if (components.items.len > 0) {
try self.emitCodeArg(
locations[node],
.OP_LIST_APPEND,
@intCast(components.items.len),
);
}

try self.patchOptJumps(node);
try self.endScope(node);
Expand All @@ -2668,14 +2645,16 @@ fn generateMap(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize)
else
null;

const map_offset = try self.emitMap(locations[node]);
try self.emitCodeArg(
locations[node],
.OP_MAP,
try self.makeConstant(Value.fromObj(type_defs[node].?.toObj())),
);

for (components.entries) |entry| {
_ = try self.generateNode(entry.key, breaks);
_ = try self.generateNode(entry.value, breaks);

try self.emitOpCode(locations[node], .OP_SET_MAP);

if (type_defs[entry.key].?.def_type == .Placeholder) {
self.reporter.reportPlaceholder(self.ast, type_defs[entry.key].?.resolved_type.?.Placeholder);
}
Expand Down Expand Up @@ -2707,8 +2686,13 @@ fn generateMap(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize)
}
}

const map_type_constant = try self.makeConstant(Value.fromObj(type_defs[node].?.toObj()));
try self.patchMap(map_offset, map_type_constant);
if (components.entries.len > 0) {
try self.emitCodeArg(
locations[node],
.OP_SET_MAP,
@intCast(components.entries.len),
);
}

try self.patchOptJumps(node);
try self.endScope(node);
Expand Down
8 changes: 8 additions & 0 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3345,6 +3345,10 @@ fn list(self: *Self, _: bool) Error!Ast.Node.Index {
}
}

if (items.items.len > std.math.maxInt(u24)) {
self.reportErrorAtCurrent(.syntax, "Too many elements in list initialization");
}

if (self.ast.tokens.items(.tag)[self.current_token.? - 1] != .RightBracket) {
self.reportErrorAtCurrent(.syntax, "Expected `]`");
}
Expand Down Expand Up @@ -3663,6 +3667,10 @@ fn map(self: *Self, _: bool) Error!Ast.Node.Index {
}
}

if (entries.items.len > std.math.maxInt(u24)) {
self.reportErrorAtCurrent(.syntax, "Too many entries in map initialization");
}

key_type_def = key_type_def orelse common_key_type;
value_type_def = value_type_def orelse common_value_type;
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/disassembler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,6 @@ pub fn disassembleInstruction(chunk: *Chunk, offset: usize) usize {
.OP_MOD,
.OP_UNWRAP,
.OP_GET_ENUM_CASE_VALUE,
.OP_LIST_APPEND,
.OP_SET_MAP,
.OP_GET_LIST_SUBSCRIPT,
.OP_GET_MAP_SUBSCRIPT,
.OP_GET_STRING_SUBSCRIPT,
Expand Down Expand Up @@ -266,16 +264,18 @@ pub fn disassembleInstruction(chunk: *Chunk, offset: usize) usize {
.OP_GET_UPVALUE,
.OP_SET_UPVALUE,
.OP_GET_ENUM_CASE,
.OP_MAP,
.OP_EXPORT,
.OP_COPY,
.OP_CLONE,
.OP_CLOSE_UPVALUE,
.OP_RETURN,
.OP_LIST_APPEND,
.OP_SET_MAP,
=> byteInstruction(instruction, chunk, offset),

.OP_OBJECT,
.OP_LIST,
.OP_MAP,
.OP_RANGE,
.OP_METHOD,
.OP_PROPERTY,
Expand Down
45 changes: 26 additions & 19 deletions src/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ pub const VM = struct {
self.current_fiber.stack_top -= 1;
return self.current_fiber.stack_top[0];
}

pub fn peek(self: *Self, distance: u32) Value {
return (self.current_fiber.stack_top - 1 - distance)[0];
}
Expand Down Expand Up @@ -2009,16 +2008,20 @@ pub const VM = struct {
);
}

fn OP_LIST_APPEND(self: *Self, _: *CallFrame, _: u32, _: OpCode, _: u24) void {
var list = self.peek(1).obj().access(ObjList, .List, self.gc).?;
const list_value = self.peek(0);
fn OP_LIST_APPEND(self: *Self, _: *CallFrame, _: u32, _: OpCode, item_count: u24) void {
var list = self.peek(item_count).obj().access(ObjList, .List, self.gc).?;

list.rawAppend(self.gc, list_value) catch {
self.panic("Out of memory");
unreachable;
};
var distance: i64 = @intCast(item_count - 1);
while (distance >= 0) : (distance -= 1) {
const item = self.peek(@intCast(distance));
list.rawAppend(self.gc, item) catch {
self.panic("Out of memory");
unreachable;
};
}

_ = self.pop();
// Pop items all at once
self.current_fiber.stack_top -= item_count;

const next_full_instruction: u32 = self.readInstruction();
@call(
Expand Down Expand Up @@ -2059,18 +2062,22 @@ pub const VM = struct {
);
}

fn OP_SET_MAP(self: *Self, _: *CallFrame, _: u32, _: OpCode, _: u24) void {
var map = self.peek(2).obj().access(ObjMap, .Map, self.gc).?;
const key = self.peek(1);
const value = self.peek(0);
fn OP_SET_MAP(self: *Self, _: *CallFrame, _: u32, _: OpCode, entries_count: u24) void {
var map = self.peek(entries_count * 2).obj().access(ObjMap, .Map, self.gc).?;

map.set(self.gc, key, value) catch {
self.panic("Out of memory");
unreachable;
};
var distance: i64 = @intCast((entries_count * 2) - 1);
while (distance >= 0) : (distance -= 2) {
const key = self.peek(@intCast(distance));
const value = self.peek(@intCast(distance - 1));

_ = self.pop();
_ = self.pop();
map.set(self.gc, key, value) catch {
self.panic("Out of memory");
unreachable;
};
}

// Pop entries all at once
self.current_fiber.stack_top -= entries_count * 2;

const next_full_instruction: u32 = self.readInstruction();
@call(
Expand Down
2 changes: 1 addition & 1 deletion tests/057-any.buzz
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ test "map of any" {
foreach (any key, any element in map3) {
std.print("{key}: {element}");
}
}
}
Loading