Skip to content

Commit a2d6cfa

Browse files
committed
chore: optimize method calls to be fast
1 parent 1078e83 commit a2d6cfa

4 files changed

Lines changed: 78 additions & 1 deletion

File tree

src/chunk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ typedef enum
3434
OP_JUMP_IF_FALSE,
3535
OP_LOOP,
3636
OP_CALL,
37+
OP_INVOKE,
3738
OP_CLOSURE,
3839
OP_CLOSE_UPVALUE,
3940
OP_RETURN,

src/compiler.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ typedef struct
6666
typedef enum
6767
{
6868
TYPE_FUNCTION,
69+
TYPE_INITIALIZER,
6970
TYPE_METHOD,
7071
TYPE_SCRIPT,
7172
} FunctionType;
@@ -201,7 +202,11 @@ static int emit_jump(u8 instruction)
201202

202203
static void emit_return()
203204
{
204-
emit_byte(OP_NIL);
205+
if (current->type == TYPE_INITIALIZER)
206+
emit_bytes(OP_GET_LOCAL, 0);
207+
else
208+
emit_byte(OP_NIL);
209+
205210
emit_byte(OP_RETURN);
206211
}
207212

@@ -525,6 +530,12 @@ static void dot(bool can_assign)
525530
expression();
526531
emit_bytes(OP_SET_PROPERTY, name);
527532
}
533+
else if (match(TOKEN_LEFT_PAREN))
534+
{
535+
u8 arg_count = arguments_list();
536+
emit_bytes(OP_INVOKE, name);
537+
emit_byte(arg_count);
538+
}
528539
else
529540
{
530541
emit_bytes(OP_GET_PROPERTY, name);
@@ -796,6 +807,9 @@ static void method()
796807
u8 constant = identifier_constant(&parser.previous);
797808

798809
FunctionType type = TYPE_METHOD;
810+
if (parser.previous.length == 4 && memcmp(parser.previous.start, "init", 4) == 0)
811+
type = TYPE_INITIALIZER;
812+
799813
function(type);
800814

801815
emit_bytes(OP_METHOD, constant);
@@ -953,6 +967,9 @@ static void return_statement()
953967
}
954968
else
955969
{
970+
if (current->type == TYPE_INITIALIZER)
971+
error("Can't return an a value from an initializer");
972+
956973
expression();
957974
consume(TOKEN_SEMICOLON, "Expect semicolon after return value;");
958975
emit_byte(OP_RETURN);

src/debug.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
static int simple_instruction(const char* name, int offset);
99
static int constant_instruction(const char* name, Chunk* chunk, int offset);
10+
static int invoke_instruction(const char* name, Chunk* chunk, int offset);
1011
static int byte_instruction(const char* name, Chunk* chunk, int offset);
1112
static int jump_instruction(const char* name, int sign, Chunk* chunk,
1213
int offset);
@@ -89,6 +90,8 @@ int disassemble_instruction(Chunk* chunk, int offset)
8990
return jump_instruction("OP_JUMP_IF_FALSE", -1, chunk, offset);
9091
case OP_CALL:
9192
return byte_instruction("OP_CALL", chunk, offset);
93+
case OP_INVOKE:
94+
return invoke_instruction("OP_INVOKE", chunk, offset);
9295
case OP_CLOSURE:
9396
{
9497
u8 constant = chunk->code[++offset];
@@ -152,6 +155,17 @@ static int constant_instruction(const char* name, Chunk* chunk, int offset)
152155
return offset + 2;
153156
}
154157

158+
static int invoke_instruction(const char* name, Chunk* chunk, int offset)
159+
{
160+
u8 constant = chunk->code[offset + 1];
161+
u8 arg_count = chunk->code[offset + 2];
162+
163+
printf("%-16s (%d args) %4d '", name, arg_count, constant);
164+
print_value(chunk->constants.values[constant]);
165+
printf("\n");
166+
return offset + 3;
167+
}
168+
155169
static const char* token_type_to_string(TokenType type)
156170
{
157171
switch (type)

src/vm.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <endian.h>
12
#include <linux/limits.h>
23
#include <stdarg.h>
34
#include <stdio.h>
@@ -168,6 +169,40 @@ static bool call_value(Value callee, int arg_count)
168169
return false;
169170
}
170171

172+
static bool invoke_from_class(ObjClass* klass, ObjString* name, int arg_count)
173+
{
174+
Value method;
175+
if (!table_get(&klass->methods, name, &method))
176+
{
177+
runtime_error("Undefined property '%s'.", name->chars);
178+
return false;
179+
}
180+
181+
return call(AS_CLOSURE(method), arg_count);
182+
}
183+
184+
static bool invoke(ObjString* name, int arg_count)
185+
{
186+
Value receiver = peek(arg_count);
187+
188+
if (!IS_INSTANCE(receiver))
189+
{
190+
runtime_error("Only class have methods");
191+
return false;
192+
}
193+
194+
ObjInstance* instance = AS_INSTANCE(receiver);
195+
196+
Value value;
197+
if (table_get(&instance->fields, name, &value))
198+
{
199+
vm.stack_top[-arg_count - 1] = value;
200+
return call_value(value, arg_count);
201+
}
202+
203+
return invoke_from_class(instance->klass, name, arg_count);
204+
}
205+
171206
static bool bind_method(ObjClass* klass, ObjString* name)
172207
{
173208
Value method;
@@ -488,6 +523,16 @@ static InterpretResult run()
488523
frame = &vm.frames[vm.frame_count - 1];
489524
break;
490525
}
526+
case OP_INVOKE:
527+
{
528+
ObjString* method = READ_STRING();
529+
int arg_count = READ_BYTE();
530+
if (!invoke(method, arg_count))
531+
return INTERPRET_RUNTIME_ERROR;
532+
533+
frame = &vm.frames[vm.frame_count - 1];
534+
break;
535+
}
491536
case OP_CLOSURE:
492537
{
493538
ObjFunction* function = AS_FUNCTION(READ_CONSTANT());

0 commit comments

Comments
 (0)