Skip to content

Commit eb4e7c8

Browse files
committed
feat: capture upvalues and store them in vm
1 parent c028175 commit eb4e7c8

7 files changed

Lines changed: 62 additions & 6 deletions

File tree

src/chunk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef enum
3333
OP_LOOP,
3434
OP_CALL,
3535
OP_CLOSURE,
36+
OP_CLOSE_UPVALUE,
3637
OP_RETURN,
3738
} OpCode;
3839

src/compiler.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ typedef struct
5252
{
5353
Token name;
5454
int depth;
55+
bool is_captured;
5556
bool is_immutable;
5657
} Local;
5758

@@ -237,6 +238,8 @@ static void init_compiler(Compiler* compiler, FunctionType type)
237238

238239
Local* local = &current->locals[current->local_count++];
239240
local->depth = 0;
241+
local->is_captured = false;
242+
local->is_immutable = false;
240243
local->name.start = "";
241244
local->name.length = 0;
242245
}
@@ -270,7 +273,10 @@ static void end_scope()
270273
current->locals[current->local_count - 1].depth >
271274
current->scope_depth)
272275
{
273-
emit_byte(OP_POP);
276+
if (current->locals[current->local_count - 1].is_captured)
277+
emit_byte(OP_CLOSE_UPVALUE);
278+
else
279+
emit_byte(OP_POP);
274280
current->local_count--;
275281
}
276282
}
@@ -338,7 +344,10 @@ static int resolve_upvalue(Compiler* compiler, Token* name)
338344

339345
int local = resolve_local(compiler->enclosing, name);
340346
if (local != -1)
347+
{
348+
compiler->enclosing->locals[local].is_captured = true;
341349
return add_upvalue(compiler, (u8)local, true);
350+
}
342351

343352
int upvalue = resolve_upvalue(compiler->enclosing, name);
344353
if (upvalue != -1)
@@ -356,8 +365,9 @@ static void add_local(Token name, bool is_immutable)
356365
}
357366
Local* local = &current->locals[current->local_count++];
358367
local->name = name;
359-
local->is_immutable = is_immutable;
360368
local->depth = -1;
369+
local->is_captured = false;
370+
local->is_immutable = is_immutable;
361371
}
362372

363373
static void declare_variable(bool is_immutable)

src/debug.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ int disassemble_instruction(Chunk* chunk, int offset)
103103

104104
return offset;
105105
}
106+
case OP_CLOSE_UPVALUE:
107+
return simple_instruction("OP_CLOSE_UPVALUE", offset);
106108
case OP_RETURN:
107109
return simple_instruction("OP_RETURN", offset);
108110
default:

src/object.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ ObjUpvalue* new_upvalue(Value* slot)
113113
{
114114
ObjUpvalue* upvalue = ALLOCATE_OBJ(ObjUpvalue, OBJ_UPVALUE);
115115
upvalue->location = slot;
116+
upvalue->closed = NIL_VAL;
117+
upvalue->next = NULL;
116118
return upvalue;
117119
}
118120

src/object.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,12 @@ struct ObjString
6161
u32 hash;
6262
};
6363

64-
typedef struct
64+
typedef struct ObjUpvalue
6565
{
66-
Obj obj;
67-
Value* location;
66+
Obj obj;
67+
Value* location;
68+
Value closed;
69+
struct ObjUpvalue* next;
6870
} ObjUpvalue;
6971

7072
typedef struct

src/vm.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ static void reset_stack()
2020
{
2121
vm.stack_top = vm.stack;
2222
vm.frame_count = 0;
23+
vm.open_upvalues = NULL;
2324
}
2425

2526
static void runtime_error(const char* format, ...)
@@ -136,9 +137,39 @@ static bool call_value(Value callee, int arg_count)
136137
return false;
137138
}
138139

140+
static void close_upvalues(Value* last)
141+
{
142+
while (vm.open_upvalues != NULL && vm.open_upvalues->location >= last)
143+
{
144+
ObjUpvalue* upvalue = vm.open_upvalues;
145+
upvalue->closed = *upvalue->location;
146+
upvalue->location = &upvalue->closed;
147+
vm.open_upvalues->next = upvalue->next;
148+
}
149+
}
150+
139151
static ObjUpvalue* capture_upvalue(Value* local)
140152
{
153+
ObjUpvalue* prev_upvalue = NULL;
154+
ObjUpvalue* upvalue = vm.open_upvalues;
155+
156+
while (upvalue != NULL && upvalue->location > local)
157+
{
158+
prev_upvalue = upvalue;
159+
upvalue = upvalue->next;
160+
}
161+
162+
if (upvalue != NULL && upvalue->location == local)
163+
return upvalue;
164+
141165
ObjUpvalue* created_upvalue = new_upvalue(local);
166+
created_upvalue->next = upvalue;
167+
168+
if (prev_upvalue == NULL)
169+
vm.open_upvalues = created_upvalue;
170+
else
171+
prev_upvalue->next = created_upvalue;
172+
142173
return created_upvalue;
143174
}
144175

@@ -377,9 +408,16 @@ static InterpretResult run()
377408
}
378409
break;
379410
}
411+
case OP_CLOSE_UPVALUE:
412+
{
413+
close_upvalues(vm.stack_top - 1);
414+
pop();
415+
break;
416+
}
380417
case OP_RETURN:
381418
{
382419
Value result = pop();
420+
close_upvalues(frame->slots);
383421

384422
if (--vm.frame_count == 0)
385423
{

src/vm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ typedef struct
2525
Value* stack_top;
2626
Table globals;
2727
Table strings; // for string interning just like (string pool in java)
28-
Obj* objects;
28+
ObjUpvalue* open_upvalues;
29+
Obj* objects;
2930
} VM;
3031

3132
typedef enum

0 commit comments

Comments
 (0)