Skip to content

Commit 1f93e9c

Browse files
committed
feat(vm): Do list and map initialization in less op codes
closes #245
1 parent 4b8a805 commit 1f93e9c

File tree

5 files changed

+63
-64
lines changed

5 files changed

+63
-64
lines changed

src/Codegen.zig

+25-41
Original file line numberDiff line numberDiff line change
@@ -260,37 +260,6 @@ pub fn patchTryOrJit(self: *Self, offset: usize) void {
260260
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(jump));
261261
}
262262

263-
pub fn emitList(
264-
self: *Self,
265-
location: Ast.TokenIndex,
266-
) !usize {
267-
try self.emitCodeArg(location, .OP_LIST, 0xffffff);
268-
269-
return self.currentCode() - 1;
270-
}
271-
272-
pub fn patchList(self: *Self, offset: usize, constant: u24) !void {
273-
const original: u32 = self.current.?.function.?.chunk.code.items[offset];
274-
const instruction: u8 = @intCast(original >> 24);
275-
276-
self.current.?.function.?.chunk.code.items[offset] =
277-
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(constant));
278-
}
279-
280-
pub fn emitMap(self: *Self, location: Ast.TokenIndex) !usize {
281-
try self.emitCodeArg(location, .OP_MAP, 0xffffff);
282-
283-
return self.currentCode() - 1;
284-
}
285-
286-
pub fn patchMap(self: *Self, offset: usize, map_type_constant: u24) !void {
287-
const original: u32 = self.current.?.function.?.chunk.code.items[offset];
288-
const instruction: u8 = @intCast(original >> 24);
289-
290-
self.current.?.function.?.chunk.code.items[offset] =
291-
(@as(u32, @intCast(instruction)) << 24) | @as(u32, @intCast(map_type_constant));
292-
}
293-
294263
pub fn emitReturn(self: *Self, location: Ast.TokenIndex) !void {
295264
try self.emitOpCode(location, .OP_VOID);
296265
try self.emitOpCode(location, .OP_RETURN);
@@ -2623,7 +2592,12 @@ fn generateList(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize
26232592
const type_defs = self.ast.nodes.items(.type_def);
26242593

26252594
const item_type = type_defs[node].?.resolved_type.?.List.item_type;
2626-
const list_offset = try self.emitList(locations[node]);
2595+
2596+
try self.emitCodeArg(
2597+
locations[node],
2598+
.OP_LIST,
2599+
try self.makeConstant(Value.fromObj(type_defs[node].?.toObj())),
2600+
);
26272601

26282602
for (components.items) |item| {
26292603
if (item_type.def_type == .Placeholder) {
@@ -2639,13 +2613,16 @@ fn generateList(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize
26392613
);
26402614
} else {
26412615
_ = try self.generateNode(item, breaks);
2642-
2643-
try self.emitOpCode(locations[item], .OP_LIST_APPEND);
26442616
}
26452617
}
26462618

2647-
const list_type_constant = try self.makeConstant(Value.fromObj(type_defs[node].?.toObj()));
2648-
try self.patchList(list_offset, list_type_constant);
2619+
if (components.items.len > 0) {
2620+
try self.emitCodeArg(
2621+
locations[node],
2622+
.OP_LIST_APPEND,
2623+
@intCast(components.items.len),
2624+
);
2625+
}
26492626

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

2671-
const map_offset = try self.emitMap(locations[node]);
2648+
try self.emitCodeArg(
2649+
locations[node],
2650+
.OP_MAP,
2651+
try self.makeConstant(Value.fromObj(type_defs[node].?.toObj())),
2652+
);
26722653

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

2677-
try self.emitOpCode(locations[node], .OP_SET_MAP);
2678-
26792658
if (type_defs[entry.key].?.def_type == .Placeholder) {
26802659
self.reporter.reportPlaceholder(self.ast, type_defs[entry.key].?.resolved_type.?.Placeholder);
26812660
}
@@ -2707,8 +2686,13 @@ fn generateMap(self: *Self, node: Ast.Node.Index, breaks: ?*std.ArrayList(usize)
27072686
}
27082687
}
27092688

2710-
const map_type_constant = try self.makeConstant(Value.fromObj(type_defs[node].?.toObj()));
2711-
try self.patchMap(map_offset, map_type_constant);
2689+
if (components.entries.len > 0) {
2690+
try self.emitCodeArg(
2691+
locations[node],
2692+
.OP_SET_MAP,
2693+
@intCast(components.entries.len),
2694+
);
2695+
}
27122696

27132697
try self.patchOptJumps(node);
27142698
try self.endScope(node);

src/Parser.zig

+8
Original file line numberDiff line numberDiff line change
@@ -3345,6 +3345,10 @@ fn list(self: *Self, _: bool) Error!Ast.Node.Index {
33453345
}
33463346
}
33473347

3348+
if (items.items.len > std.math.maxInt(u24)) {
3349+
self.reportErrorAtCurrent(.syntax, "Too many elements in list initialization");
3350+
}
3351+
33483352
if (self.ast.tokens.items(.tag)[self.current_token.? - 1] != .RightBracket) {
33493353
self.reportErrorAtCurrent(.syntax, "Expected `]`");
33503354
}
@@ -3663,6 +3667,10 @@ fn map(self: *Self, _: bool) Error!Ast.Node.Index {
36633667
}
36643668
}
36653669

3670+
if (entries.items.len > std.math.maxInt(u24)) {
3671+
self.reportErrorAtCurrent(.syntax, "Too many entries in map initialization");
3672+
}
3673+
36663674
key_type_def = key_type_def orelse common_key_type;
36673675
value_type_def = value_type_def orelse common_value_type;
36683676
} else {

src/disassembler.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,6 @@ pub fn disassembleInstruction(chunk: *Chunk, offset: usize) usize {
227227
.OP_MOD,
228228
.OP_UNWRAP,
229229
.OP_GET_ENUM_CASE_VALUE,
230-
.OP_LIST_APPEND,
231-
.OP_SET_MAP,
232230
.OP_GET_LIST_SUBSCRIPT,
233231
.OP_GET_MAP_SUBSCRIPT,
234232
.OP_GET_STRING_SUBSCRIPT,
@@ -266,16 +264,18 @@ pub fn disassembleInstruction(chunk: *Chunk, offset: usize) usize {
266264
.OP_GET_UPVALUE,
267265
.OP_SET_UPVALUE,
268266
.OP_GET_ENUM_CASE,
269-
.OP_MAP,
270267
.OP_EXPORT,
271268
.OP_COPY,
272269
.OP_CLONE,
273270
.OP_CLOSE_UPVALUE,
274271
.OP_RETURN,
272+
.OP_LIST_APPEND,
273+
.OP_SET_MAP,
275274
=> byteInstruction(instruction, chunk, offset),
276275

277276
.OP_OBJECT,
278277
.OP_LIST,
278+
.OP_MAP,
279279
.OP_RANGE,
280280
.OP_METHOD,
281281
.OP_PROPERTY,

src/vm.zig

+26-19
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,6 @@ pub const VM = struct {
444444
self.current_fiber.stack_top -= 1;
445445
return self.current_fiber.stack_top[0];
446446
}
447-
448447
pub fn peek(self: *Self, distance: u32) Value {
449448
return (self.current_fiber.stack_top - 1 - distance)[0];
450449
}
@@ -2009,16 +2008,20 @@ pub const VM = struct {
20092008
);
20102009
}
20112010

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

2016-
list.rawAppend(self.gc, list_value) catch {
2017-
self.panic("Out of memory");
2018-
unreachable;
2019-
};
2014+
var distance: i64 = @intCast(item_count - 1);
2015+
while (distance >= 0) : (distance -= 1) {
2016+
const item = self.peek(@intCast(distance));
2017+
list.rawAppend(self.gc, item) catch {
2018+
self.panic("Out of memory");
2019+
unreachable;
2020+
};
2021+
}
20202022

2021-
_ = self.pop();
2023+
// Pop items all at once
2024+
self.current_fiber.stack_top -= item_count;
20222025

20232026
const next_full_instruction: u32 = self.readInstruction();
20242027
@call(
@@ -2059,18 +2062,22 @@ pub const VM = struct {
20592062
);
20602063
}
20612064

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

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

2072-
_ = self.pop();
2073-
_ = self.pop();
2073+
map.set(self.gc, key, value) catch {
2074+
self.panic("Out of memory");
2075+
unreachable;
2076+
};
2077+
}
2078+
2079+
// Pop entries all at once
2080+
self.current_fiber.stack_top -= entries_count * 2;
20742081

20752082
const next_full_instruction: u32 = self.readInstruction();
20762083
@call(

tests/057-any.buzz

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ test "map of any" {
6363
foreach (any key, any element in map3) {
6464
std.print("{key}: {element}");
6565
}
66-
}
66+
}

0 commit comments

Comments
 (0)