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); } } } }
static void print_types(compile_t* c, FILE* fp, printbuf_t* buf) { size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { // Print the docstring if we have one. ast_t* def = (ast_t*)ast_data(t->ast); ast_t* docstring = ast_childidx(def, 6); if(ast_id(docstring) == TK_STRING) fprintf(fp, "/*\n%s*/\n", ast_name(docstring)); if(!is_pointer(t->ast) && !is_maybe(t->ast) && !is_machine_word(t->ast)) { // Forward declare an opaque type. fprintf(fp, "typedef struct %s %s;\n\n", t->name, t->name); // Function signature for the allocator. printbuf(buf, "/* Allocate a %s without initialising it. */\n%s* %s_Alloc();\n\n", t->name, t->name, t->name ); } print_methods(c, t, buf); } }
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 add_traits_to_type(reachable_method_stack_t** s, reachable_types_t* r, reachable_type_t* t) { size_t i = HASHMAP_BEGIN; reachable_type_t* t2; while((t2 = reachable_types_next(r, &i)) != NULL) { if(ast_id(t2->type) == TK_TUPLETYPE) continue; ast_t* def = (ast_t*)ast_data(t2->type); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: if(is_subtype(t->type, t2->type, NULL)) { reachable_type_cache_put(&t->subtypes, t2); reachable_type_cache_put(&t2->subtypes, t); add_methods_to_type(s, t2, t); } break; default: {} } } }
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(t->underlying != TK_PRIMITIVE) continue; reachable_method_t* m = reach_method(t, method, NULL); if(m == NULL) continue; LLVMValueRef args[2]; args[0] = t->instance; args[1] = arg; codegen_call(c, m->func, args, count); } }
// 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; } }
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 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(t->underlying != TK_TUPLETYPE) continue; reachable_method_name_t* n = reach_method_name(t, method); if(n == NULL) continue; return true; } return false; }
static void add_types_to_trait(reachable_method_stack_t** s, reachable_types_t* r, reachable_type_t* t) { size_t i = HASHMAP_BEGIN; reachable_type_t* t2; ast_t* def = (ast_t*)ast_data(t->type); bool interface = ast_id(def) == TK_INTERFACE; while((t2 = reachable_types_next(r, &i)) != NULL) { if(ast_id(t2->type) == TK_TUPLETYPE) continue; ast_t* def2 = (ast_t*)ast_data(t2->type); switch(ast_id(def2)) { case TK_INTERFACE: { // Use the same typeid. if(interface && is_eqtype(t->type, t2->type, NULL)) t->type_id = t2->type_id; break; } case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: if(is_subtype(t2->type, t->type, NULL)) { reachable_type_cache_put(&t->subtypes, t2); reachable_type_cache_put(&t2->subtypes, t); add_methods_to_type(s, t, t2); } break; default: {} } } }
bool gentypes(compile_t* c) { reachable_type_t* t; size_t i; genprim_builtins(c); PONY_LOG(c->opt, VERBOSITY_INFO, (" Data prototypes\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_opaque_struct(c, t)) return false; gendesc_type(c, t); make_debug_info(c, t); make_box_type(c, t); make_dispatch(c, t); gentrace_prototype(c, t); } PONY_LOG(c->opt, VERBOSITY_INFO, (" Data types\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_struct(c, t)) return false; make_global_instance(c, t); } PONY_LOG(c->opt, VERBOSITY_INFO, (" Function prototypes\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { make_debug_final(c, t); make_pointer_methods(c, t); if(!genfun_method_sigs(c, t)) return false; } PONY_LOG(c->opt, VERBOSITY_INFO, (" Functions\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!genfun_method_bodies(c, t)) return false; } PONY_LOG(c->opt, VERBOSITY_INFO, (" Descriptors\n")); i = HASHMAP_BEGIN; while((t = reachable_types_next(&c->reachable->types, &i)) != NULL) { if(!make_trace(c, t)) return false; gendesc_init(c, t); } return true; }