From dd4691649a77d80adf40ab313b22f1ec7fb0b009 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Sun, 22 Mar 2015 12:22:47 -0700 Subject: [PATCH] Convert Compiler and ObjList to both use ValueBuffer for their arrays. --- src/vm/wren_compiler.c | 30 +++++++--------- src/vm/wren_core.c | 37 ++++++++++--------- src/vm/wren_value.c | 81 ++++++++++++++++-------------------------- src/vm/wren_value.h | 17 ++++----- 4 files changed, 67 insertions(+), 98 deletions(-) diff --git a/src/vm/wren_compiler.c b/src/vm/wren_compiler.c index 258a2f65..94764156 100644 --- a/src/vm/wren_compiler.c +++ b/src/vm/wren_compiler.c @@ -235,7 +235,7 @@ struct sCompiler struct sCompiler* parent; // The constants that have been defined in this function so far. - ObjList* constants; + ValueBuffer constants; // The currently in scope local variables. Local locals[MAX_LOCALS]; @@ -334,9 +334,11 @@ static void error(Compiler* compiler, const char* format, ...) // Adds [constant] to the constant pool and returns its index. static int addConstant(Compiler* compiler, Value constant) { - if (compiler->constants->count < MAX_CONSTANTS) + if (compiler->constants.count < MAX_CONSTANTS) { - wrenListAdd(compiler->parser->vm, compiler->constants, constant); + if (IS_OBJ(constant)) wrenPushRoot(compiler->parser->vm, AS_OBJ(constant)); + wrenValueBufferWrite(compiler->parser->vm, &compiler->constants, constant); + if (IS_OBJ(constant)) wrenPopRoot(compiler->parser->vm); } else { @@ -344,7 +346,7 @@ static int addConstant(Compiler* compiler, Value constant) MAX_CONSTANTS); } - return compiler->constants->count - 1; + return compiler->constants.count - 1; } // Initializes [compiler]. @@ -356,7 +358,7 @@ static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent, // Initialize this to NULL before allocating in case a GC gets triggered in // the middle of initializing the compiler. - compiler->constants = NULL; + wrenValueBufferInit(parser->vm, &compiler->constants); compiler->numUpvalues = 0; compiler->numParams = 0; @@ -365,9 +367,6 @@ static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent, wrenSetCompiler(parser->vm, compiler); - // Create a growable list for the constants used by this function. - compiler->constants = wrenNewList(parser->vm, 0); - if (parent == NULL) { compiler->numLocals = 0; @@ -1305,8 +1304,8 @@ static ObjFn* endCompiler(Compiler* compiler, // Create a function object for the code we just compiled. ObjFn* fn = wrenNewFunction(compiler->parser->vm, compiler->parser->module, - compiler->constants->elements, - compiler->constants->count, + compiler->constants.data, + compiler->constants.count, compiler->numUpvalues, compiler->numParams, compiler->bytecode.data, @@ -2686,7 +2685,7 @@ static void endLoop(Compiler* compiler) { // Skip this instruction and its arguments. i += 1 + getNumArguments(compiler->bytecode.data, - compiler->constants->elements, i); + compiler->constants.data, i); } } @@ -3234,13 +3233,10 @@ void wrenMarkCompiler(WrenVM* vm, Compiler* compiler) // Walk up the parent chain to mark the outer compilers too. The VM only // tracks the innermost one. - while (compiler != NULL) + do { - if (compiler->constants != NULL) - { - wrenMarkObj(vm, (Obj*)compiler->constants); - } - + wrenMarkBuffer(vm, &compiler->constants); compiler = compiler->parent; } + while (compiler != NULL); } diff --git a/src/vm/wren_core.c b/src/vm/wren_core.c index 51992aab..efa36a1d 100644 --- a/src/vm/wren_core.c +++ b/src/vm/wren_core.c @@ -666,23 +666,19 @@ DEF_PRIMITIVE(list_instantiate) DEF_PRIMITIVE(list_add) { - wrenListAdd(vm, AS_LIST(args[0]), args[1]); + wrenValueBufferWrite(vm, &AS_LIST(args[0])->elements, args[1]); RETURN_VAL(args[1]); } DEF_PRIMITIVE(list_clear) { - ObjList* list = AS_LIST(args[0]); - DEALLOCATE(vm, list->elements); - list->elements = NULL; - list->capacity = 0; - list->count = 0; + wrenValueBufferClear(vm, &AS_LIST(args[0])->elements); RETURN_NULL; } DEF_PRIMITIVE(list_count) { - RETURN_NUM(AS_LIST(args[0])->count); + RETURN_NUM(AS_LIST(args[0])->elements.count); } DEF_PRIMITIVE(list_insert) @@ -690,7 +686,8 @@ DEF_PRIMITIVE(list_insert) ObjList* list = AS_LIST(args[0]); // count + 1 here so you can "insert" at the very end. - uint32_t index = validateIndex(vm, args, list->count + 1, 1, "Index"); + uint32_t index = validateIndex(vm, args, list->elements.count + 1, 1, + "Index"); if (index == UINT32_MAX) return PRIM_ERROR; wrenListInsert(vm, list, args[2], index); @@ -704,7 +701,7 @@ DEF_PRIMITIVE(list_iterate) // If we're starting the iteration, return the first index. if (IS_NULL(args[1])) { - if (list->count == 0) RETURN_FALSE; + if (list->elements.count == 0) RETURN_FALSE; RETURN_NUM(0); } @@ -712,7 +709,7 @@ DEF_PRIMITIVE(list_iterate) // Stop if we're out of bounds. double index = AS_NUM(args[1]); - if (index < 0 || index >= list->count - 1) RETURN_FALSE; + if (index < 0 || index >= list->elements.count - 1) RETURN_FALSE; // Otherwise, move to the next index. RETURN_NUM(index + 1); @@ -721,16 +718,16 @@ DEF_PRIMITIVE(list_iterate) DEF_PRIMITIVE(list_iteratorValue) { ObjList* list = AS_LIST(args[0]); - uint32_t index = validateIndex(vm, args, list->count, 1, "Iterator"); + uint32_t index = validateIndex(vm, args, list->elements.count, 1, "Iterator"); if (index == UINT32_MAX) return PRIM_ERROR; - RETURN_VAL(list->elements[index]); + RETURN_VAL(list->elements.data[index]); } DEF_PRIMITIVE(list_removeAt) { ObjList* list = AS_LIST(args[0]); - uint32_t index = validateIndex(vm, args, list->count, 1, "Index"); + uint32_t index = validateIndex(vm, args, list->elements.count, 1, "Index"); if (index == UINT32_MAX) return PRIM_ERROR; RETURN_VAL(wrenListRemoveAt(vm, list, index)); @@ -742,10 +739,11 @@ DEF_PRIMITIVE(list_subscript) if (IS_NUM(args[1])) { - uint32_t index = validateIndex(vm, args, list->count, 1, "Subscript"); + uint32_t index = validateIndex(vm, args, list->elements.count, 1, + "Subscript"); if (index == UINT32_MAX) return PRIM_ERROR; - RETURN_VAL(list->elements[index]); + RETURN_VAL(list->elements.data[index]); } if (!IS_RANGE(args[1])) @@ -754,14 +752,14 @@ DEF_PRIMITIVE(list_subscript) } int step; - uint32_t count = list->count; + uint32_t count = list->elements.count; uint32_t start = calculateRange(vm, args, AS_RANGE(args[1]), &count, &step); if (start == UINT32_MAX) return PRIM_ERROR; ObjList* result = wrenNewList(vm, count); for (uint32_t i = 0; i < count; i++) { - result->elements[i] = list->elements[start + (i * step)]; + result->elements.data[i] = list->elements.data[start + (i * step)]; } RETURN_OBJ(result); @@ -770,10 +768,11 @@ DEF_PRIMITIVE(list_subscript) DEF_PRIMITIVE(list_subscriptSetter) { ObjList* list = AS_LIST(args[0]); - uint32_t index = validateIndex(vm, args, list->count, 1, "Subscript"); + uint32_t index = validateIndex(vm, args, list->elements.count, 1, + "Subscript"); if (index == UINT32_MAX) return PRIM_ERROR; - list->elements[index] = args[2]; + list->elements.data[index] = args[2]; RETURN_VAL(args[2]); } diff --git a/src/vm/wren_value.c b/src/vm/wren_value.c index 3cee56c0..b4bda8c4 100644 --- a/src/vm/wren_value.c +++ b/src/vm/wren_value.c @@ -245,80 +245,55 @@ ObjList* wrenNewList(WrenVM* vm, uint32_t numElements) ObjList* list = ALLOCATE(vm, ObjList); initObj(vm, &list->obj, OBJ_LIST, vm->listClass); - list->capacity = numElements; - list->count = numElements; - list->elements = elements; + list->elements.capacity = numElements; + list->elements.count = numElements; + list->elements.data = elements; return list; } -// Grows [list] if needed to ensure it can hold one more element. -static void ensureListCapacity(WrenVM* vm, ObjList* list) -{ - if (list->capacity >= list->count + 1) return; - - uint32_t capacity = list->capacity * GROW_FACTOR; - if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; - - list->capacity = capacity; - list->elements = (Value*)wrenReallocate(vm, list->elements, - list->capacity * sizeof(Value), capacity * sizeof(Value)); - // TODO: Handle allocation failure. - list->capacity = capacity; -} - -void wrenListAdd(WrenVM* vm, ObjList* list, Value value) -{ - if (IS_OBJ(value)) wrenPushRoot(vm, AS_OBJ(value)); - - ensureListCapacity(vm, list); - - if (IS_OBJ(value)) wrenPopRoot(vm); - - list->elements[list->count++] = value; -} - void wrenListInsert(WrenVM* vm, ObjList* list, Value value, uint32_t index) { if (IS_OBJ(value)) wrenPushRoot(vm, AS_OBJ(value)); - ensureListCapacity(vm, list); + // Add a slot at the end of the list. + wrenValueBufferWrite(vm, &list->elements, NULL_VAL); if (IS_OBJ(value)) wrenPopRoot(vm); - // Shift items down. - for (uint32_t i = list->count; i > index; i--) + // Shift the existing elements down. + for (uint32_t i = list->elements.count - 1; i > index; i--) { - list->elements[i] = list->elements[i - 1]; + list->elements.data[i] = list->elements.data[i - 1]; } - list->elements[index] = value; - list->count++; + // Store the new element. + list->elements.data[index] = value; } Value wrenListRemoveAt(WrenVM* vm, ObjList* list, uint32_t index) { - Value removed = list->elements[index]; + Value removed = list->elements.data[index]; if (IS_OBJ(removed)) wrenPushRoot(vm, AS_OBJ(removed)); // Shift items up. - for (uint32_t i = index; i < list->count - 1; i++) + for (int i = index; i < list->elements.count - 1; i++) { - list->elements[i] = list->elements[i + 1]; + list->elements.data[i] = list->elements.data[i + 1]; } // If we have too much excess capacity, shrink it. - if (list->capacity / GROW_FACTOR >= list->count) + if (list->elements.capacity / GROW_FACTOR >= list->elements.count) { - list->elements = (Value*)wrenReallocate(vm, list->elements, - sizeof(Value) * list->capacity, - sizeof(Value) * (list->capacity / GROW_FACTOR)); - list->capacity /= GROW_FACTOR; + list->elements.data = (Value*)wrenReallocate(vm, list->elements.data, + sizeof(Value) * list->elements.capacity, + sizeof(Value) * (list->elements.capacity / GROW_FACTOR)); + list->elements.capacity /= GROW_FACTOR; } if (IS_OBJ(removed)) wrenPopRoot(vm); - list->count--; + list->elements.count--; return removed; } @@ -940,15 +915,11 @@ static void markInstance(WrenVM* vm, ObjInstance* instance) static void markList(WrenVM* vm, ObjList* list) { // Mark the elements. - Value* elements = list->elements; - for (uint32_t i = 0; i < list->count; i++) - { - wrenMarkValue(vm, elements[i]); - } + wrenMarkBuffer(vm, &list->elements); // Keep track of how much memory is still in use. vm->bytesAllocated += sizeof(ObjList); - vm->bytesAllocated += sizeof(Value) * list->capacity; + vm->bytesAllocated += sizeof(Value) * list->elements.capacity; } static void markMap(WrenVM* vm, ObjMap* map) @@ -1048,6 +1019,14 @@ void wrenMarkValue(WrenVM* vm, Value value) wrenMarkObj(vm, AS_OBJ(value)); } +void wrenMarkBuffer(WrenVM* vm, ValueBuffer* buffer) +{ + for (int i = 0; i < buffer->count; i++) + { + wrenMarkValue(vm, buffer->data[i]); + } +} + void wrenFreeObj(WrenVM* vm, Obj* obj) { #if WREN_DEBUG_TRACE_MEMORY @@ -1074,7 +1053,7 @@ void wrenFreeObj(WrenVM* vm, Obj* obj) } case OBJ_LIST: - DEALLOCATE(vm, ((ObjList*)obj)->elements); + wrenValueBufferClear(vm, &((ObjList*)obj)->elements); break; case OBJ_MAP: diff --git a/src/vm/wren_value.h b/src/vm/wren_value.h index c4202e8b..184d5c12 100644 --- a/src/vm/wren_value.h +++ b/src/vm/wren_value.h @@ -393,14 +393,8 @@ typedef struct { Obj obj; - // The number of elements allocated. - uint32_t capacity; - - // The number of items in the list. - uint32_t count; - - // Pointer to a contiguous array of [capacity] elements. - Value* elements; + // The elements in the list. + ValueBuffer elements; } ObjList; typedef struct @@ -639,9 +633,6 @@ Value wrenNewInstance(WrenVM* vm, ObjClass* classObj); // uninitialized.) ObjList* wrenNewList(WrenVM* vm, uint32_t numElements); -// Adds [value] to [list], reallocating and growing its storage if needed. -void wrenListAdd(WrenVM* vm, ObjList* list, Value value); - // Inserts [value] in [list] at [index], shifting down the other elements. void wrenListInsert(WrenVM* vm, ObjList* list, Value value, uint32_t index); @@ -710,6 +701,10 @@ void wrenMarkValue(WrenVM* vm, Value value); // during the sweep phase of a garbage collection. void wrenMarkObj(WrenVM* vm, Obj* obj); +// Mark the values in [buffer] as reachable and still in use. This should only +// be called during the sweep phase of a garbage collection. +void wrenMarkBuffer(WrenVM* vm, ValueBuffer* buffer); + // Releases all memory owned by [obj], including [obj] itself. void wrenFreeObj(WrenVM* vm, Obj* obj);