void reach_dump(reachable_types_t* r) { printf("REACH\n"); size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(r, &i)) != NULL) { printf(" %s vtable size %d\n", t->name, t->vtable_size); size_t j = HASHMAP_BEGIN; reachable_method_name_t* m; while((m = reachable_method_names_next(&t->methods, &j)) != NULL) { size_t k = HASHMAP_BEGIN; reachable_method_t* p; while((p = reachable_methods_next(&m->r_methods, &k)) != NULL) { printf(" %s vtable index %d (%p)\n", p->name, p->vtable_index, p); } } } }
bool genfun_method_bodies(compile_t* c, reachable_type_t* t) { switch(t->underlying) { case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: break; default: return true; } size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { if(m->intrinsic) continue; switch(ast_id(m->r_fun)) { case TK_NEW: if(t->underlying == TK_ACTOR) { if(!genfun_newbe(c, t, m)) return false; } else { if(!genfun_new(c, t, m)) return false; } break; case TK_BE: if(!genfun_be(c, t, m)) return false; break; case TK_FUN: if(!genfun_fun(c, t, m)) return false; break; default: assert(0); return false; } } } return true; }
static LLVMValueRef make_vtable(compile_t* c, gentype_t* g) { uint32_t vtable_size = genfun_vtable_size(c, g); if(vtable_size == 0) return LLVMConstArray(c->void_ptr, NULL, 0); size_t buf_size = vtable_size * sizeof(LLVMValueRef); LLVMValueRef* vtable = (LLVMValueRef*)pool_alloc_size(buf_size); memset(vtable, 0, buf_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { const char* fullname = genname_fun(t->name, n->name, m->typeargs); token_id t = ast_id(m->r_fun); switch(t) { case TK_NEW: case TK_BE: if(g->underlying == TK_ACTOR) fullname = genname_be(fullname); break; default: {} } uint32_t index = m->vtable_index; assert(index != (uint32_t)-1); assert(vtable[index] == NULL); if(g->primitive != NULL) vtable[index] = make_unbox_function(c, g, fullname, t); else vtable[index] = make_function_ptr(c, fullname, c->void_ptr); } } for(uint32_t i = 0; i < vtable_size; i++) { if(vtable[i] == NULL) vtable[i] = LLVMConstNull(c->void_ptr); } LLVMValueRef r = LLVMConstArray(c->void_ptr, vtable, vtable_size); pool_free_size(buf_size, vtable); return r; }
size_t reach_method_count(reachable_type_t* t) { size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; size_t count = 0; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) count += reachable_methods_size(&n->r_methods); return count; }
static void print_methods(compile_t* c, reachable_type_t* t, printbuf_t* buf) { size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) print_method(c, buf, t, n->name, m->typeargs); } }
static void add_methods_to_type(reachable_method_stack_t** s, reachable_type_t* from, reachable_type_t* to) { size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&from->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) add_method(s, to, n->name, m->typeargs); } }
bool genfun_methods(compile_t* c, gentype_t* g) { reachable_type_t* t = reach_type(c->reachable, g->type_name); size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; LLVMValueRef fun; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { switch(ast_id(m->r_fun)) { case TK_NEW: if(g->underlying == TK_ACTOR) fun = genfun_newbe(c, g, n->name, m->typeargs); else fun = genfun_new(c, g, n->name, m->typeargs); break; case TK_BE: fun = genfun_be(c, g, n->name, m->typeargs); break; case TK_FUN: fun = genfun_fun(c, g, n->name, m->typeargs); break; default: fun = NULL; break; } if(fun == NULL) return false; } } if(!genfun_allocator(c, g)) return false; return true; }
// Step 1 static void find_names_types_use(painter_t* painter, reachable_types_t* types) { assert(painter != NULL); assert(types != NULL); size_t i = HASHMAP_BEGIN; size_t typemap_index = 0; uint64_t typemap_mask = 1; reachable_type_t* type; while((type = reachable_types_next(types, &i)) != NULL) { assert(typemap_index < painter->typemap_size); size_t j = HASHMAP_BEGIN; reachable_method_name_t* mn; while((mn = reachable_method_names_next(&type->methods, &j)) != NULL) { size_t k = HASHMAP_BEGIN; reachable_method_t* method; while((method = reachable_methods_next(&mn->r_methods, &k)) != NULL) { const char* name = method->name; name_record_t* name_rec = find_name(painter, name); if(name_rec == NULL) // This is the first use of this name name_rec = add_name(painter, name); // Mark this name as using the current type name_rec->type_map[typemap_index] |= typemap_mask; } } // Advance to next type bitmap entry typemap_mask <<= 1; if(typemap_mask == 0) { typemap_mask = 1; typemap_index++; } } }
// Step 5 static void distribute_info(painter_t* painter, reachable_types_t* types) { assert(painter != NULL); assert(types != NULL); size_t i = HASHMAP_BEGIN; reachable_type_t* type; // Iterate over all types while((type = reachable_types_next(types, &i)) != NULL) { if(reachable_method_names_size(&type->methods) == 0) continue; size_t j = HASHMAP_BEGIN; reachable_method_name_t* mn; uint32_t max_colour = 0; // Iterate over all method names in type while((mn = reachable_method_names_next(&type->methods, &j)) != NULL) { size_t k = HASHMAP_BEGIN; reachable_method_t* method; while((method = reachable_methods_next(&mn->r_methods, &k)) != NULL) { // Store colour assigned to name in reachable types set const char* name = method->name; name_record_t* name_rec = find_name(painter, name); assert(name_rec != NULL); uint32_t colour = name_rec->colour; method->vtable_index = colour; if(colour > max_colour) max_colour = colour; } } // Store vtable size for type type->vtable_size = max_colour + 1; } }
bool genfun_method_sigs(compile_t* c, reachable_type_t* t) { size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) make_prototype(c, t, m); } if(!genfun_allocator(c, t)) return false; return true; }