Skip to content

Commit

Permalink
feat(obj): Store properties and methods in a slice rather than a hashmap
Browse files Browse the repository at this point in the history
closes #90

We never needed to known the property name at runtime, this is an artifact of the 'Crafting Interpreters' heritage.

This results in a performance boost of about 40% on some benches:

Before:
→ hyperfine --warmup 10 'buzz tests/bench/001-btree.buzz 15
Benchmark 1: buzz tests/bench/001-btree.buzz 15
  Time (mean ± σ):      1.221 s ±  0.022 s    [User: 1.028 s, System: 0.174 s]
  Range (min … max):    1.195 s …  1.271 s    10 runs

After:
→ hyperfine --warmup 10 'buzz tests/bench/001-btree.buzz 15
Benchmark 1: buzz tests/bench/001-btree.buzz 15
  Time (mean ± σ):     795.5 ms ±   7.7 ms    [User: 725.1 ms, System: 62.9 ms]
  Range (min … max):   785.3 ms … 811.7 ms    10 runs
  • Loading branch information
giann committed Jun 12, 2024
1 parent 468d114 commit 11ec46a
Show file tree
Hide file tree
Showing 23 changed files with 2,079 additions and 1,339 deletions.
4 changes: 2 additions & 2 deletions src/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ pub fn toValue(self: Self, node: Node.Index, gc: *GarbageCollector) Error!Value

var list = try gc.allocateObject(
obj.ObjList,
obj.ObjList.init(gc.allocator, type_def.?),
try obj.ObjList.init(gc.allocator, type_def.?),
);

for (components.items) |item| {
Expand All @@ -1156,7 +1156,7 @@ pub fn toValue(self: Self, node: Node.Index, gc: *GarbageCollector) Error!Value

var map = try gc.allocateObject(
obj.ObjMap,
obj.ObjMap.init(gc.allocator, type_def.?),
try obj.ObjMap.init(gc.allocator, type_def.?),
);

for (components.entries) |entry| {
Expand Down
9 changes: 7 additions & 2 deletions src/Chunk.zig
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ pub const OpCode = enum(u8) {

OP_CALL,
OP_TAIL_CALL,
OP_CALL_INSTANCE_PROPERTY,
OP_TAIL_CALL_INSTANCE_PROPERTY,
OP_INSTANCE_INVOKE,
OP_INSTANCE_TAIL_INVOKE,
OP_PROTOCOL_INVOKE,
OP_PROTOCOL_TAIL_INVOKE,
OP_STRING_INVOKE,
OP_PATTERN_INVOKE,
OP_FIBER_INVOKE,
Expand All @@ -80,7 +84,6 @@ pub const OpCode = enum(u8) {
OP_CLOSE_UPVALUE,

OP_FIBER,
OP_INVOKE_FIBER,
OP_RESUME,
OP_RESOLVE,
OP_YIELD,
Expand All @@ -94,10 +97,12 @@ pub const OpCode = enum(u8) {
OP_OBJECT,
OP_INSTANCE,
OP_FCONTAINER_INSTANCE,
OP_METHOD,
OP_PROPERTY,
OP_OBJECT_DEFAULT,
OP_GET_OBJECT_PROPERTY,
OP_GET_INSTANCE_PROPERTY,
OP_GET_INSTANCE_METHOD,
OP_GET_PROTOCOL_METHOD,
OP_GET_FCONTAINER_INSTANCE_PROPERTY,
OP_GET_LIST_PROPERTY,
OP_GET_MAP_PROPERTY,
Expand Down
250 changes: 139 additions & 111 deletions src/Codegen.zig

Large diffs are not rendered by default.

212 changes: 163 additions & 49 deletions src/Jit.zig

Large diffs are not rendered by default.

70 changes: 55 additions & 15 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1825,35 +1825,52 @@ fn resolvePlaceholderWithRelation(
.List => {
std.debug.assert(child_placeholder.name != null);

if (try obj.ObjList.ListDef.member(resolved_type, self, child_placeholder.name.?.string)) |member| {
if (try obj.ObjList.ListDef.member(
resolved_type,
self,
child_placeholder.name.?.string,
)) |member| {
try self.resolvePlaceholder(child, member, false);
}
},
.Map => {
std.debug.assert(child_placeholder.name != null);

if (try obj.ObjMap.MapDef.member(resolved_type, self, child_placeholder.name.?.string)) |member| {
if (try obj.ObjMap.MapDef.member(
resolved_type,
self,
child_placeholder.name.?.string,
)) |member| {
try self.resolvePlaceholder(child, member, false);
}
},
.String => {
std.debug.assert(child_placeholder.name != null);

if (try obj.ObjString.memberDef(self, child_placeholder.name.?.string)) |member| {
if (try obj.ObjString.memberDefByName(
self,
child_placeholder.name.?.string,
)) |member| {
try self.resolvePlaceholder(child, member, false);
}
},
.Pattern => {
std.debug.assert(child_placeholder.name != null);

if (try obj.ObjPattern.memberDef(self, child_placeholder.name.?.string)) |member| {
if (try obj.ObjPattern.memberDefByName(
self,
child_placeholder.name.?.string,
)) |member| {
try self.resolvePlaceholder(child, member, false);
}
},
.Fiber => {
std.debug.assert(child_placeholder.name != null);

if (try obj.ObjFiber.memberDef(self, child_placeholder.name.?.string)) |member| {
if (try obj.ObjFiber.memberDefByName(
self,
child_placeholder.name.?.string,
)) |member| {
try self.resolvePlaceholder(child, member, false);
}
},
Expand Down Expand Up @@ -3007,7 +3024,8 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString
var tuple_index: u8 = 0;
var obj_is_tuple = false;
var obj_is_not_tuple = false;
while (!self.check(.RightBrace) and !self.check(.Eof)) {
var property_idx: usize = 0;
while (!self.check(.RightBrace) and !self.check(.Eof)) : (property_idx += 1) {
const constant = try self.match(.Const);

const property_type = try self.parseTypeDef(generic_types, true);
Expand Down Expand Up @@ -3075,6 +3093,7 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString
.static = false,
.method = false,
.has_default = false,
.index = property_idx,
},
);
try field_names.put(property_name_lexeme, {});
Expand Down Expand Up @@ -3920,7 +3939,8 @@ fn anonymousObjectInit(self: *Self, _: bool) Error!Ast.Node.Index {
var tuple_index: u8 = 0;
var obj_is_tuple = false;
var obj_is_not_tuple = false;
while (!self.check(.RightBrace) and !self.check(.Eof)) {
var property_idx: usize = 0;
while (!self.check(.RightBrace) and !self.check(.Eof)) : (property_idx += 1) {
// Unnamed: this expression is a little bit tricky:
// - either an identifier followed by something other than =
// - or not an identifier
Expand Down Expand Up @@ -3992,6 +4012,7 @@ fn anonymousObjectInit(self: *Self, _: bool) Error!Ast.Node.Index {
.method = false,
.constant = false,
.has_default = false,
.index = property_idx,
},
);
} else {
Expand Down Expand Up @@ -4042,6 +4063,7 @@ fn anonymousObjectInit(self: *Self, _: bool) Error!Ast.Node.Index {
.method = false,
.constant = false,
.has_default = false,
.index = property_idx,
},
);
}
Expand Down Expand Up @@ -4103,7 +4125,7 @@ fn dot(self: *Self, can_assign: bool, callee: Ast.Node.Index) Error!Ast.Node.Ind
const callee_def_type = callee_type_def.?.def_type;
switch (callee_def_type) {
.String => {
if (try obj.ObjString.memberDef(self, member_name)) |member_type_def| {
if (try obj.ObjString.memberDefByName(self, member_name)) |member_type_def| {
const generic_resolve = if (try self.match(.DoubleColon))
try self.parseGenericResolve(member_type_def, null)
else
Expand Down Expand Up @@ -4143,7 +4165,7 @@ fn dot(self: *Self, can_assign: bool, callee: Ast.Node.Index) Error!Ast.Node.Ind
}
},
.Range => {
if (try obj.ObjRange.memberDef(self, member_name)) |member_type_def| {
if (try obj.ObjRange.memberDefByName(self, member_name)) |member_type_def| {
const generic_resolve = if (try self.match(.DoubleColon))
try self.parseGenericResolve(member_type_def, null)
else
Expand Down Expand Up @@ -4178,15 +4200,12 @@ fn dot(self: *Self, can_assign: bool, callee: Ast.Node.Index) Error!Ast.Node.Ind
self.ast.nodes.items(.components)[dot_node].Dot.member_kind = .Ref;
self.ast.nodes.items(.type_def)[dot_node] = member;
}
} else if (std.mem.eql(u8, member_name, "high") or std.mem.eql(u8, member_name, "low")) {
self.ast.nodes.items(.components)[dot_node].Dot.member_kind = .Ref;
self.ast.nodes.items(.type_def)[dot_node] = self.gc.type_registry.int_type;
} else {
self.reportError(.property_does_not_exists, "Range property doesn't exist.");
}
},
.Pattern => {
if (try obj.ObjPattern.memberDef(self, member_name)) |member_type_def| {
if (try obj.ObjPattern.memberDefByName(self, member_name)) |member_type_def| {
const generic_resolve = if (try self.match(.DoubleColon))
try self.parseGenericResolve(member_type_def, null)
else
Expand Down Expand Up @@ -4226,7 +4245,7 @@ fn dot(self: *Self, can_assign: bool, callee: Ast.Node.Index) Error!Ast.Node.Ind
}
},
.Fiber => {
if (try obj.ObjFiber.memberDef(self, member_name)) |member_type_def| {
if (try obj.ObjFiber.memberDefByName(self, member_name)) |member_type_def| {
const generic_resolve = if (try self.match(.DoubleColon))
try self.parseGenericResolve(member_type_def, null)
else
Expand Down Expand Up @@ -6335,6 +6354,8 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index {
var properties_type = std.StringHashMap(*obj.ObjTypeDef).init(self.gc.allocator);

// Docblocks
var property_idx: usize = 0;
var static_property_idx: usize = 0;
while (!self.check(.RightBrace) and !self.check(.Eof)) {
const docblock = if (try self.match(.Docblock))
self.current_token.? - 1
Expand Down Expand Up @@ -6403,9 +6424,19 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index {
.location = self.ast.tokens.get(method_token),
.method = true,
.has_default = false,
.index = if (static)
static_property_idx
else
property_idx,
},
);

if (static) {
static_property_idx += 1;
} else {
property_idx += 1;
}

try members.append(
.{
.name = method_token,
Expand Down Expand Up @@ -6507,9 +6538,19 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index {
.location = property_name,
.method = false,
.has_default = default != null,
.index = if (static)
static_property_idx
else
property_idx,
},
);

if (static) {
static_property_idx += 1;
} else {
property_idx += 1;
}

try members.append(
.{
.name = property_token,
Expand Down Expand Up @@ -8444,7 +8485,6 @@ fn returnStatement(self: *Self) Error!Ast.Node.Index {
if (value) |uvalue| {
try self.consume(.Semicolon, "Expected `;` after statement.");

// Tail call (TODO: do it for dot call)
if (self.ast.nodes.items(.tag)[uvalue] == .Call) {
self.ast.nodes.items(.components)[uvalue].Call.tail_call = true;
} else if (self.ast.nodes.items(.tag)[uvalue] == .Dot and self.ast.nodes.items(.components)[uvalue].Dot.member_kind == .Call) {
Expand Down
29 changes: 24 additions & 5 deletions src/builtin/list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ pub fn reverse(ctx: *NativeCtx) c_int {

var new_list = ctx.vm.gc.allocateObject(
ObjList,
ObjList.init(ctx.vm.gc.allocator, list.type_def),
ObjList.init(ctx.vm.gc.allocator, list.type_def) catch {
ctx.vm.panic("Out of memory");
unreachable;
},
) catch {
ctx.vm.panic("Out of memory");
unreachable;
Expand Down Expand Up @@ -181,7 +184,10 @@ pub fn clone(ctx: *NativeCtx) c_int {

var new_list = ctx.vm.gc.allocateObject(
ObjList,
ObjList.init(ctx.vm.gc.allocator, self.type_def),
ObjList.init(ctx.vm.gc.allocator, self.type_def) catch {
ctx.vm.panic("Out of memory");
unreachable;
},
) catch {
ctx.vm.panic("Out of memory");
unreachable;
Expand Down Expand Up @@ -247,11 +253,18 @@ pub fn sub(ctx: *NativeCtx) c_int {
self.items.items.len;
const substr = self.items.items[@intCast(start)..limit];

var methods = std.ArrayList(?*_obj.ObjNative)
.fromOwnedSlice(ctx.vm.gc.allocator, self.methods)
.clone() catch {
ctx.vm.panic("Out of memory");
unreachable;
};

var list = ctx.vm.gc.allocateObject(
ObjList,
.{
.type_def = self.type_def,
.methods = self.methods.clone() catch {
.methods = methods.toOwnedSlice() catch {
ctx.vm.panic("Out of memory");
unreachable;
},
Expand Down Expand Up @@ -355,7 +368,10 @@ pub fn filter(ctx: *NativeCtx) c_int {
ObjList.init(
ctx.vm.gc.allocator,
list.type_def,
),
) catch {
ctx.vm.panic("Out of memory");
unreachable;
},
) catch {
ctx.vm.panic("Out of memory");
unreachable;
Expand Down Expand Up @@ -396,7 +412,10 @@ pub fn map(ctx: *NativeCtx) c_int {
ObjList.init(
ctx.vm.gc.allocator,
mapped_type,
),
) catch {
ctx.vm.panic("Out of memory");
unreachable;
},
) catch {
ctx.vm.panic("Out of memory");
unreachable;
Expand Down
Loading

0 comments on commit 11ec46a

Please sign in to comment.