瀏覽代碼

closure upvalues for close upvalues

runningwater 2 年之前
父節點
當前提交
ef7973e334
共有 8 個文件被更改,包括 61 次插入12 次删除
  1. 1 0
      chunk.h
  2. 9 1
      compiler.c
  3. 1 0
      debug.c
  4. 2 0
      object.c
  5. 2 0
      object.h
  6. 13 10
      test/closures.lox
  7. 31 0
      vm.c
  8. 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;
 
 //============================================================================

+ 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 {

+ 13 - 10
test/closures.lox

@@ -1,11 +1,14 @@
-fun outer() {
-  var x = "outside";
-  fun inner() {
-    print x;
+{
+  var a = 1;
+  fun f() {
+    print a;
   }
-
-  return inner;
-}
-
-var closure = outer();
-closure();
+  var b = 2;
+  fun g() {
+    print b;
+  }
+  var c = 3;
+  fun h() {
+    print c;
+  }
+}

+ 31 - 0
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() {
@@ -326,8 +352,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();

+ 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,