static void add_method(reachable_method_stack_t** s, reachable_type_t* t, const char* name, ast_t* typeargs) { reachable_method_name_t* n = reach_method_name(t, name); if(n == NULL) { n = POOL_ALLOC(reachable_method_name_t); n->name = name; reachable_methods_init(&n->r_methods, 0); reachable_method_names_put(&t->methods, n); } add_rmethod(s, t, n, typeargs); // Add to subtypes if we're an interface or trait. ast_t* def = (ast_t*)ast_data(t->type); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: { size_t i = HASHMAP_BEGIN; reachable_type_t* t2; while((t2 = reachable_type_cache_next(&t->subtypes, &i)) != NULL) add_method(s, t2, name, typeargs); break; } default: {} } }
reach_method_t* reach_method(reach_type_t* t, token_id cap, const char* name, ast_t* typeargs) { reach_method_name_t* n = reach_method_name(t, name); if(n == NULL) return NULL; if((n->id == TK_FUN) && ((n->cap == TK_BOX) || (n->cap == TK_TAG))) { switch(cap) { case TK_ISO: case TK_TRN: cap = TK_REF; break; case TK_REF: case TK_VAL: case TK_BOX: break; default: cap = n->cap; } } else { cap = n->cap; } name = genname_fun(cap, n->name, typeargs); return reach_rmethod(n, name); }
static bool need_primitive_call(compile_t* c, const char* method) { size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { if(ast_id(t->type) == TK_TUPLETYPE) continue; ast_t* def = (ast_t*)ast_data(t->type); if(ast_id(def) != TK_PRIMITIVE) continue; reachable_method_name_t* n = reach_method_name(t, method); if(n == NULL) continue; return true; } return false; }
static void set_method_external_interface(reach_type_t* t, const char* name, uint32_t vtable_index) { size_t i = HASHMAP_BEGIN; reach_type_t* sub; while((sub = reach_type_cache_next(&t->subtypes, &i)) != NULL) { reach_method_name_t* n = reach_method_name(sub, name); if(n == NULL) continue; size_t j = HASHMAP_BEGIN; reach_method_t* m; while((m = reach_mangled_next(&n->r_mangled, &j)) != NULL) { if(m->vtable_index == vtable_index) { compile_method_t* c_m = (compile_method_t*)m->c_method; LLVMSetFunctionCallConv(c_m->func, LLVMCCallConv); LLVMSetLinkage(c_m->func, LLVMExternalLinkage); break; } } } }
reachable_method_t* reach_method(reachable_type_t* t, const char* name, ast_t* typeargs) { reachable_method_name_t* n = reach_method_name(t, name); if(n == NULL) return NULL; return reach_method_instance(n, typeargs); }
static void set_method_external_nominal(reach_type_t* t, const char* name) { reach_method_name_t* n = reach_method_name(t, name); if(n != NULL) { size_t i = HASHMAP_BEGIN; reach_method_t* m; while((m = reach_methods_next(&n->r_methods, &i)) != NULL) { LLVMSetFunctionCallConv(m->func, LLVMCCallConv); LLVMSetLinkage(m->func, LLVMExternalLinkage); } } }
static void primitive_call(compile_t* c, const char* method, LLVMValueRef arg) { size_t count = 1; if(arg != NULL) count++; size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { if(ast_id(t->type) == TK_TUPLETYPE) continue; ast_t* def = (ast_t*)ast_data(t->type); if(ast_id(def) != TK_PRIMITIVE) continue; reachable_method_name_t* n = reach_method_name(t, method); if(n == NULL) continue; gentype_t g; if(!gentype(c, t->type, &g)) { assert(0); return; } LLVMValueRef fun = genfun_proto(c, &g, method, NULL); assert(fun != NULL); LLVMValueRef args[2]; args[0] = g.instance; args[1] = arg; codegen_call(c, fun, args, count); } }
static reach_method_name_t* add_method_name(reach_type_t* t, const char* name) { reach_method_name_t* n = reach_method_name(t, name); if(n == NULL) { n = POOL_ALLOC(reach_method_name_t); n->name = name; reach_methods_init(&n->r_methods, 0); reach_mangled_init(&n->r_mangled, 0); reach_method_names_put(&t->methods, n); ast_t* fun = lookup(NULL, NULL, t->ast, name); n->id = ast_id(fun); n->cap = ast_id(ast_child(fun)); ast_free_unattached(fun); } return n; }
static void set_method_external_interface(reach_type_t* t, const char* name) { set_method_external_nominal(t, name); size_t i = HASHMAP_BEGIN; reach_type_t* sub; while((sub = reach_type_cache_next(&t->subtypes, &i)) != NULL) { reach_method_name_t* n = reach_method_name(sub, name); if(n == NULL) continue; size_t j = HASHMAP_BEGIN; reach_method_t* m; while((m = reach_methods_next(&n->r_methods, &j)) != NULL) { LLVMSetFunctionCallConv(m->func, LLVMCCallConv); LLVMSetLinkage(m->func, LLVMExternalLinkage); } } }
static bool need_primitive_call(compile_t* c, const char* method) { size_t i = HASHMAP_BEGIN; reach_type_t* t; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { if(t->underlying != TK_PRIMITIVE) continue; reach_method_name_t* n = reach_method_name(t, method); if(n == NULL) continue; return true; } return false; }
static uint32_t vtable_index(compile_t* c, const char* type_name, const char* name, ast_t* typeargs) { reachable_type_t* t = reach_type(c->reachable, type_name); if(t == NULL) return -1; reachable_method_name_t* n = reach_method_name(t, name); if(n == NULL) return -1; if(typeargs != NULL) name = genname_fun(NULL, name, typeargs); reachable_method_t* m = reach_method(n, name); if(m == NULL) return -1; assert(m->vtable_index != (uint32_t)-1); return m->vtable_index; }