瀏覽代碼

closure upvalues for close upvalues

runningwater 2 年之前
父節點
當前提交
eef8b30015
共有 9 個文件被更改,包括 66 次插入12 次删除
  1. 1 0
      chunk.h
  2. 2 1
      common.h
  3. 9 1
      compiler.c
  4. 1 0
      debug.c
  5. 2 0
      object.c
  6. 2 0
      object.h
  7. 9 8
      test/closures.lox
  8. 38 1
      vm.c
  9. 2 1
      vm.h

+ 1 - 0
chunk.h

@@ -44,6 +44,7 @@ typedef enum {
   OP_CALL,         /// <OP_CALL argCount>
   OP_RETURN,       ///<OP_RETURN>
   OP_CLOSURE,
+  OP_CLOSE_UPVALUE,
 } OpCode;
 
 //============================================================================

+ 2 - 1
common.h

@@ -13,7 +13,8 @@
 #include <string.h>
 
 #define DEBUG_PRINT_CODE
-//#define DEBUG_TRACE_EXECUTION
+#define DEBUG_TRACE_EXECUTION
+//#define DEBUG_STACK_INFO
 
 #define UINT8_COUNT (UINT8_MAX + 1)
 

+ 9 - 1
compiler.c

@@ -46,6 +46,7 @@ typedef struct {
 typedef struct {
   Token name;
   int depth;
+  bool isCaptured;
 } Local;
 typedef struct {
   uint8_t index;
@@ -435,7 +436,11 @@ static void endScope() {
 
   while (current->localCount > 0
          && current->locals[current->localCount - 1].depth > current->scopeDepth) {
-    emitByte(OP_POP);
+    if (current->locals[current->localCount - 1].isCaptured) {
+      emitByte(OP_CLOSE_UPVALUE);
+    } else {
+      emitByte(OP_POP);
+    }
     current->localCount--;
   }
 }
@@ -457,6 +462,7 @@ static void initCompiler(Compiler *compiler, FunctionType type) {
 
   Local *local = &current->locals[current->localCount++];
   local->depth = 0;
+  local->isCaptured = false;
   local->name.start = "";
   local->name.length = 0;
 }
@@ -555,6 +561,7 @@ static int resolveUpvalue(Compiler *compiler, Token *name) {
 
   int local = resolveLocal(compiler->enclosing, name);
   if (local != -1) {
+    compiler->enclosing->locals[local].isCaptured = true;
     return addUpvalue(compiler, (uint8_t) local, true);
   }
 
@@ -767,6 +774,7 @@ static void addLocal(Token name) {
   Local *local = &current->locals[current->localCount++];
   local->name = name;
   local->depth = -1;// 未初始化
+  local->isCaptured = false;
 }
 static void declareVariable() {
   if (current->scopeDepth == 0) return;

+ 1 - 0
debug.c

@@ -77,6 +77,7 @@ int disassembleInstruction(Chunk *chunk, int offset) {
     }
     case OP_GET_UPVALUE: return byteInstruction("OP_GET_UPVALUE", chunk, offset);
     case OP_SET_UPVALUE: return byteInstruction("OP_SET_UPVALUE", chunk, offset);
+    case OP_CLOSE_UPVALUE: return simpleInstruction("OP_CLOSE_UPVALUE", offset);
     case OP_RETURN: return simpleInstruction("OP_RETURN", offset);
     default:
       printf("Unknown opcode %d\n", instruction);

+ 2 - 0
object.c

@@ -109,7 +109,9 @@ ObjClosure *newClosure(ObjFunction *function) {
 }
 ObjUpvalue *newUpvalue(Value *slot) {
   ObjUpvalue *upvalue = ALLOCATE_OBJ(ObjUpvalue, OBJ_UPVALUE);
+  upvalue->closed = NIL_VAL;
   upvalue->location = slot;
+  upvalue->next = NULL;
   return upvalue;
 }
 /// 分配内存空间

+ 2 - 0
object.h

@@ -66,6 +66,8 @@ struct ObjString {
 typedef struct ObjUpvalue {
   struct Obj obj;
   Value *location;
+  Value closed;
+  struct ObjUpvalue *next;
 } ObjUpvalue;
 
 typedef struct {

+ 9 - 8
test/closures.lox

@@ -1,11 +1,12 @@
-fun outer() {
-  var x = "outside";
-  fun inner() {
-    print x;
-  }
+fun makeClosure() {
+  var a = "data";
 
-  return inner;
+  fun f() { print a; }
+  return f;
 }
 
-var closure = outer();
-closure();
+{
+  var closure = makeClosure();
+  // GC here.
+  closure();
+}

+ 38 - 1
vm.c

@@ -21,6 +21,7 @@ VM vm;
 static void resetStack() {
   vm.stackTop = vm.stack;// 指针指向栈底
   vm.frameCount = 0;
+  vm.openUpvalues = NULL;
 }
 
 static void runtimeError(const char *format, ...) {
@@ -125,9 +126,34 @@ static void concatenate() {
   push(OBJ_VAL(result));
 }
 static ObjUpvalue *captureUpvalue(Value *local) {
+  ObjUpvalue *preUpvalue = NULL;
+  ObjUpvalue *upvalue = vm.openUpvalues;
+  while (upvalue != NULL && upvalue->location > local) {
+    preUpvalue = upvalue;
+    upvalue = upvalue->next;
+  }
+
+  if (upvalue != NULL && upvalue->location == local) {
+    return upvalue;
+  }
+
   ObjUpvalue *createdUpvalue = newUpvalue(local);
+  if (preUpvalue == NULL) {
+    vm.openUpvalues = createdUpvalue;
+  } else {
+    preUpvalue->next = createdUpvalue;
+  }
   return createdUpvalue;
 }
+static void closeUpvalues(Value *last) {
+  while (vm.openUpvalues != NULL && vm.openUpvalues->location >= last) {
+    ObjUpvalue *upvalue = vm.openUpvalues;
+    upvalue->closed = *upvalue->location;
+    upvalue->location = &upvalue->closed;
+    vm.openUpvalues = upvalue->next;
+  }
+}
+
 /// VM run function - exec opcode
 /// \return
 static InterpretResult run() {
@@ -157,6 +183,7 @@ static InterpretResult run() {
 
   for (;;) {
 #ifdef DEBUG_TRACE_EXECUTION
+#ifdef DEBUG_STACK_INFO
     //! <Stack tracing> start
     printf("\n!!! <Stack tracing now>:\n");
     printf("------------------------\n|");
@@ -170,7 +197,7 @@ static InterpretResult run() {
     printf("\n");
     printf("\n");
     //! <Stack tracing> end
-
+#endif
     printf("The Instruction: \n");
     disassembleInstruction(&frame->closure->function->chunk, (int) (frame->ip - frame->closure->function->chunk.code));
 #endif
@@ -326,8 +353,13 @@ static InterpretResult run() {
         *frame->closure->upvalues[slot]->location = peek(0);
         break;
       }
+      case OP_CLOSE_UPVALUE:
+        closeUpvalues(vm.stackTop - 1);
+        pop();
+        break;
       case OP_RETURN: {
         Value result = pop();
+        closeUpvalues(frame->slots);
         vm.frameCount--;
         if (vm.frameCount == 0) {
           pop();
@@ -378,6 +410,11 @@ InterpretResult interpret(const char *source) {
 void push(Value value) {
   *vm.stackTop = value;
   vm.stackTop++;
+#ifdef DEBUG_TRACE_EXECUTION
+  printf("push stack: ");
+  printValue(value);
+  printf("\n");
+#endif
 }
 
 Value pop() {

+ 2 - 1
vm.h

@@ -32,7 +32,8 @@ typedef struct VM {
   Value *stackTop;// 栈指针
   Table globals;
   Table strings;//
-  Obj *objects; // 管理分配的 heap 内存
+  ObjUpvalue *openUpvalues;
+  Obj *objects;// 管理分配的 heap 内存
 } VM;
 typedef enum {
   INTERPRET_OK,