diff --git a/src/Codegen.zig b/src/Codegen.zig index 96a3bba3..9cfc4166 100644 --- a/src/Codegen.zig +++ b/src/Codegen.zig @@ -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); @@ -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) { @@ -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); @@ -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); } @@ -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); diff --git a/src/Parser.zig b/src/Parser.zig index 51aad46b..827c28cb 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -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 `]`"); } @@ -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 { diff --git a/src/disassembler.zig b/src/disassembler.zig index f1a8fd6f..c10dce64 100644 --- a/src/disassembler.zig +++ b/src/disassembler.zig @@ -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, @@ -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, diff --git a/src/vm.zig b/src/vm.zig index fb4e6b91..26784134 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -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]; } @@ -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( @@ -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( diff --git a/tests/057-any.buzz b/tests/057-any.buzz index b06a917b..f0219597 100644 --- a/tests/057-any.buzz +++ b/tests/057-any.buzz @@ -63,4 +63,4 @@ test "map of any" { foreach (any key, any element in map3) { std.print("{key}: {element}"); } -} \ No newline at end of file +}