1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-24 17:27:18 +00:00

Retabbed things

This commit is contained in:
Calvin Rose 2017-03-15 01:26:45 -04:00
parent 9f09a19feb
commit ba82ba414a
5 changed files with 364 additions and 364 deletions

306
dict.c
View File

@ -11,25 +11,25 @@
static GstValue *gst_object_bag_find(GstDict *obj, GstValue key) {
GstValue *start = obj->data;
GstValue *end = obj->data + obj->count * 2;
while (start < end) {
if (gst_equals(*start, key))
return start;
start += 2;
}
return NULL;
while (start < end) {
if (gst_equals(*start, key))
return start;
start += 2;
}
return NULL;
}
/* Check for string equality */
static int str_equal_value(GstValue v, const char *str, uint32_t len, uint32_t hash) {
uint32_t i;
uint32_t i;
if (v.type != GST_STRING) return 0;
if (gst_string_length(str) != len) return 0;
if (!gst_string_hash(str))
gst_string_hash(str) = gst_string_calchash((uint8_t *)str);
if (gst_string_hash(str) != hash) return 0;
for (i = 0; i < len; ++i)
if (str[1] != v.data.string[i]) return 0;
return 1;
if (gst_string_length(str) != len) return 0;
if (!gst_string_hash(str))
gst_string_hash(str) = gst_string_calchash((uint8_t *)str);
if (gst_string_hash(str) != hash) return 0;
for (i = 0; i < len; ++i)
if (str[1] != v.data.string[i]) return 0;
return 1;
}
/* Find key value pair with c string key */
@ -39,53 +39,53 @@ static GstValue *gst_object_bag_findcstring(GstDict *obj, const char *key) {
hash = gst_cstring_calchash((uint8_t *)key, len);
GstValue *start = obj->data;
GstValue *end = obj->data + obj->count * 2;
while (start < end) {
if (start->type == GST_STRING) {
uint8_t *str = start->data.string;
if (gst_string_length(str) == len) {
if (!gst_string_hash(str))
gst_string_hash(str) = gst_string_calchash(str);
if (gst_string_hash(str) == hash) {
return start
}
}
}
start += 2;
}
return NULL;
while (start < end) {
if (start->type == GST_STRING) {
uint8_t *str = start->data.string;
if (gst_string_length(str) == len) {
if (!gst_string_hash(str))
gst_string_hash(str) = gst_string_calchash(str);
if (gst_string_hash(str) == hash) {
return start
}
}
}
start += 2;
}
return NULL;
}
/* Remove a key from a bag */
static void gst_object_bag_remove(GstDict *obj, GstValue key) {
GstValue *kv = gst_object_bag_find(obj, key);
if (kv != NULL) {
GstValue *lastKv = obj->data + --obj->count * 2;
kv[0] = lastKv[0];
kv[1] = lastKv[1];
}
GstValue *kv = gst_object_bag_find(obj, key);
if (kv != NULL) {
GstValue *lastKv = obj->data + --obj->count * 2;
kv[0] = lastKv[0];
kv[1] = lastKv[1];
}
}
/* Add a key to a bag */
static void gst_object_bag_put(Gst *vm, GstDict *obj, GstValue key, GstValue value) {
GstValue *kv = gst_object_bag_find(obj, key);
if (kv != NULL) {
/* Replace value */
kv[1] = value;
} else {
/* Check for need to resize */
if (obj->count + 1 > obj->capacity) {
uint32_t newCap = 2 * obj->count + 2;
GstValue *newData = gst_alloc(vm, sizeof(GstValue) * 2 * newCap);
gst_memcpy(newData, obj->data, obj->count * 2 * sizeof(GstValue));
obj->data = newData;
obj->capacity = newCap;
}
/* Push to end */
kv = obj->data + obj->count * 2;
kv[0] = key;
kv[1] = value;
++obj->count;
}
GstValue *kv = gst_object_bag_find(obj, key);
if (kv != NULL) {
/* Replace value */
kv[1] = value;
} else {
/* Check for need to resize */
if (obj->count + 1 > obj->capacity) {
uint32_t newCap = 2 * obj->count + 2;
GstValue *newData = gst_alloc(vm, sizeof(GstValue) * 2 * newCap);
gst_memcpy(newData, obj->data, obj->count * 2 * sizeof(GstValue));
obj->data = newData;
obj->capacity = newCap;
}
/* Push to end */
kv = obj->data + obj->count * 2;
kv[0] = key;
kv[1] = value;
++obj->count;
}
}
/****/
@ -94,58 +94,58 @@ static void gst_object_bag_put(Gst *vm, GstDict *obj, GstValue key, GstValue val
/* Add a key value pair to a given array. Returns if key successfully added. */
static void hash_putkv(GstValue *data, uint32_t cap, GstValue key, GstValue value) {
GstValue *end = data + 2 * cap;
GstValue *start = data + (gst_hash(key) % cap) * 2;
GstValue *bucket;
/* Check second half of array */
for (bucket = start; bucket < end; bucket += 2) {
if (bucket[0].type == GST_NIL) {
bucket[0] = key;
bucket[1] = value;
return;
}
}
/* Check first half of array */
for (bucket = data; bucket < start; bucket += 2) {
if (bucket[0].type == GST_NIL) {
bucket[0] = key;
bucket[1] = value;
return;
}
}
/* Should never reach here - data would be full */
GstValue *end = data + 2 * cap;
GstValue *start = data + (gst_hash(key) % cap) * 2;
GstValue *bucket;
/* Check second half of array */
for (bucket = start; bucket < end; bucket += 2) {
if (bucket[0].type == GST_NIL) {
bucket[0] = key;
bucket[1] = value;
return;
}
}
/* Check first half of array */
for (bucket = data; bucket < start; bucket += 2) {
if (bucket[0].type == GST_NIL) {
bucket[0] = key;
bucket[1] = value;
return;
}
}
/* Should never reach here - data would be full */
}
/* Find a bucket in the hastable */
static GstValue *hash_findkv(GstValue *data, uint32_t cap, GstValue key, GstValue **out) {
GstValue *end = data + 2 * cap;
GstValue *start = data + (gst_hash(key) % cap) * 2;
GstValue *bucket;
/* Check second half of array */
for (bucket = start; bucket < end; bucket += 2)
if (bucket[0].type == GST_NIL)
if (bucket[1].type == GST_BOOLEAN) /* Check if just marked deleted */
continue;
else {
*out = bucket;
return NULL;
}
else if (gst_equals(bucket[0], key))
return bucket;
/* Check first half of array */
for (bucket = data; bucket < start; bucket += 2)
if (bucket[0].type == GST_NIL)
if (bucket[1].type == GST_BOOLEAN) /* Check if just marked deleted */
continue;
else {
*out = bucket;
return NULL;
}
else if (gst_equals(bucket[0], key))
return bucket;
/* Should never reach here - data would be full */
*out = bucket;
return NULL;
GstValue *end = data + 2 * cap;
GstValue *start = data + (gst_hash(key) % cap) * 2;
GstValue *bucket;
/* Check second half of array */
for (bucket = start; bucket < end; bucket += 2)
if (bucket[0].type == GST_NIL)
if (bucket[1].type == GST_BOOLEAN) /* Check if just marked deleted */
continue;
else {
*out = bucket;
return NULL;
}
else if (gst_equals(bucket[0], key))
return bucket;
/* Check first half of array */
for (bucket = data; bucket < start; bucket += 2)
if (bucket[0].type == GST_NIL)
if (bucket[1].type == GST_BOOLEAN) /* Check if just marked deleted */
continue;
else {
*out = bucket;
return NULL;
}
else if (gst_equals(bucket[0], key))
return bucket;
/* Should never reach here - data would be full */
*out = bucket;
return NULL;
}
/* Resize internal hashtable. Also works if currently a bag. */
@ -155,32 +155,32 @@ static void gst_object_rehash(Gst *vm, GstDict *obj, uint32_t capacity) {
toEnd = toData + 2 * capacity;
fromBucket = obj->data;
fromEnd = fromBucket + obj->count * 2;
for (; fromBucket < fromEnd; fromBucket += 2) {
if (fromBucket[0].type == GST_NIL) continue;
toStart = toData + (gst_hash(fromBucket[0]) % capacity) * 2;
/* Check second half of array */
for (toBucket = toStart; toBucket < toEnd; toBucket += 2) {
if (toBucket[0].type == GST_NIL) {
toBucket[0] = fromBucket[0];
toBucket[1] = fromBucket[1];
goto finish_put;
}
}
/* Check first half of array */
for (toBucket = toData; toBucket < toStart; toBucket += 2) {
if (toBucket[0].type == GST_NIL) {
toBucket[0] = fromBucket[0];
toBucket[1] = fromBucket[1];
goto finish_put;
}
}
/* Error if we got here - backing array to small. */
;
/* Continue. */
finish_put: continue;
}
obj->capacity = capacity;
obj->data = toData;
for (; fromBucket < fromEnd; fromBucket += 2) {
if (fromBucket[0].type == GST_NIL) continue;
toStart = toData + (gst_hash(fromBucket[0]) % capacity) * 2;
/* Check second half of array */
for (toBucket = toStart; toBucket < toEnd; toBucket += 2) {
if (toBucket[0].type == GST_NIL) {
toBucket[0] = fromBucket[0];
toBucket[1] = fromBucket[1];
goto finish_put;
}
}
/* Check first half of array */
for (toBucket = toData; toBucket < toStart; toBucket += 2) {
if (toBucket[0].type == GST_NIL) {
toBucket[0] = fromBucket[0];
toBucket[1] = fromBucket[1];
goto finish_put;
}
}
/* Error if we got here - backing array to small. */
;
/* Continue. */
finish_put: continue;
}
obj->capacity = capacity;
obj->data = toData;
}
/****/
@ -202,16 +202,16 @@ GstDict *gst_dict(Gst *vm, uint32_t capacity) {
GstValue gst_dict_get(GstDict *dict, GstValue key) {
GstValue *bucket *notused;
if (dict->flags & GST_OBJECT_FLAG_ISBAG) {
bucket = gst_object_bag_find(dict, key);
bucket = gst_object_bag_find(dict, key);
} else {
bucket = hash_findkv(obj->data, obj->capacity, key, &notused);
}
if (bucket != NULL) {
return bucket[1];
return bucket[1];
} else {
GstValue ret;
ret.type = GST_NIL;
return ret;
ret.type = GST_NIL;
return ret;
}
}
@ -223,42 +223,42 @@ void gst_dict_put(Gst *vm, GstDict *obj, GstValue key, GstValue value) {
if (obj->flags & GST_OBJECT_FLAG_ISBAG) {
if (obj->count > GST_OBJECT_BAG_THRESHOLD) {
/* Change to hashtable */
obj->flags |= GST_OBJECT_FLAG_ISBAG;
gst_object_rehash(vm, obj, 4 * obj->count);
goto put_hash;
obj->flags |= GST_OBJECT_FLAG_ISBAG;
gst_object_rehash(vm, obj, 4 * obj->count);
goto put_hash;
}
gst_object_bag_put(vm, obj, key, value);
gst_object_bag_put(vm, obj, key, value);
} else {
GstValue *bucket, *out;
put_hash:
put_hash:
bucket = hash_findkv(obj->data, obj->capacity, key, &out);
if (bucket != NULL) {
bucket[1] = value;
} else {
/* Check for resize */
if (obj->count + 1 > obj->capacity) {
gst_object_rehash(vm, obj, 2 * (obj->count + 1));
if (bucket != NULL) {
bucket[1] = value;
} else {
/* Check for resize */
if (obj->count + 1 > obj->capacity) {
gst_object_rehash(vm, obj, 2 * (obj->count + 1));
bucket = hash_findkv(obj->data, obj->capacity, key, &out);
}
out[0] = key;
out[1] = value;
++obj->count;
}
}
out[0] = key;
out[1] = value;
++obj->count;
}
}
}
/* Remove item from dictionary */
void gst_dict_remove(GstDict *obj, GstValue key) {
if (obj->flags & GST_OBJECT_FLAG_ISBAG) {
gst_object_bag_remove(obj, key);
gst_object_bag_remove(obj, key);
} else {
GstValue *bucket, *out;
bucket = hash_findkv(obj->data, obj->capacity, key, &out);
if (bucket != NULL) {
--obj->count;
bucket[0].type = GST_NIL;
bucket[1].type = GST_BOOLEAN;
}
if (bucket != NULL) {
--obj->count;
bucket[0].type = GST_NIL;
bucket[1].type = GST_BOOLEAN;
}
}
}

2
ds.c
View File

@ -229,7 +229,7 @@ GstValue gst_object_get(GstObject *o, GstValue key) {
/* Get a value of the object with a cstring key */
GstValue gst_object_get_cstring(GstObject *obj, const char *key) {
uint32_t len;
for (len = 0; key[len]; ++len);
for (len = 0; key[len]; ++len);
uint32_t hash = gst_cstring_calchash((uint8_t *)key, len);
uint32_t index = hash % obj->capacity;
GstBucket *bucket = obj->buckets[index];

90
gc.c
View File

@ -45,11 +45,11 @@ static void gst_mark_funcdef(Gst *vm, GstFuncDef *def) {
for (i = 0; i < count; ++i) {
/* If the literal is a NIL type, it actually
* contains a FuncDef */
if (def->literals[i].type == GST_NIL) {
gst_mark_funcdef(vm, (GstFuncDef *) def->literals[i].data.pointer);
} else {
if (def->literals[i].type == GST_NIL) {
gst_mark_funcdef(vm, (GstFuncDef *) def->literals[i].data.pointer);
} else {
gst_mark(vm, def->literals + i);
}
}
}
}
}
@ -141,31 +141,31 @@ void gst_mark(Gst *vm, GstValue *x) {
gc_header(x->data.object)->color = vm->black;
gc_header(x->data.object->buckets)->color = vm->black;
for (i = 0; i < x->data.object->capacity; ++i) {
bucket = x->data.object->buckets[i];
while (bucket) {
gc_header(bucket)->color = vm->black;
gst_mark(vm, &bucket->key);
gst_mark(vm, &bucket->value);
bucket = bucket->next;
}
bucket = x->data.object->buckets[i];
while (bucket) {
gc_header(bucket)->color = vm->black;
gst_mark(vm, &bucket->key);
gst_mark(vm, &bucket->value);
bucket = bucket->next;
}
}
if (x->data.object->meta != NULL) {
GstValue temp;
temp.type = GST_OBJECT;
temp.data.object = x->data.object->meta;
gst_mark(vm, &temp);
gst_mark(vm, &temp);
}
}
break;
case GST_USERDATA:
if (gc_header(x->data.string - sizeof(GstUserdataHeader))->color != vm->black) {
GstUserdataHeader *userHeader = (GstUserdataHeader *)x->data.string - 1;
gc_header(userHeader)->color = vm->black;
GstValue temp;
temp.type = GST_OBJECT;
temp.data.object = userHeader->meta;
gst_mark(vm, &temp);
GstUserdataHeader *userHeader = (GstUserdataHeader *)x->data.string - 1;
gc_header(userHeader)->color = vm->black;
GstValue temp;
temp.type = GST_OBJECT;
temp.data.object = userHeader->meta;
gst_mark(vm, &temp);
}
}
}
@ -254,20 +254,20 @@ void gst_clear_memory(Gst *vm) {
/* Header for managed memory blocks */
struct MMHeader {
struct MMHeader *next;
struct MMHeader *previous;
struct MMHeader *next;
struct MMHeader *previous;
};
/* Initialize managed memory */
void gst_mm_init(GstManagedMemory *mm) {
*mm = NULL;
*mm = NULL;
}
/* Allocate some managed memory */
void *gst_mm_alloc(GstManagedMemory *mm, uint32_t size) {
struct MMHeader *mem = gst_raw_alloc(size + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
struct MMHeader *mem = gst_raw_alloc(size + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
mem->next = *mm;
mem->previous = NULL;
*mm = mem;
@ -276,9 +276,9 @@ void *gst_mm_alloc(GstManagedMemory *mm, uint32_t size) {
/* Intialize zeroed managed memory */
void *gst_mm_zalloc(GstManagedMemory *mm, uint32_t size) {
struct MMHeader *mem = gst_raw_calloc(1, size + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
struct MMHeader *mem = gst_raw_calloc(1, size + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
mem->next = *mm;
mem->previous = NULL;
*mm = mem;
@ -287,32 +287,32 @@ void *gst_mm_zalloc(GstManagedMemory *mm, uint32_t size) {
/* Free a memory block used in managed memory */
void gst_mm_free(GstManagedMemory *mm, void *block) {
struct MMHeader *mem = (struct MMHeader *)(((char *)block) - sizeof(struct MMHeader));
if (mem->previous != NULL) {
mem->previous->next = mem->next;
} else {
*mm = mem->next;
}
gst_raw_free(mem);
struct MMHeader *mem = (struct MMHeader *)(((char *)block) - sizeof(struct MMHeader));
if (mem->previous != NULL) {
mem->previous->next = mem->next;
} else {
*mm = mem->next;
}
gst_raw_free(mem);
}
/* Free all memory in managed memory */
void gst_mm_clear(GstManagedMemory *mm) {
struct MMHeader *block = (struct MMHeader *)(*mm);
struct MMHeader *next;
while (block != NULL) {
next = block->next;
free(block);
block = next;
};
*mm = NULL;
struct MMHeader *block = (struct MMHeader *)(*mm);
struct MMHeader *next;
while (block != NULL) {
next = block->next;
free(block);
block = next;
};
*mm = NULL;
}
/* Analog to realloc */
void *gst_mm_realloc(GstManagedMemory *mm, void *block, uint32_t nsize) {
struct MMHeader *mem = gst_raw_realloc(block, nsize + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
struct MMHeader *mem = gst_raw_realloc(block, nsize + sizeof(struct MMHeader));
if (mem == NULL)
return NULL;
mem->next = *mm;
mem->previous = NULL;
*mm = mem;

216
thread.c
View File

@ -7,80 +7,80 @@
/* Create a new thread */
GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
GstThread *thread = gst_alloc(vm, sizeof(GstThread));
GstValue *data, *stack;
if (capacity < GST_FRAME_SIZE) capacity = GST_FRAME_SIZE;
data = gst_alloc(vm, sizeof(GstValue) * capacity);
thread->capacity = capacity;
thread->count = GST_FRAME_SIZE;
thread->data = data;
thread->status = GST_THREAD_PENDING;
stack = data + GST_FRAME_SIZE;
gst_frame_size(stack) = 0;
gst_frame_prevsize(stack) = 0;
gst_frame_ret(stack) = 0;
gst_frame_errloc(stack) = 0;
gst_frame_pc(stack) = NULL;
gst_frame_env(stack) = NULL;
gst_frame_errjmp(stack) = NULL;
GstValue *data, *stack;
if (capacity < GST_FRAME_SIZE) capacity = GST_FRAME_SIZE;
data = gst_alloc(vm, sizeof(GstValue) * capacity);
thread->capacity = capacity;
thread->count = GST_FRAME_SIZE;
thread->data = data;
thread->status = GST_THREAD_PENDING;
stack = data + GST_FRAME_SIZE;
gst_frame_size(stack) = 0;
gst_frame_prevsize(stack) = 0;
gst_frame_ret(stack) = 0;
gst_frame_errloc(stack) = 0;
gst_frame_pc(stack) = NULL;
gst_frame_env(stack) = NULL;
gst_frame_errjmp(stack) = NULL;
gst_thread_expand_callable(vm, thread, callee);
gst_thread_endframe(vm, thread);
gst_thread_endframe(vm, thread);
return thread;
}
/* Ensure that the thread has enough EXTRA capacity */
void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra) {
GstValue *newData, *stack;
uint32_t usedCapacity, neededCapacity, newCapacity;
stack = thread->data + thread->count;
usedCapacity = thread->count + gst_frame_size(stack) + GST_FRAME_SIZE;
neededCapacity = usedCapacity + extra;
if (thread->capacity >= neededCapacity) return;
newCapacity = 2 * neededCapacity;
newData = gst_alloc(vm, sizeof(GstValue) * newCapacity);
gst_memcpy(newData, thread->data, sizeof(GstValue) * usedCapacity);
thread->data = newData;
thread->capacity = newCapacity;
GstValue *newData, *stack;
uint32_t usedCapacity, neededCapacity, newCapacity;
stack = thread->data + thread->count;
usedCapacity = thread->count + gst_frame_size(stack) + GST_FRAME_SIZE;
neededCapacity = usedCapacity + extra;
if (thread->capacity >= neededCapacity) return;
newCapacity = 2 * neededCapacity;
newData = gst_alloc(vm, sizeof(GstValue) * newCapacity);
gst_memcpy(newData, thread->data, sizeof(GstValue) * usedCapacity);
thread->data = newData;
thread->capacity = newCapacity;
}
/* Push a value on the current stack frame*/
void gst_thread_push(Gst *vm, GstThread *thread, GstValue x) {
GstValue *stack;
gst_thread_ensure_extra(vm, thread, 1);
stack = thread->data + thread->count;
stack[gst_frame_size(stack)++] = x;
gst_thread_ensure_extra(vm, thread, 1);
stack = thread->data + thread->count;
stack[gst_frame_size(stack)++] = x;
}
/* Push n nils onto the stack */
void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n) {
GstValue *stack, *current, *end;
gst_thread_ensure_extra(vm, thread, n);
stack = thread->data + thread->count;
current = stack + gst_frame_size(stack);
end = current + n;
for (; current < end; ++current) {
current->type = GST_NIL;
}
gst_frame_size(stack) += n;
gst_thread_ensure_extra(vm, thread, n);
stack = thread->data + thread->count;
current = stack + gst_frame_size(stack);
end = current + n;
for (; current < end; ++current) {
current->type = GST_NIL;
}
gst_frame_size(stack) += n;
}
/* Package up extra args after and including n into tuple at n*/
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n) {
GstValue *stack = thread->data + thread->count;
uint32_t size = gst_frame_size(stack);
if (n >= size) {
gst_thread_pushnil(vm, thread, n - size + 1);
stack = thread->data + thread->count;
stack[n].type = GST_TUPLE;
stack[n].data.tuple = gst_tuple(vm, 0);
} else {
uint32_t i;
GstValue *tuple = gst_tuple(vm, size - n);
for (i = n; i < size; ++i)
tuple[i - n] = stack[i];
stack[n].type = GST_TUPLE;
stack[n].data.tuple = tuple;
gst_frame_size(stack) = n + 1;
}
GstValue *stack = thread->data + thread->count;
uint32_t size = gst_frame_size(stack);
if (n >= size) {
gst_thread_pushnil(vm, thread, n - size + 1);
stack = thread->data + thread->count;
stack[n].type = GST_TUPLE;
stack[n].data.tuple = gst_tuple(vm, 0);
} else {
uint32_t i;
GstValue *tuple = gst_tuple(vm, size - n);
for (i = n; i < size; ++i)
tuple[i - n] = stack[i];
stack[n].type = GST_TUPLE;
stack[n].data.tuple = tuple;
gst_frame_size(stack) = n + 1;
}
}
/* Expand a callee on the stack frame to its delegate function. This means that
@ -128,70 +128,70 @@ GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uin
uint32_t frameOffset;
GstValue *oldStack, *newStack;
/* Push the frame */
gst_thread_ensure_extra(vm, thread, GST_FRAME_SIZE + arity + 4);
oldStack = thread->data + thread->count;
frameOffset = gst_frame_size(oldStack) + GST_FRAME_SIZE;
newStack = oldStack + frameOffset;
gst_frame_prevsize(newStack) = gst_frame_size(oldStack);
gst_frame_env(newStack) = NULL;
gst_frame_errjmp(newStack) = NULL;
gst_frame_size(newStack) = 0;
thread->count += frameOffset;
/* Push the frame */
gst_thread_ensure_extra(vm, thread, GST_FRAME_SIZE + arity + 4);
oldStack = thread->data + thread->count;
frameOffset = gst_frame_size(oldStack) + GST_FRAME_SIZE;
newStack = oldStack + frameOffset;
gst_frame_prevsize(newStack) = gst_frame_size(oldStack);
gst_frame_env(newStack) = NULL;
gst_frame_errjmp(newStack) = NULL;
gst_frame_size(newStack) = 0;
thread->count += frameOffset;
/* Get real callable */
if (gst_thread_expand_callable(vm, thread, callee) == NULL)
return NULL;
/* Ensure the extra space and initialize to nil */
/* Ensure the extra space and initialize to nil */
gst_thread_pushnil(vm, thread, arity);
/* Return ok */
/* Return ok */
return thread->data + thread->count;
}
/* After pushing arguments to a stack frame created with gst_thread_beginframe, call this
* to finalize the frame before starting a function call. */
void gst_thread_endframe(Gst *vm, GstThread *thread) {
GstValue *stack = thread->data + thread->count;
GstValue callee = gst_frame_callee(stack);
if (callee.type == GST_FUNCTION) {
GstFunction *fn = callee.data.function;
gst_frame_pc(stack) = fn->def->byteCode;
if (fn->def->flags & GST_FUNCDEF_FLAG_VARARG) {
uint32_t arity = fn->def->arity;
gst_thread_tuplepack(vm, thread, arity);
} else {
uint32_t locals = fn->def->locals;
if (gst_frame_size(stack) < locals) {
gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack));
}
}
}
GstValue *stack = thread->data + thread->count;
GstValue callee = gst_frame_callee(stack);
if (callee.type == GST_FUNCTION) {
GstFunction *fn = callee.data.function;
gst_frame_pc(stack) = fn->def->byteCode;
if (fn->def->flags & GST_FUNCDEF_FLAG_VARARG) {
uint32_t arity = fn->def->arity;
gst_thread_tuplepack(vm, thread, arity);
} else {
uint32_t locals = fn->def->locals;
if (gst_frame_size(stack) < locals) {
gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack));
}
}
}
}
/* Pop a stack frame from the thread. Returns the new stack frame, or
* NULL if there are no more frames */
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
GstValue *stack = thread->data + thread->count;
uint32_t prevsize = gst_frame_prevsize(stack);
GstValue *nextstack = stack - GST_FRAME_SIZE - prevsize;
GstFuncEnv *env = gst_frame_env(stack);
GstValue *stack = thread->data + thread->count;
uint32_t prevsize = gst_frame_prevsize(stack);
GstValue *nextstack = stack - GST_FRAME_SIZE - prevsize;
GstFuncEnv *env = gst_frame_env(stack);
/* Check for closures */
/* Check for closures */
if (env != NULL) {
uint32_t size = gst_frame_size(stack);
env->thread = NULL;
env->stackOffset = size;
env->values = gst_alloc(vm, sizeof(GstValue) * size);
env->values = gst_alloc(vm, sizeof(GstValue) * size);
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
}
/* Shrink stack */
thread->count -= GST_FRAME_SIZE + prevsize;
/* Check if the stack is empty, and if so, return null */
if (thread->count)
/* Check if the stack is empty, and if so, return null */
if (thread->count)
return nextstack;
else
return NULL;
@ -201,39 +201,39 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
* for primitive tail calls. */
GstValue *gst_thread_tail(Gst *vm, GstThread *thread) {
GstFuncEnv *env;
GstValue *stack = thread->data + thread->count;
GstValue *nextStack = gst_thread_popframe(vm, thread);
uint32_t i;
GstValue *stack = thread->data + thread->count;
GstValue *nextStack = gst_thread_popframe(vm, thread);
uint32_t i;
if (nextStack == NULL) return NULL;
env = gst_frame_env(nextStack);
if (nextStack == NULL) return NULL;
env = gst_frame_env(nextStack);
/* Check for old closures */
/* Check for old closures */
if (env != NULL) {
uint32_t size = gst_frame_size(stack);
env->thread = NULL;
env->stackOffset = size;
env->values = gst_alloc(vm, sizeof(GstValue) * size);
env->values = gst_alloc(vm, sizeof(GstValue) * size);
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
}
/* Modify new closure */
env = gst_frame_env(stack);
if (env != NULL) {
env->stackOffset = thread->count;
env->stackOffset = thread->count;
}
/* Copy over (some of) stack frame. Leave ret and prevsize untouched. */
gst_frame_env(nextStack) = env;
gst_frame_size(nextStack) = gst_frame_size(stack);
gst_frame_pc(nextStack) = gst_frame_pc(stack);
gst_frame_errjmp(nextStack) = gst_frame_errjmp(stack);
gst_frame_errloc(nextStack) = gst_frame_errloc(stack);
gst_frame_callee(nextStack) = gst_frame_callee(stack);
/* Copy over (some of) stack frame. Leave ret and prevsize untouched. */
gst_frame_env(nextStack) = env;
gst_frame_size(nextStack) = gst_frame_size(stack);
gst_frame_pc(nextStack) = gst_frame_pc(stack);
gst_frame_errjmp(nextStack) = gst_frame_errjmp(stack);
gst_frame_errloc(nextStack) = gst_frame_errloc(stack);
gst_frame_callee(nextStack) = gst_frame_callee(stack);
/* Copy stack arguments */
for (i = 0; i < gst_frame_size(nextStack); ++i)
nextStack[i] = stack[i];
/* Copy stack arguments */
for (i = 0; i < gst_frame_size(nextStack); ++i)
nextStack[i] = stack[i];
return nextStack;
return nextStack;
}

114
vm.c
View File

@ -349,7 +349,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
continue;
case GST_OP_RET: /* Return */
temp = stack[pc[1]];
temp = stack[pc[1]];
stack = gst_thread_popframe(vm, &thread);
if (thread.count < stackBase) {
vm->ret = temp;
@ -362,59 +362,59 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
case GST_OP_CAL: /* Call */
case GST_OP_TCL: /* Tail call */
{
GstValue *oldStack;
temp = stack[pc[1]];
{
GstValue *oldStack;
temp = stack[pc[1]];
int isTCall = *pc == GST_OP_TCL;
uint32_t i, arity, offset, size;
uint16_t ret = pc[2];
offset = isTCall ? 3 : 4;
arity = pc[offset - 1];
/* Push new frame */
stack = gst_thread_beginframe(vm, &thread, temp, arity);
oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack);
/* Write arguments */
size = gst_frame_size(stack);
for (i = 0; i < arity; ++i)
stack[i + size - arity] = oldStack[pc[offset + i]];
/* Finish new frame */
gst_thread_endframe(vm, &thread);
/* Check tail call - if so, replace frame. */
if (isTCall) {
stack = gst_thread_tail(vm, &thread);
} else {
gst_frame_ret(oldStack) = ret;
}
/* Call function */
temp = gst_frame_callee(stack);
if (temp.type == GST_FUNCTION) {
/* Save pc and set new pc */
uint32_t i, arity, offset, size;
uint16_t ret = pc[2];
offset = isTCall ? 3 : 4;
arity = pc[offset - 1];
/* Push new frame */
stack = gst_thread_beginframe(vm, &thread, temp, arity);
oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack);
/* Write arguments */
size = gst_frame_size(stack);
for (i = 0; i < arity; ++i)
stack[i + size - arity] = oldStack[pc[offset + i]];
/* Finish new frame */
gst_thread_endframe(vm, &thread);
/* Check tail call - if so, replace frame. */
if (isTCall) {
stack = gst_thread_tail(vm, &thread);
} else {
gst_frame_ret(oldStack) = ret;
}
/* Call function */
temp = gst_frame_callee(stack);
if (temp.type == GST_FUNCTION) {
/* Save pc and set new pc */
if (!isTCall)
gst_frame_pc(oldStack) = pc + offset + arity;
pc = temp.data.function->def->byteCode;
} else {
int status;
GST_STATE_WRITE();
vm->ret.type = GST_NIL;
status = temp.data.cfunction(vm);
GST_STATE_SYNC();
stack = gst_thread_popframe(vm, &thread);
if (status == GST_RETURN_OK)
if (thread.count < stackBase) {
pc = temp.data.function->def->byteCode;
} else {
int status;
GST_STATE_WRITE();
vm->ret.type = GST_NIL;
status = temp.data.cfunction(vm);
GST_STATE_SYNC();
stack = gst_thread_popframe(vm, &thread);
if (status == GST_RETURN_OK)
if (thread.count < stackBase) {
GST_STATE_WRITE();
return status;
return status;
} else {
stack[gst_frame_ret(stack)] = vm->ret;
stack[gst_frame_ret(stack)] = vm->ret;
if (isTCall)
pc = gst_frame_pc(stack);
else
pc += offset + arity;
}
else
goto vm_error;
}
}
break;
else
goto vm_error;
}
}
break;
/* Handle errors from c functions and vm opcodes */
vm_error:
@ -453,11 +453,11 @@ int gst_run(Gst *vm, GstValue callee) {
/* If callee was not actually a function, get the delegate function */
callee = gst_frame_callee(stack);
if (callee.type == GST_CFUNCTION) {
int status;
vm->ret.type = GST_NIL;
status = callee.data.cfunction(vm);
gst_thread_popframe(vm, vm->thread);
return status;
int status;
vm->ret.type = GST_NIL;
status = callee.data.cfunction(vm);
gst_thread_popframe(vm, vm->thread);
return status;
} else {
return gst_continue(vm);
}
@ -484,15 +484,15 @@ int gst_call(Gst *vm, GstValue callee, uint32_t arity, GstValue *args) {
gst_thread_endframe(vm, vm->thread);
/* Call function */
callee = gst_frame_callee(stack);
if (callee.type == GST_FUNCTION) {
callee = gst_frame_callee(stack);
if (callee.type == GST_FUNCTION) {
gst_frame_pc(stack) = callee.data.function->def->byteCode;
status = gst_continue(vm);
} else {
vm->ret.type = GST_NIL;
status = callee.data.cfunction(vm);
gst_thread_popframe(vm, vm->thread);
}
status = gst_continue(vm);
} else {
vm->ret.type = GST_NIL;
status = callee.data.cfunction(vm);
gst_thread_popframe(vm, vm->thread);
}
/* Pop the extra nil */
--gst_frame_size(gst_thread_stack(vm->thread));