mirror of
https://github.com/janet-lang/janet
synced 2024-12-25 07:50:27 +00:00
Retabbed things
This commit is contained in:
parent
9f09a19feb
commit
ba82ba414a
306
dict.c
306
dict.c
@ -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, ¬used);
|
||||
}
|
||||
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
2
ds.c
@ -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
90
gc.c
@ -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
216
thread.c
@ -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
114
vm.c
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user