optimizing invocations
This commit is contained in:
parent
0bc5f495b9
commit
22ed27a931
17
samples/ch28_optimized_invocation.lox
Normal file
17
samples/ch28_optimized_invocation.lox
Normal file
@ -0,0 +1,17 @@
|
||||
class Oops {
|
||||
init() {
|
||||
fun f() {
|
||||
print "not a method";
|
||||
return "returned value from f";
|
||||
}
|
||||
this.field = f;
|
||||
}
|
||||
|
||||
blah() {
|
||||
return "returned value from blah";
|
||||
}
|
||||
}
|
||||
|
||||
var oops = Oops();
|
||||
print oops.field();
|
||||
print oops.blah();
|
@ -154,6 +154,7 @@ pub const Chunk = struct {
|
||||
@intFromEnum(OpCode.OP_METHOD) => return utils.constant_instruction("OP_METHOD", self, offset),
|
||||
@intFromEnum(OpCode.OP_INDEX_GET) => return utils.simple_instruction("OP_INDEX_GET", offset),
|
||||
@intFromEnum(OpCode.OP_INDEX_SET) => return utils.simple_instruction("OP_INDEX_SET", offset),
|
||||
@intFromEnum(OpCode.OP_INVOKE) => return utils.invoke_instruction("OP_INVOKE", self, offset),
|
||||
else => {
|
||||
debug.print("unknown opcode {d}\n", .{instruction});
|
||||
return offset + 1;
|
||||
|
@ -939,6 +939,10 @@ pub const Parser = struct {
|
||||
if (can_assign and self.match(TokenType.EQUAL)) {
|
||||
try self.expression();
|
||||
try self.emit_bytes(@intFromEnum(OpCode.OP_SET_PROPERTY), name);
|
||||
} else if (self.match(TokenType.LEFT_PAREN)) {
|
||||
const arg_count = try self.argument_list();
|
||||
try self.emit_bytes(@intFromEnum(OpCode.OP_INVOKE), name);
|
||||
try self.emit_byte(@intCast(arg_count));
|
||||
} else {
|
||||
try self.emit_bytes(@intFromEnum(OpCode.OP_GET_PROPERTY), name);
|
||||
}
|
||||
|
@ -34,4 +34,5 @@ pub const OpCode = enum(u8) {
|
||||
OP_METHOD,
|
||||
OP_INDEX_SET,
|
||||
OP_INDEX_GET,
|
||||
OP_INVOKE,
|
||||
};
|
||||
|
@ -55,3 +55,14 @@ pub fn identifiers_equals(a: Token, b: Token) bool {
|
||||
|
||||
return std.mem.eql(u8, a.start[0..a.length], b.start[0..b.length]);
|
||||
}
|
||||
|
||||
pub fn invoke_instruction(opcode_name: []const u8, chunk: Chunk, offset: usize) usize {
|
||||
const constant = chunk.code[offset + 1];
|
||||
const arg_count = chunk.code[offset + 2];
|
||||
|
||||
std.debug.print("{s:<16} ({d} args) {d:4} '", .{ opcode_name, arg_count, constant });
|
||||
chunk.constants.values[constant].print();
|
||||
std.debug.print("'\n", .{});
|
||||
|
||||
return offset + 3;
|
||||
}
|
||||
|
35
src/vm.zig
35
src/vm.zig
@ -372,6 +372,13 @@ pub const VM = struct {
|
||||
|
||||
_ = try self.push(Value.obj_val(&self.take_string(str).obj));
|
||||
},
|
||||
@intFromEnum(OpCode.OP_INVOKE) => {
|
||||
const method = self.read_constant().as_string();
|
||||
const arg_count = self.read_byte();
|
||||
if (!self.invoke(method, arg_count)) {
|
||||
return InterpretResult.RUNTIME_ERROR;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
debug.print("Invalid instruction: {d}\n", .{instruction});
|
||||
return InterpretResult.RUNTIME_ERROR;
|
||||
@ -586,9 +593,7 @@ pub const VM = struct {
|
||||
if (arg_count != closure.function.arity) {
|
||||
const err_msg = std.fmt.allocPrint(self.allocator, "Expected {d} arguments but got {d}.", .{ closure.function.arity, arg_count }) catch unreachable;
|
||||
defer self.allocator.free(err_msg);
|
||||
|
||||
self.runtime_error(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -659,4 +664,30 @@ pub const VM = struct {
|
||||
_ = class.methods.set(name, method);
|
||||
_ = self.pop();
|
||||
}
|
||||
|
||||
fn invoke(self: *VM, name: *Obj.String, arg_count: usize) bool {
|
||||
const receiver = self.peek(arg_count);
|
||||
const instance = receiver.as_obj().as_instance();
|
||||
|
||||
var value = Value.nil_val();
|
||||
if (instance.fields.get(name, &value)) {
|
||||
self.stack[self.stack_top - arg_count - 1] = value;
|
||||
|
||||
return self.call_value(value, arg_count);
|
||||
}
|
||||
|
||||
return self.invoke_from_class(instance.class, name, arg_count);
|
||||
}
|
||||
|
||||
fn invoke_from_class(self: *VM, class: *Obj.Class, name: *Obj.String, arg_count: usize) bool {
|
||||
var method = Value.nil_val();
|
||||
if (!class.methods.get(name, &method)) {
|
||||
const err_msg = std.fmt.allocPrint(self.allocator, "Undefined property '{s}'.", .{name.chars}) catch unreachable;
|
||||
defer self.allocator.free(err_msg);
|
||||
self.runtime_error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return self.call(method.as_obj().as_closure(), arg_count);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user