Add concurrency
This commit is contained in:
		
							parent
							
								
									64c21ca43a
								
							
						
					
					
						commit
						0165980111
					
				
							
								
								
									
										10
									
								
								lexer.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								lexer.c
									
									
									
									
									
								
							@ -148,3 +148,13 @@ vec_Token ltokenize(const char *buf, size_t len) {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	return tokens;
 | 
						return tokens;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void lfreetoks(vec_Token *toks) {
 | 
				
			||||||
 | 
						for(size_t i = 0; i < toks->size; i++) {
 | 
				
			||||||
 | 
							Token *tok = &toks->data[i];
 | 
				
			||||||
 | 
							if(tok->text) {
 | 
				
			||||||
 | 
								free(tok->text);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						vec_Token_drop(toks);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								lexer.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								lexer.h
									
									
									
									
									
								
							@ -84,3 +84,5 @@ typedef struct Token {
 | 
				
			|||||||
#undef i_header
 | 
					#undef i_header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec_Token ltokenize(const char *buf, size_t len);
 | 
					vec_Token ltokenize(const char *buf, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void lfreetoks(vec_Token*);
 | 
				
			||||||
							
								
								
									
										50
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								main.c
									
									
									
									
									
								
							@ -6,19 +6,31 @@
 | 
				
			|||||||
#include"str.h"
 | 
					#include"str.h"
 | 
				
			||||||
#include"dump.h"
 | 
					#include"dump.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t native_print(LVM *lvm, void *ud, size_t argn, LValue *values) {
 | 
					static size_t native_print(LVM *lvm, void *ud, size_t argn, LRegSet *regset) {
 | 
				
			||||||
	if(lvalue_tag(values[0]) == LTAG_STRING) {
 | 
						if(lvalue_tag(regset->regs[0]) == LTAG_STRING) {
 | 
				
			||||||
		LString *lstr = (void*) (values[0].u & ~LTAG_MASK);
 | 
							LString *lstr = (void*) (regset->regs[0].u & ~LTAG_MASK);
 | 
				
			||||||
		printf("%.*s\n", (int) lstr->length, lstr->data);
 | 
							printf("%.*s\n", (int) lstr->length, lstr->data);
 | 
				
			||||||
	} else if(lvalue_tag(values[0]) == LTAG_I32) {
 | 
						} else if(lvalue_tag(regset->regs[0]) == LTAG_I32) {
 | 
				
			||||||
		printf("%i\n", lvalue_to_int32(values[0]));
 | 
							printf("%i\n", lvalue_to_int32(regset->regs[0]));
 | 
				
			||||||
	} else if(values[0].u == LTAG_NIL) {
 | 
						} else if(regset->regs[0].u == LTAG_NIL) {
 | 
				
			||||||
		printf("nil\n");
 | 
							printf("nil\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main() {
 | 
					static char* read_full_file(const char *fn) {
 | 
				
			||||||
 | 
						FILE *f = fopen(fn, "rb");
 | 
				
			||||||
 | 
						fseek(f, 0, SEEK_END);
 | 
				
			||||||
 | 
						size_t filesize = ftell(f);
 | 
				
			||||||
 | 
						fseek(f, 0, SEEK_SET);
 | 
				
			||||||
 | 
						char *buf = malloc(filesize + 1);
 | 
				
			||||||
 | 
						fread(buf, 1, filesize, f);
 | 
				
			||||||
 | 
						buf[filesize] = '\0';
 | 
				
			||||||
 | 
						fclose(f);
 | 
				
			||||||
 | 
						return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
	LTable *env = ltable_new(128);
 | 
						LTable *env = ltable_new(128);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	LString *key = lstring_newz("print");
 | 
						LString *key = lstring_newz("print");
 | 
				
			||||||
@ -26,19 +38,33 @@ int main() {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	ltable_set(env, lvalue_from_string(key), lvalue_from_func(func));
 | 
						ltable_set(env, lvalue_from_string(key), lvalue_from_func(func));
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	const char *bufs = "for i = 1, 1000000 do print(i) if i % 3 == 0 then print(\"Fizz\") end if i % 5 == 0 then print(\"Buzz\") end end";
 | 
						//const char *bufs = "for i = 1, 10000 do print(i) if i % 3 == 0 then print(\"Fizz\") end if i % 5 == 0 then print(\"Buzz\") end end";
 | 
				
			||||||
	//const char *bufs = "local t = {a = 9} print(t.a)";
 | 
						//const char *bufs = "local t = {a = 9} print(t.a)";
 | 
				
			||||||
	//const char *bufs = "z = 5 print(z)";
 | 
						//const char *bufs = "z = 5 print(z)";
 | 
				
			||||||
	//const char *bufs = "local i = 0 while i ~= 1500000 do print(i) i = i + 1 end";
 | 
						//const char *bufs = "local i = 0 while i ~= 1500000 do print(i) i = i + 1 end";
 | 
				
			||||||
 | 
						//const char *bufs = "for i = 1, 1000 do print(print) end";
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						char *bufs = read_full_file(argv[1]);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	vec_Token toks = ltokenize(bufs, strlen(bufs));
 | 
						vec_Token toks = ltokenize(bufs, strlen(bufs));
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						free(bufs);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	LUnit *unit = lparse(toks.size, toks.data, env);
 | 
						LUnit *unit = lparse(toks.size, toks.data, env);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	dump(unit->funcs[0].lua_instrs);
 | 
						lfreetoks(&toks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LValue regs[256];
 | 
						//dump(unit->funcs[0].lua_instrs);
 | 
				
			||||||
	lvm_reset_regs(regs);
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	LVM lvm = {};
 | 
						LVM lvm = {};
 | 
				
			||||||
	lvm_run(&lvm, &unit->funcs[0], 0, regs);
 | 
						lvm_init(&lvm);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//#pragma omp parallel for
 | 
				
			||||||
 | 
						for(int i = 0; i < 1; i++) {
 | 
				
			||||||
 | 
							LRegSet regset = {.parent = NULL};
 | 
				
			||||||
 | 
							lvm_reset_regs(®set);
 | 
				
			||||||
 | 
							lvm_run(&lvm, &unit->funcs[0], 0, ®set);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						lvm_destroy(&lvm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										63
									
								
								parse.c
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								parse.c
									
									
									
									
									
								
							@ -98,6 +98,7 @@ typedef enum ExprKind {
 | 
				
			|||||||
} ExprKind;
 | 
					} ExprKind;
 | 
				
			||||||
typedef struct Expr {
 | 
					typedef struct Expr {
 | 
				
			||||||
	ExprKind kind;
 | 
						ExprKind kind;
 | 
				
			||||||
 | 
						struct Expr *next_to_die;
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			struct Expr *A;
 | 
								struct Expr *A;
 | 
				
			||||||
@ -181,6 +182,19 @@ void free_vreg(Parser *P, int vreg) {
 | 
				
			|||||||
	assert(P->current_chunk.used_vregs[vreg] >= 0 && "Cannot free unused vreg");
 | 
						assert(P->current_chunk.used_vregs[vreg] >= 0 && "Cannot free unused vreg");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void scope_kill(Parser *P) {
 | 
				
			||||||
 | 
						Scope *parent = P->scope->parent;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						for(ScopeItem *si = P->scope->items; si;) {
 | 
				
			||||||
 | 
							ScopeItem *next = si->next;
 | 
				
			||||||
 | 
							free(si);
 | 
				
			||||||
 | 
							si = next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						free(P->scope);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						P->scope = parent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void parse_chunk(Parser *P);
 | 
					void parse_chunk(Parser *P);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int parse_functiondef(Parser *P, bool can_be_local) {
 | 
					int parse_functiondef(Parser *P, bool can_be_local) {
 | 
				
			||||||
@ -251,7 +265,7 @@ int parse_functiondef(Parser *P, bool can_be_local) {
 | 
				
			|||||||
	size_t function_idx = P->unit_functions.size - 1;
 | 
						size_t function_idx = P->unit_functions.size - 1;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	P->current_chunk = old_chunk;
 | 
						P->current_chunk = old_chunk;
 | 
				
			||||||
	P->scope = P->scope->parent;
 | 
						scope_kill(P);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	int vreg = find_vreg(P);
 | 
						int vreg = find_vreg(P);
 | 
				
			||||||
	assert(vreg != -1);
 | 
						assert(vreg != -1);
 | 
				
			||||||
@ -315,6 +329,17 @@ vec_Token parse_namelist(Parser *P) {
 | 
				
			|||||||
	return v;
 | 
						return v;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Expr *last_desc = NULL;
 | 
				
			||||||
 | 
					static Expr *mark_for_death(Expr *e) {
 | 
				
			||||||
 | 
						e->next_to_die = last_desc;
 | 
				
			||||||
 | 
						last_desc = e;
 | 
				
			||||||
 | 
						return e;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static Expr *new_expr(size_t space) {
 | 
				
			||||||
 | 
						Expr *e = calloc(1, sizeof(*e) + space);
 | 
				
			||||||
 | 
						mark_for_death(e);
 | 
				
			||||||
 | 
						return e;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Expr *desc_subexp(Parser *P, int priority) {
 | 
					Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			||||||
	if(priority == 0) {
 | 
						if(priority == 0) {
 | 
				
			||||||
		Expr *a = desc_subexp(P, priority + 1);
 | 
							Expr *a = desc_subexp(P, priority + 1);
 | 
				
			||||||
@ -324,7 +349,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			Expr *b = desc_subexp(P, priority + 1);
 | 
								Expr *b = desc_subexp(P, priority + 1);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			Expr *opex = calloc(1, sizeof(*opex));
 | 
								Expr *opex = new_expr(0);
 | 
				
			||||||
			opex->A = a;
 | 
								opex->A = a;
 | 
				
			||||||
			opex->B = b;
 | 
								opex->B = b;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -346,7 +371,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			Expr *b = desc_subexp(P, priority + 1);
 | 
								Expr *b = desc_subexp(P, priority + 1);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			Expr *opex = calloc(1, sizeof(*opex));
 | 
								Expr *opex = new_expr(0);
 | 
				
			||||||
			opex->A = a;
 | 
								opex->A = a;
 | 
				
			||||||
			opex->B = b;
 | 
								opex->B = b;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -368,7 +393,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			Expr *b = desc_subexp(P, priority + 1);
 | 
								Expr *b = desc_subexp(P, priority + 1);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			Expr *opex = calloc(1, sizeof(*opex));
 | 
								Expr *opex = new_expr(0);
 | 
				
			||||||
			opex->A = a;
 | 
								opex->A = a;
 | 
				
			||||||
			opex->B = b;
 | 
								opex->B = b;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -390,11 +415,11 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
		Expr *e = NULL;
 | 
							Expr *e = NULL;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if(maybe(P, TOK_TRUE)) {
 | 
							if(maybe(P, TOK_TRUE)) {
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = EX_BOOL;
 | 
								e->kind = EX_BOOL;
 | 
				
			||||||
			e->b = true;
 | 
								e->b = true;
 | 
				
			||||||
		} else if(maybe(P, TOK_FALSE)) {
 | 
							} else if(maybe(P, TOK_FALSE)) {
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = EX_BOOL;
 | 
								e->kind = EX_BOOL;
 | 
				
			||||||
			e->b = false;
 | 
								e->b = false;
 | 
				
			||||||
		} else if(maybe(P, TOK_NUMBER)) {
 | 
							} else if(maybe(P, TOK_NUMBER)) {
 | 
				
			||||||
@ -403,7 +428,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			Token num = expect(P, TOK_NUMBER);
 | 
								Token num = expect(P, TOK_NUMBER);
 | 
				
			||||||
			long i = strtol(num.text, NULL, 10);
 | 
								long i = strtol(num.text, NULL, 10);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = EX_INT;
 | 
								e->kind = EX_INT;
 | 
				
			||||||
			e->i = i;
 | 
								e->i = i;
 | 
				
			||||||
		} else if(maybe(P, TOK_NAME)) {
 | 
							} else if(maybe(P, TOK_NAME)) {
 | 
				
			||||||
@ -413,7 +438,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			ScopeItem *si = scope_find(P->scope, name.text);
 | 
								ScopeItem *si = scope_find(P->scope, name.text);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = si ? EX_LOCAL : EX_GLOBAL;
 | 
								e->kind = si ? EX_LOCAL : EX_GLOBAL;
 | 
				
			||||||
			e->name = name;
 | 
								e->name = name;
 | 
				
			||||||
		} else if(maybe(P, TOK_STRING)) {
 | 
							} else if(maybe(P, TOK_STRING)) {
 | 
				
			||||||
@ -421,11 +446,11 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			Token str = expect(P, TOK_STRING);
 | 
								Token str = expect(P, TOK_STRING);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = EX_STR;
 | 
								e->kind = EX_STR;
 | 
				
			||||||
			e->name = str;
 | 
								e->name = str;
 | 
				
			||||||
		} else if(maybe(P, TOK_SQUIGGLY_L)) {
 | 
							} else if(maybe(P, TOK_SQUIGGLY_L)) {
 | 
				
			||||||
			e = calloc(1, sizeof(*e));
 | 
								e = new_expr(0);
 | 
				
			||||||
			e->kind = EX_TBL_LIT;
 | 
								e->kind = EX_TBL_LIT;
 | 
				
			||||||
			e->table_first_token = P->i - 1;
 | 
								e->table_first_token = P->i - 1;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -448,15 +473,14 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
		if(e) {
 | 
							if(e) {
 | 
				
			||||||
			while(maybe(P, TOK_PAREN_L) || maybe(P, TOK_DOT)) {
 | 
								while(maybe(P, TOK_PAREN_L) || maybe(P, TOK_DOT)) {
 | 
				
			||||||
				if(peek(P, -1).type == TOK_PAREN_L) {
 | 
									if(peek(P, -1).type == TOK_PAREN_L) {
 | 
				
			||||||
					Expr *call = calloc(1, sizeof(*call) + sizeof(Expr*));
 | 
										Expr *call = new_expr(sizeof(Expr*) + sizeof(Expr*) * 32);
 | 
				
			||||||
					call->kind = EX_CALL;
 | 
										call->kind = EX_CALL;
 | 
				
			||||||
					call->sub_count = 1;
 | 
										call->sub_count = 1;
 | 
				
			||||||
					call->subs[0] = e;
 | 
										call->subs[0] = e;
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
					if(!maybe(P, TOK_PAREN_R)) {
 | 
										if(!maybe(P, TOK_PAREN_R)) {
 | 
				
			||||||
						while(1) {
 | 
											while(1) {
 | 
				
			||||||
							call = realloc(call, sizeof(*call) + sizeof(Expr*) * (++call->sub_count));
 | 
												call->subs[call->sub_count++] = desc_exp(P);
 | 
				
			||||||
							call->subs[call->sub_count - 1] = desc_exp(P);
 | 
					 | 
				
			||||||
							
 | 
												
 | 
				
			||||||
							if(maybe(P, TOK_PAREN_R)) {
 | 
												if(maybe(P, TOK_PAREN_R)) {
 | 
				
			||||||
								break;
 | 
													break;
 | 
				
			||||||
@ -468,7 +492,7 @@ Expr *desc_subexp(Parser *P, int priority) {
 | 
				
			|||||||
					
 | 
										
 | 
				
			||||||
					e = call;
 | 
										e = call;
 | 
				
			||||||
				} else if(peek(P, -1).type == TOK_DOT) {
 | 
									} else if(peek(P, -1).type == TOK_DOT) {
 | 
				
			||||||
					Expr *dot = calloc(1, sizeof(*dot));
 | 
										Expr *dot = new_expr(0);
 | 
				
			||||||
					dot->kind = EX_INDEX;
 | 
										dot->kind = EX_INDEX;
 | 
				
			||||||
					dot->A = e;
 | 
										dot->A = e;
 | 
				
			||||||
					dot->B_tok = expect(P, TOK_NAME);
 | 
										dot->B_tok = expect(P, TOK_NAME);
 | 
				
			||||||
@ -932,7 +956,7 @@ bool parse_stat(Parser *P) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end;
 | 
							P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		P->scope = P->scope->parent;
 | 
							scope_kill(P);
 | 
				
			||||||
	} else if(maybe(P, TOK_FOR)) {
 | 
						} else if(maybe(P, TOK_FOR)) {
 | 
				
			||||||
		if(peek(P, 0).type == TOK_NAME && peek(P, 1).type == TOK_EQUAL) {
 | 
							if(peek(P, 0).type == TOK_NAME && peek(P, 1).type == TOK_EQUAL) {
 | 
				
			||||||
			// Range loop
 | 
								// Range loop
 | 
				
			||||||
@ -985,7 +1009,7 @@ bool parse_stat(Parser *P) {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end;
 | 
								P->current_chunk.instrs.data[jump2end].bc = P->current_chunk.instrs.size - 1 - jump2end;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			P->scope = P->scope->parent;
 | 
								scope_kill(P);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			expect(P, TOK_END);
 | 
								expect(P, TOK_END);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -1049,5 +1073,12 @@ LUnit *lparse(size_t sz, Token *tokens, LTable *environment) {
 | 
				
			|||||||
	unit->func_count = 1;
 | 
						unit->func_count = 1;
 | 
				
			||||||
	unit->funcs = P.unit_functions.data;
 | 
						unit->funcs = P.unit_functions.data;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						for(Expr *e = last_desc; e;) {
 | 
				
			||||||
 | 
							Expr *n = e->next_to_die;
 | 
				
			||||||
 | 
							free(e);
 | 
				
			||||||
 | 
							e = n;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						last_desc = NULL;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	return unit;
 | 
						return unit;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								table.h
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								table.h
									
									
									
									
									
								
							@ -59,7 +59,7 @@ static inline bool ltablebuckets_set(LTableBuckets *self, LValue key, LValue val
 | 
				
			|||||||
		LValue prevKey = {.u = LTAG_NIL};
 | 
							LValue prevKey = {.u = LTAG_NIL};
 | 
				
			||||||
		atomic_compare_exchange_strong(¤t[idx].key.u, &prevKey.u, key.u);
 | 
							atomic_compare_exchange_strong(¤t[idx].key.u, &prevKey.u, key.u);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if(prevKey.u == LTAG_NIL || prevKey.u == key.u) {
 | 
							if(prevKey.u == LTAG_NIL || lvalue_eq(prevKey, key)) {
 | 
				
			||||||
			atomic_store(¤t[idx].val.u, val.u);
 | 
								atomic_store(¤t[idx].val.u, val.u);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -76,11 +76,37 @@ static inline bool ltablebuckets_set(LTableBuckets *self, LValue key, LValue val
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void ltable_set(LTable *self, LValue key, LValue val) {
 | 
					static inline void ltable_set(LTable *self, LValue key, LValue val) {
 | 
				
			||||||
 | 
						if(lvalue_tag(key) == LTAG_I32 && lvalue_to_int32(key) < 9007199254740993UL) {
 | 
				
			||||||
 | 
							key = lvalue_from_double(lvalue_to_int32(key));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	if(!ltablebuckets_set(self->buckets, key, val)) {
 | 
						if(!ltablebuckets_set(self->buckets, key, val)) {
 | 
				
			||||||
		assert(0 && "No table resizing");
 | 
							assert(0 && "No table resizing");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool ltable_set_no_overwrite(LTable *tbl, LValue key, LValue val) {
 | 
				
			||||||
 | 
						LTableBuckets *self = tbl->buckets;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						size_t idx = lvalue_hash(key);
 | 
				
			||||||
 | 
						LTableEntry *current = self->data;
 | 
				
			||||||
 | 
						while(1) {
 | 
				
			||||||
 | 
							idx &= self->capacity - 1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							LValue prevKey = {.u = LTAG_NIL};
 | 
				
			||||||
 | 
							atomic_compare_exchange_strong(¤t[idx].key.u, &prevKey.u, key.u);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(prevKey.u == LTAG_NIL) {
 | 
				
			||||||
 | 
								atomic_store(¤t[idx].val.u, val.u);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							} else if(lvalue_eq(prevKey, key)) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							idx++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline LValue ltablebuckets_get(LTableBuckets *self, LValue key) {
 | 
					static inline LValue ltablebuckets_get(LTableBuckets *self, LValue key) {
 | 
				
			||||||
	size_t idx = lvalue_hash(key);
 | 
						size_t idx = lvalue_hash(key);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@ -103,5 +129,9 @@ static inline LValue ltablebuckets_get(LTableBuckets *self, LValue key) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline LValue ltable_get(LTable *self, LValue key) {
 | 
					static inline LValue ltable_get(LTable *self, LValue key) {
 | 
				
			||||||
 | 
						if(lvalue_tag(key) == LTAG_I32 && lvalue_to_int32(key) < 9007199254740993UL) {
 | 
				
			||||||
 | 
							key = lvalue_from_double(lvalue_to_int32(key));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	return ltablebuckets_get(self->buckets, key);
 | 
						return ltablebuckets_get(self->buckets, key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										375
									
								
								vm.c
									
									
									
									
									
								
							
							
						
						
									
										375
									
								
								vm.c
									
									
									
									
									
								
							@ -5,13 +5,14 @@
 | 
				
			|||||||
#include"str.h"
 | 
					#include"str.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include<math.h>
 | 
					#include<math.h>
 | 
				
			||||||
 | 
					#include<malloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LValue *regs) {
 | 
					static size_t lvm_run_internal(LVM *L, LFunc *func, size_t arg_count, set_LValueU *heap, LRegSet *regset) {
 | 
				
			||||||
	if(func->is_native) {
 | 
						if(func->is_native) {
 | 
				
			||||||
		return func->native_func(L, func->ud, arg_count, regs);
 | 
							return func->native_func(L, func->ud, arg_count, regset);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	static void *dispatch_table[] = {
 | 
						static const void *dispatch_table[] = {
 | 
				
			||||||
		[L_GETGLOBAL] = &&do_getglobal,
 | 
							[L_GETGLOBAL] = &&do_getglobal,
 | 
				
			||||||
		[L_SETGLOBAL] = &&do_setglobal,
 | 
							[L_SETGLOBAL] = &&do_setglobal,
 | 
				
			||||||
		[L_SETINT16] = &&do_setint16,
 | 
							[L_SETINT16] = &&do_setint16,
 | 
				
			||||||
@ -44,6 +45,8 @@ size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LValue *regs) {
 | 
				
			|||||||
	LInst *inst = func->lua_instrs;
 | 
						LInst *inst = func->lua_instrs;
 | 
				
			||||||
	#define DISPATCH() goto *dispatch_table[(++inst)->opcode]
 | 
						#define DISPATCH() goto *dispatch_table[(++inst)->opcode]
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						LThreadPrivates privates = {.regset = regset, .heap = heap};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	inst--;
 | 
						inst--;
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@ -53,9 +56,15 @@ do_getglobal:;
 | 
				
			|||||||
		size_t len = *(uint16_t*) area;
 | 
							size_t len = *(uint16_t*) area;
 | 
				
			||||||
		area += 2;
 | 
							area += 2;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		LString *str = lstring_new(len, area);
 | 
							LString *str = realloc(NULL, sizeof(*str) + len);
 | 
				
			||||||
		regs[inst->a] = ltable_get(func->env, lvalue_from_string(str));
 | 
							str->length = len;
 | 
				
			||||||
		lstring_free(str);
 | 
							memcpy(str->data, area, len);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							regset->regs[inst->a] = ltable_get(func->env, lvalue_from_string(str));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							set_LValueU_insert(heap, lvalue_from_string(str).u);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							lvm_gc_alert(L, &privates, sizeof(*str) + len);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@ -65,18 +74,24 @@ do_setglobal:;
 | 
				
			|||||||
		size_t len = *(uint16_t*) area;
 | 
							size_t len = *(uint16_t*) area;
 | 
				
			||||||
		area += 2;
 | 
							area += 2;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		LString *str = lstring_new(len, area);
 | 
							LString *str = realloc(NULL, sizeof(*str) + len);
 | 
				
			||||||
		ltable_set(func->env, lvalue_from_string(str), regs[inst->a]);
 | 
							str->length = len;
 | 
				
			||||||
		lvm_gc_add(L, lvalue_from_string(str));
 | 
							memcpy(str->data, area, len);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							ltable_set(func->env, lvalue_from_string(str), regset->regs[inst->a]);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							set_LValueU_insert(heap, lvalue_from_string(str).u);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							lvm_gc_alert(L, &privates, sizeof(*str) + len);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setint16:;
 | 
					do_setint16:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_int32((int16_t) inst->bc);
 | 
						regset->regs[inst->a] = lvalue_from_int32((int16_t) inst->bc);
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setint32:;
 | 
					do_setint32:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_int32(*(int32_t*) &unit->abyss[inst->bc]);
 | 
						regset->regs[inst->a] = lvalue_from_int32(*(int32_t*) &unit->abyss[inst->bc]);
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setfloat:;
 | 
					do_setfloat:;
 | 
				
			||||||
@ -88,87 +103,94 @@ do_setstr:;
 | 
				
			|||||||
		size_t len = *(uint16_t*) area;
 | 
							size_t len = *(uint16_t*) area;
 | 
				
			||||||
		area += 2;
 | 
							area += 2;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		regs[inst->a] = lvalue_raw(LTAG_STRING, (uintptr_t) lstring_new(len, area));
 | 
							LString *str = realloc(NULL, sizeof(*str) + len);
 | 
				
			||||||
		lvm_gc_add(L, regs[inst->a]);
 | 
							str->length = len;
 | 
				
			||||||
 | 
							memcpy(str->data, area, len);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							regset->regs[inst->a] = lvalue_from_string(str);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							set_LValueU_insert(heap, lvalue_from_string(str).u);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							lvm_gc_alert(L, &privates, sizeof(*str) + len);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_settable:;
 | 
					do_settable:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LTable *tbl = ltable_new(inst->bc);
 | 
							LTable *tbl = ltable_new(inst->bc);
 | 
				
			||||||
		lvm_gc_add(L, lvalue_from_table(tbl));
 | 
							regset->regs[inst->a] = lvalue_from_table(tbl);
 | 
				
			||||||
		regs[inst->a] = lvalue_from_table(tbl);
 | 
							set_LValueU_insert(heap, lvalue_from_table(tbl).u);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setbool:;
 | 
					do_setbool:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_bool(inst->b);
 | 
						regset->regs[inst->a] = lvalue_from_bool(inst->b);
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setnil:;
 | 
					do_setnil:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_nil();
 | 
						regset->regs[inst->a] = lvalue_from_nil();
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_setfunc:;
 | 
					do_setfunc:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_func(&func->unit->funcs[inst->bc]);
 | 
						regset->regs[inst->a] = lvalue_from_func(&func->unit->funcs[inst->bc]);
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_add:;
 | 
					do_add:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue x = regs[inst->b];
 | 
							LValue x = regset->regs[inst->b];
 | 
				
			||||||
		LValue y = regs[inst->c];
 | 
							LValue y = regset->regs[inst->c];
 | 
				
			||||||
		if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
							if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) + y.f);
 | 
								regset->regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) + y.f);
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(x.f + lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_double(x.f + lvalue_to_int32(y));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) + lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) + lvalue_to_int32(y));
 | 
				
			||||||
		} else goto err;
 | 
							} else goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_sub:;
 | 
					do_sub:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue x = regs[inst->b];
 | 
							LValue x = regset->regs[inst->b];
 | 
				
			||||||
		LValue y = regs[inst->c];
 | 
							LValue y = regset->regs[inst->c];
 | 
				
			||||||
		if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
							if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) - y.f);
 | 
								regset->regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) - y.f);
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(x.f - lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_double(x.f - lvalue_to_int32(y));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) - lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) - lvalue_to_int32(y));
 | 
				
			||||||
		} else goto err;
 | 
							} else goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_mul:;
 | 
					do_mul:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue x = regs[inst->b];
 | 
							LValue x = regset->regs[inst->b];
 | 
				
			||||||
		LValue y = regs[inst->c];
 | 
							LValue y = regset->regs[inst->c];
 | 
				
			||||||
		if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
							if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) * y.f);
 | 
								regset->regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) * y.f);
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(x.f * lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_double(x.f * lvalue_to_int32(y));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) * lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) * lvalue_to_int32(y));
 | 
				
			||||||
		} else goto err;
 | 
							} else goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_div:;
 | 
					do_div:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue x = regs[inst->b];
 | 
							LValue x = regset->regs[inst->b];
 | 
				
			||||||
		LValue y = regs[inst->c];
 | 
							LValue y = regset->regs[inst->c];
 | 
				
			||||||
		if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
							if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) / y.f);
 | 
								regset->regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) / y.f);
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(x.f / lvalue_to_int32(y));
 | 
								regset->regs[inst->a] = lvalue_from_double(x.f / lvalue_to_int32(y));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			int32_t yv = lvalue_to_int32(y);
 | 
								int32_t yv = lvalue_to_int32(y);
 | 
				
			||||||
			if(yv == 0) {
 | 
								if(yv == 0) {
 | 
				
			||||||
				regs[inst->a] = lvalue_from_nil();
 | 
									regset->regs[inst->a] = lvalue_from_nil();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) / yv);
 | 
									regset->regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) / yv);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else goto err;
 | 
							} else goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -176,19 +198,19 @@ do_div:;
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
do_mod:;
 | 
					do_mod:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue x = regs[inst->b];
 | 
							LValue x = regset->regs[inst->b];
 | 
				
			||||||
		LValue y = regs[inst->c];
 | 
							LValue y = regset->regs[inst->c];
 | 
				
			||||||
		if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
							if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) {
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(fmod(fmod(lvalue_to_int32(x), y.f) + y.f, y.f));
 | 
								regset->regs[inst->a] = lvalue_from_double(fmod(fmod(lvalue_to_int32(x), y.f) + y.f, y.f));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			int32_t yv = lvalue_to_int32(y);
 | 
								int32_t yv = lvalue_to_int32(y);
 | 
				
			||||||
			regs[inst->a] = lvalue_from_double(fmod(fmod(x.f, yv) + yv, yv));
 | 
								regset->regs[inst->a] = lvalue_from_double(fmod(fmod(x.f, yv) + yv, yv));
 | 
				
			||||||
		} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
							} else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) {
 | 
				
			||||||
			int32_t yv = lvalue_to_int32(y);
 | 
								int32_t yv = lvalue_to_int32(y);
 | 
				
			||||||
			if(yv == 0) {
 | 
								if(yv == 0) {
 | 
				
			||||||
				goto err;
 | 
									goto err;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				regs[inst->a] = lvalue_from_int32((lvalue_to_int32(x) % yv + yv) % yv);
 | 
									regset->regs[inst->a] = lvalue_from_int32((lvalue_to_int32(x) % yv + yv) % yv);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else goto err;
 | 
							} else goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -196,11 +218,13 @@ do_mod:;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
do_jump:;
 | 
					do_jump:;
 | 
				
			||||||
	inst += (int16_t) inst->bc;
 | 
						inst += (int16_t) inst->bc;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						L->safepoint_func(L, heap, regset);
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do_jnotcond:;
 | 
					do_jnotcond:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		LValue v = regs[inst->a];
 | 
							LValue v = regset->regs[inst->a];
 | 
				
			||||||
		if(v.u == LTAG_NIL || v.u == LTAG_FALSE) {
 | 
							if(v.u == LTAG_NIL || v.u == LTAG_FALSE) {
 | 
				
			||||||
			inst += (int16_t) inst->bc;
 | 
								inst += (int16_t) inst->bc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -209,7 +233,7 @@ do_jnotcond:;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
do_call:;
 | 
					do_call:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if(lvalue_tag(regs[inst->a]) != LTAG_FUNCTION) {
 | 
							if(lvalue_tag(regset->regs[inst->a]) != LTAG_FUNCTION) {
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -219,29 +243,29 @@ do_call:;
 | 
				
			|||||||
		uint8_t arg_count = abyss_data[1];
 | 
							uint8_t arg_count = abyss_data[1];
 | 
				
			||||||
		uint8_t *args = &abyss_data[2];
 | 
							uint8_t *args = &abyss_data[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LValue regs2[256];
 | 
							LRegSet regset2 = {.parent = regset};
 | 
				
			||||||
		lvm_reset_regs(regs2);
 | 
							lvm_reset_regs(®set2);
 | 
				
			||||||
		for(int i = 0; i < arg_count; i++) {
 | 
							for(int i = 0; i < arg_count; i++) {
 | 
				
			||||||
			regs2[i] = regs[args[i]];
 | 
								regset2.regs[i] = regset->regs[args[i]];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		size_t returned_count = lvm_run(L, (LFunc*) (regs[inst->a].u & ~LTAG_MASK), arg_count, regs2);
 | 
							size_t returned_count = lvm_run_internal(L, (LFunc*) (regset->regs[inst->a].u & ~LTAG_MASK), arg_count, heap, ®set2);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if(returned_count) {
 | 
							if(returned_count) {
 | 
				
			||||||
			// TODO: more than 1 return
 | 
								// TODO: more than 1 return
 | 
				
			||||||
			regs[ret_vreg] = regs2[0];
 | 
								regset->regs[ret_vreg] = regset2.regs[0];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do_move:;
 | 
					do_move:;
 | 
				
			||||||
	regs[inst->a] = regs[inst->b];
 | 
						regset->regs[inst->a] = regset->regs[inst->b];
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do_advancetest:;
 | 
					do_advancetest:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int64_t a = lvalue_to_int32(regs[inst->a]);
 | 
							int64_t a = lvalue_to_int32(regset->regs[inst->a]);
 | 
				
			||||||
		int64_t b = lvalue_to_int32(regs[inst->b]);
 | 
							int64_t b = lvalue_to_int32(regset->regs[inst->b]);
 | 
				
			||||||
		int64_t c = lvalue_to_int32(regs[inst->c]);
 | 
							int64_t c = lvalue_to_int32(regset->regs[inst->c]);
 | 
				
			||||||
		if(!((c >= 0 && a > b) || (c < 0 && a < b))) {
 | 
							if(!((c >= 0 && a > b) || (c < 0 && a < b))) {
 | 
				
			||||||
			inst++;
 | 
								inst++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -249,49 +273,65 @@ do_advancetest:;
 | 
				
			|||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_cond_eq:;
 | 
					do_cond_eq:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_bool(lvalue_eq(regs[inst->b], regs[inst->c]));
 | 
						regset->regs[inst->a] = lvalue_from_bool(lvalue_eq(regset->regs[inst->b], regset->regs[inst->c]));
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
do_cond_neq:;
 | 
					do_cond_neq:;
 | 
				
			||||||
	regs[inst->a] = lvalue_from_bool(!lvalue_eq(regs[inst->b], regs[inst->c]));
 | 
						regset->regs[inst->a] = lvalue_from_bool(!lvalue_eq(regset->regs[inst->b], regset->regs[inst->c]));
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do_setfield:;
 | 
					do_setfield:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if(lvalue_tag(regs[inst->a]) != LTAG_TABLE) {
 | 
							if(lvalue_tag(regset->regs[inst->a]) != LTAG_TABLE) {
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(lvalue_tag(regs[inst->b]) == LTAG_NIL) {
 | 
							if(lvalue_tag(regset->regs[inst->b]) == LTAG_NIL) {
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		LTable *tbl = (void*) (regs[inst->a].u & ~LTAG_MASK);
 | 
							LTable *tbl = (void*) (regset->regs[inst->a].u & ~LTAG_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ltable_set(tbl, regs[inst->b], regs[inst->c]);
 | 
							ltable_set(tbl, regset->regs[inst->b], regset->regs[inst->c]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do_getfield:;
 | 
					do_getfield:;
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if(lvalue_tag(regs[inst->a]) != LTAG_TABLE) {
 | 
							if(lvalue_tag(regset->regs[inst->a]) != LTAG_TABLE) {
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LTable *tbl = (void*) (regs[inst->b].u & ~LTAG_MASK);
 | 
							LTable *tbl = (void*) (regset->regs[inst->b].u & ~LTAG_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		regs[inst->a] = ltable_get(tbl, regs[inst->c]);
 | 
							regset->regs[inst->a] = ltable_get(tbl, regset->regs[inst->c]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	DISPATCH();
 | 
						DISPATCH();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
err:;
 | 
					err:;
 | 
				
			||||||
 | 
						puts("Error");
 | 
				
			||||||
do_ret:;
 | 
					do_ret:;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void lvm_gc_add(LVM *L, LValue lvalue) {
 | 
					size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LRegSet *regset) {
 | 
				
			||||||
	set_LValueU_insert(&L->gc_objects, lvalue.u);
 | 
						set_LValueU heap = {};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						atomic_fetch_add(&L->active_thread_count, 1);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						size_t ret = lvm_run_internal(L, func, arg_count, &heap, regset);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						mtx_lock(&L->dead_heap_mut);
 | 
				
			||||||
 | 
							for(c_each(i, set_LValueU, heap)) {
 | 
				
			||||||
 | 
								set_LValueU_insert(&L->dead_heap, *i.ref);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							atomic_fetch_sub(&L->active_thread_count, 1);
 | 
				
			||||||
 | 
						mtx_unlock(&L->dead_heap_mut);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_LValueU_drop(&heap);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LFunc *lvm_func_from_native(LFuncCallback cb, void *ud) {
 | 
					LFunc *lvm_func_from_native(LFuncCallback cb, void *ud) {
 | 
				
			||||||
@ -324,3 +364,206 @@ bool lvalue_eq(LValue a, LValue b) {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void gc_unmark_heap(set_LValueU *heap) {
 | 
				
			||||||
 | 
						for(c_each(i, set_LValueU, *heap)) {
 | 
				
			||||||
 | 
							LValue v = (LValue) {.u = *i.ref};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert(lvalue_tag(v) == LTAG_TABLE || lvalue_tag(v) == LTAG_STRING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void *gco = (void*) (v.u & ~LTAG_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(lvalue_tag(v) == LTAG_TABLE) {
 | 
				
			||||||
 | 
								LTable *tbl = gco;
 | 
				
			||||||
 | 
								tbl->ref = false;
 | 
				
			||||||
 | 
							} else if(lvalue_tag(v) == LTAG_STRING) {
 | 
				
			||||||
 | 
								LString *str = gco;
 | 
				
			||||||
 | 
								str->ref = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_unmark_all(LVM *L, size_t thread_count) {
 | 
				
			||||||
 | 
						for(size_t thrd = 0; thrd < thread_count; thrd++) {
 | 
				
			||||||
 | 
							LThreadPrivates *privates = &L->privates[thrd];
 | 
				
			||||||
 | 
							gc_unmark_heap(privates->heap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						gc_unmark_heap(&L->dead_heap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_mark(LValue v) {
 | 
				
			||||||
 | 
						if(lvalue_tag(v) != LTAG_TABLE && lvalue_tag(v) != LTAG_STRING) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *gco = (void*) (v.u & ~LTAG_MASK);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(lvalue_tag(v) == LTAG_TABLE) {
 | 
				
			||||||
 | 
							LTable *tbl = gco;
 | 
				
			||||||
 | 
							tbl->ref = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for(size_t i = 0; tbl->buckets->capacity; i++) {
 | 
				
			||||||
 | 
								LTableEntry e = tbl->buckets->data[i];
 | 
				
			||||||
 | 
								gc_mark(e.key);
 | 
				
			||||||
 | 
								gc_mark(e.val);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if(lvalue_tag(v) == LTAG_STRING) {
 | 
				
			||||||
 | 
							LString *str = gco;
 | 
				
			||||||
 | 
							str->ref = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_mark_units(LVM *L) {
 | 
				
			||||||
 | 
						for(size_t u = 0; u < L->unit_count; u++) {
 | 
				
			||||||
 | 
							LUnit *unit = &L->units[u];
 | 
				
			||||||
 | 
							for(size_t f = 0; f < unit->func_count; f++) {
 | 
				
			||||||
 | 
								LFunc *func = &unit->funcs[f];
 | 
				
			||||||
 | 
								gc_mark(lvalue_from_table(func->env));
 | 
				
			||||||
 | 
								for(size_t upv = 0; upv < func->upvalue_count; upv++) {
 | 
				
			||||||
 | 
									gc_mark(func->upvalues[upv]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void safepoint_active(LVM *L, set_LValueU *heap, LRegSet *regset) {
 | 
				
			||||||
 | 
						size_t my_privates_index = atomic_fetch_add(&L->privates_index, 1);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						L->privates[my_privates_index].heap = heap;
 | 
				
			||||||
 | 
						L->privates[my_privates_index].regset = regset;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						atomic_fetch_add(&L->privates_ready, 1);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Wait until GC finishes
 | 
				
			||||||
 | 
						while(atomic_load(&L->safepoint_func) == safepoint_active);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						atomic_fetch_sub(&L->privates_ready, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_mark_stacks(LVM *L, size_t thread_count) {
 | 
				
			||||||
 | 
						for(size_t thrd = 0; thrd < thread_count; thrd++) {
 | 
				
			||||||
 | 
							LThreadPrivates *privates = &L->privates[thrd];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							LRegSet *rset = privates->regset;
 | 
				
			||||||
 | 
							while(rset) {
 | 
				
			||||||
 | 
								for(size_t r = 0; r < 256; r++) {
 | 
				
			||||||
 | 
									gc_mark(rset->regs[r]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								rset = rset->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void safepoint_inactive(LVM *L, set_LValueU *heap, LRegSet *regset) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_delete_unmarked_in_heap(LVM *L, set_LValueU *heap) {
 | 
				
			||||||
 | 
						for(set_LValueU_iter i = set_LValueU_begin(heap); i.ref;) {
 | 
				
			||||||
 | 
							LValue v = (LValue) {.u = *i.ref};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void *gco = (void*) (v.u & ~LTAG_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(lvalue_tag(v) == LTAG_TABLE) {
 | 
				
			||||||
 | 
								LTable *tbl = gco;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if(tbl->ref == false) {
 | 
				
			||||||
 | 
									free(tbl->buckets);
 | 
				
			||||||
 | 
									free(tbl);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									i = set_LValueU_erase_at(heap, i);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if(lvalue_tag(v) == LTAG_STRING) {
 | 
				
			||||||
 | 
								LString *str = gco;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(str->ref == false) {
 | 
				
			||||||
 | 
									lvm_gc_alert(L, NULL, -sizeof(*str) - str->length);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									free(str);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									i = set_LValueU_erase_at(heap, i);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set_LValueU_next(&i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void gc_delete_unmarked(LVM *L, size_t thread_count) {
 | 
				
			||||||
 | 
						for(size_t thrd = 0; thrd < thread_count; thrd++) {
 | 
				
			||||||
 | 
							LThreadPrivates *privates = &L->privates[thrd];
 | 
				
			||||||
 | 
							gc_delete_unmarked_in_heap(L, privates->heap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						gc_delete_unmarked_in_heap(L, &L->dead_heap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void lvm_gc_force(LVM *L, LThreadPrivates *callerPrivates) {
 | 
				
			||||||
 | 
						// At most one thread can force GC, while others must behave as usual and enter a safepoint instead
 | 
				
			||||||
 | 
						if(atomic_compare_exchange_strong(&L->gcInProgress, &(bool) {false}, true)) {
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//static size_t gcidx = 0;
 | 
				
			||||||
 | 
							//fprintf(stderr, "GC %i (%lu bytes)\n", atomic_fetch_add(&gcidx, 1), L->memUsage);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(callerPrivates) {
 | 
				
			||||||
 | 
								// Called from within VM
 | 
				
			||||||
 | 
								atomic_store(&L->privates_index, 1);
 | 
				
			||||||
 | 
								atomic_store(&L->privates_ready, 1);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								L->privates[0] = *callerPrivates;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Called outside of VM, probably by lvm_destroy
 | 
				
			||||||
 | 
								atomic_store(&L->privates_index, 0);
 | 
				
			||||||
 | 
								atomic_store(&L->privates_ready, 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							L->safepoint_func = safepoint_active;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Wait until other threads have entered GC stage
 | 
				
			||||||
 | 
							while(atomic_load(&L->privates_ready) < atomic_load(&L->active_thread_count));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							size_t thread_count = atomic_load(&L->privates_ready);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							mtx_lock(&L->dead_heap_mut);
 | 
				
			||||||
 | 
								gc_unmark_all(L, thread_count);
 | 
				
			||||||
 | 
								gc_mark_stacks(L, thread_count);
 | 
				
			||||||
 | 
								gc_mark_units(L);
 | 
				
			||||||
 | 
								gc_delete_unmarked(L, thread_count);
 | 
				
			||||||
 | 
							mtx_unlock(&L->dead_heap_mut);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							while(L->memUsage > L->nextGCThreshold) {
 | 
				
			||||||
 | 
								L->nextGCThreshold <<= 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							L->safepoint_func = safepoint_inactive;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(callerPrivates) {
 | 
				
			||||||
 | 
								// Called from within VM
 | 
				
			||||||
 | 
								atomic_fetch_sub(&L->privates_ready, 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Wait until other threads have left GC stage
 | 
				
			||||||
 | 
							while(atomic_load(&L->privates_ready) > 0);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							atomic_store(&L->gcInProgress, false);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// `privates` can be NULL but ONLY IF diff < 0
 | 
				
			||||||
 | 
					void lvm_gc_alert(LVM *L, LThreadPrivates *privates, intmax_t diff) {
 | 
				
			||||||
 | 
						L->memUsage += diff;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						assert(L->memUsage >= 0);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(L->memUsage > L->nextGCThreshold) {
 | 
				
			||||||
 | 
							lvm_gc_force(L, privates);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void lvm_init(LVM *L) {
 | 
				
			||||||
 | 
						memset(L, 0, sizeof(*L));
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						L->safepoint_func = safepoint_inactive;
 | 
				
			||||||
 | 
						L->nextGCThreshold = 16384;
 | 
				
			||||||
 | 
						mtx_init(&L->dead_heap_mut, mtx_plain);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void lvm_destroy(LVM *L) {
 | 
				
			||||||
 | 
						mtx_destroy(&L->dead_heap_mut);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						lvm_gc_force(L, NULL);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						set_LValueU_drop(&L->dead_heap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										41
									
								
								vm.h
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								vm.h
									
									
									
									
									
								
							@ -7,6 +7,7 @@
 | 
				
			|||||||
#include<stdlib.h>
 | 
					#include<stdlib.h>
 | 
				
			||||||
#include<stdio.h>
 | 
					#include<stdio.h>
 | 
				
			||||||
#include<string.h>
 | 
					#include<string.h>
 | 
				
			||||||
 | 
					#include<threads.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include"table.h"
 | 
					#include"table.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,7 +69,12 @@ typedef union __attribute__((packed)) {
 | 
				
			|||||||
struct LUnit;
 | 
					struct LUnit;
 | 
				
			||||||
struct LVM;
 | 
					struct LVM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef size_t(*LFuncCallback)(struct LVM*, void *ud, size_t argn, LValue *args);
 | 
					typedef struct LRegSet {
 | 
				
			||||||
 | 
						struct LRegSet *parent;
 | 
				
			||||||
 | 
						LValue regs[256];
 | 
				
			||||||
 | 
					} LRegSet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef size_t(*LFuncCallback)(struct LVM*, void *ud, size_t argn, LRegSet *regset);
 | 
				
			||||||
typedef struct LFunc {
 | 
					typedef struct LFunc {
 | 
				
			||||||
	struct LUnit *unit;
 | 
						struct LUnit *unit;
 | 
				
			||||||
	bool is_native;
 | 
						bool is_native;
 | 
				
			||||||
@ -98,20 +104,43 @@ typedef struct LUnit {
 | 
				
			|||||||
#include"stc/hashset.h"
 | 
					#include"stc/hashset.h"
 | 
				
			||||||
#undef i_header
 | 
					#undef i_header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct LThreadPrivates {
 | 
				
			||||||
 | 
						set_LValueU *heap;
 | 
				
			||||||
 | 
						LRegSet *regset;
 | 
				
			||||||
 | 
					} LThreadPrivates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define L_THREADS_MAX 32
 | 
				
			||||||
typedef struct LVM {
 | 
					typedef struct LVM {
 | 
				
			||||||
	size_t unit_count;
 | 
						size_t unit_count;
 | 
				
			||||||
	LUnit *units;
 | 
						LUnit *units;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	set_LValueU gc_objects;
 | 
						// The following is all used for GC
 | 
				
			||||||
 | 
						_Atomic bool gcInProgress;
 | 
				
			||||||
 | 
						_Atomic size_t nextGCThreshold;
 | 
				
			||||||
 | 
						_Atomic intmax_t memUsage;
 | 
				
			||||||
 | 
						_Atomic size_t active_thread_count;
 | 
				
			||||||
 | 
						_Atomic size_t privates_index;
 | 
				
			||||||
 | 
						_Atomic size_t privates_ready;
 | 
				
			||||||
 | 
						LThreadPrivates privates[L_THREADS_MAX];
 | 
				
			||||||
 | 
					 	void(*safepoint_func)(struct LVM*, set_LValueU*, LRegSet*);
 | 
				
			||||||
 | 
					 	
 | 
				
			||||||
 | 
					 	// The dead heap stores the heap of threads that have exited
 | 
				
			||||||
 | 
					 	// This is rare enough that it's done with a lock
 | 
				
			||||||
 | 
					 	mtx_t dead_heap_mut;
 | 
				
			||||||
 | 
					 	set_LValueU dead_heap;
 | 
				
			||||||
} LVM;
 | 
					} LVM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LValue *regs);
 | 
					size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LRegSet *regset);
 | 
				
			||||||
void lvm_gc_add(LVM *L, LValue lvalue);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
LFunc *lvm_func_from_native(LFuncCallback, void *ud);
 | 
					LFunc *lvm_func_from_native(LFuncCallback, void *ud);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void lvm_reset_regs(LValue *regs) {
 | 
					void lvm_init(LVM *L);
 | 
				
			||||||
 | 
					void lvm_destroy(LVM *L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void lvm_gc_alert(LVM *L, LThreadPrivates*, intmax_t diff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void lvm_reset_regs(LRegSet *regset) {
 | 
				
			||||||
	for(int i = 0; i < 256; i++) {
 | 
						for(int i = 0; i < 256; i++) {
 | 
				
			||||||
		regs[i] = lvalue_from_nil();
 | 
							regset->regs[i] = lvalue_from_nil();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user