diff --git a/src/compiler.c b/src/compiler.c index 41423e8..6e0d826 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1158,21 +1158,45 @@ static void beginScope(void) { static void endScope(void) { current->scopeDepth--; + + int closeCount = 0; + int popCount = 0; + while (current->localCount > 0 && current->locals[current->localCount - 1].depth > (ssize_t)current->scopeDepth) { + if (current->locals[current->localCount - 1].isCaptured) { + if (popCount) { + if (popCount == 1) emitByte(OP_POP); + else { EMIT_OPERAND_OP(OP_POP_MANY, popCount); } + popCount = 0; + } + closeCount++; + } else { + if (closeCount) { + if (closeCount == 1) emitByte(OP_CLOSE_UPVALUE); + else { EMIT_OPERAND_OP(OP_CLOSE_MANY, closeCount); } + closeCount = 0; + } + popCount++; + } + for (size_t i = 0; i < current->codeobject->localNameCount; i++) { if (current->codeobject->localNames[i].id == current->localCount - 1 && current->codeobject->localNames[i].deathday == 0) { current->codeobject->localNames[i].deathday = (size_t)currentChunk()->count; } } - if (current->locals[current->localCount - 1].isCaptured) { - emitByte(OP_CLOSE_UPVALUE); - } else { - emitByte(OP_POP); - } current->localCount--; } + + if (popCount) { + if (popCount == 1) emitByte(OP_POP); + else { EMIT_OPERAND_OP(OP_POP_MANY, popCount); } + } + if (closeCount) { + if (closeCount == 1) emitByte(OP_CLOSE_UPVALUE); + else { EMIT_OPERAND_OP(OP_CLOSE_MANY, closeCount); } + } } static void block(size_t indentation, const char * blockName) { diff --git a/src/kuroko/chunk.h b/src/kuroko/chunk.h index 4e71693..f97cf0d 100644 --- a/src/kuroko/chunk.h +++ b/src/kuroko/chunk.h @@ -107,6 +107,8 @@ typedef enum { OP_SLICE, OP_GET_METHOD, OP_CALL_METHOD, + OP_CLOSE_MANY, + OP_POP_MANY, /* Two opcode instructions */ OP_JUMP_IF_FALSE_OR_POP, @@ -156,6 +158,8 @@ typedef enum { OP_SLICE_LONG, OP_GET_METHOD_LONG, OP_CALL_METHOD_LONG, + OP_CLOSE_MANY_LONG, + OP_POP_MANY_LONG, } KrkOpCode; /** diff --git a/src/opcodes.h b/src/opcodes.h index 60defbd..e4e5ef1 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -79,6 +79,8 @@ OPERAND(OP_MAKE_SET, (void)0) OPERAND(OP_REVERSE, (void)0) OPERAND(OP_SLICE, (void)0) OPERAND(OP_CALL_METHOD, (void)0) +OPERAND(OP_CLOSE_MANY, (void)0) +OPERAND(OP_POP_MANY, (void)0) JUMP(OP_JUMP_IF_FALSE_OR_POP,+) JUMP(OP_JUMP_IF_TRUE_OR_POP,+) JUMP(OP_JUMP,+) diff --git a/src/vm.c b/src/vm.c index 0943a32..fbb8bb8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2982,6 +2982,25 @@ _finishReturn: (void)0; krk_push(KWARGS_VAL(OPERAND)); break; } + case OP_CLOSE_MANY_LONG: + THREE_BYTE_OPERAND; + case OP_CLOSE_MANY: { + ONE_BYTE_OPERAND; + for (int i = 0; i < OPERAND; ++i) { + closeUpvalues((krk_currentThread.stackTop - krk_currentThread.stack)-1); + krk_pop(); + } + break; + } + case OP_POP_MANY_LONG: + THREE_BYTE_OPERAND; + case OP_POP_MANY: { + ONE_BYTE_OPERAND; + for (int i = 0; i < OPERAND; ++i) { + krk_pop(); + } + break; + } #define doMake(func) { \ size_t count = OPERAND; \ krk_reserve_stack(4); \