Skip to content

Commit

Permalink
feat(vm): Do list and map initialization in less op codes
Browse files Browse the repository at this point in the history
closes #245
  • Loading branch information
giann committed May 14, 2024
1 parent 4b8a805 commit 268c1bb
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 64 deletions.
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}");
}
}
}

0 comments on commit 268c1bb

Please sign in to comment.