int subtype_kind_overlap(reach_type_t* left, reach_type_t* right) { int subtypes = SUBTYPE_KIND_NONE; size_t i = HASHMAP_BEGIN; reach_type_t* sub_left; while((sub_left = reach_type_cache_next(&left->subtypes, &i)) != NULL) { if(!sub_left->can_be_boxed) { subtypes |= SUBTYPE_KIND_UNBOXED; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; continue; } if(sub_left->underlying != TK_TUPLETYPE) { reach_type_t k; k.name = sub_left->name; size_t j = HASHMAP_UNKNOWN; reach_type_t* sub_right = reach_type_cache_get(&right->subtypes, &k, &j); if(sub_right != NULL) { pony_assert(sub_left == sub_right); if(sub_left->underlying == TK_PRIMITIVE) subtypes |= SUBTYPE_KIND_NUMERIC; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; } } else if((subtypes & SUBTYPE_KIND_TUPLE) == 0) { size_t cardinality = ast_childcount(sub_left->ast_cap); size_t j = HASHMAP_UNKNOWN; reach_type_t* sub_right; while((sub_right = reach_type_cache_next(&right->subtypes, &j)) != NULL) { if((sub_right->underlying == TK_TUPLETYPE) && (ast_childcount(sub_right->ast_cap) == cardinality)) { subtypes |= SUBTYPE_KIND_TUPLE; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; break; } } } } return subtypes; }
void reach_dump(reach_t* r) { printf("REACH\n"); size_t i = HASHMAP_BEGIN; reach_type_t* t; while((t = reach_types_next(&r->types, &i)) != NULL) { printf(" %d: %s, %s\n", t->type_id, t->name, t->mangle); size_t j = HASHMAP_BEGIN; reach_method_name_t* n; printf(" size: " __zu "\n", t->abi_size); printf(" vtable: %d\n", t->vtable_size); while((n = reach_method_names_next(&t->methods, &j)) != NULL) { size_t k = HASHMAP_BEGIN; reach_method_t* m; while((m = reach_mangled_next(&n->r_mangled, &k)) != NULL) printf(" %d: %s\n", m->vtable_index, m->mangled_name); } j = HASHMAP_BEGIN; reach_type_t* t2; while((t2 = reach_type_cache_next(&t->subtypes, &j)) != NULL) { printf(" %s\n", t2->name); } } }
int subtype_kind(reach_type_t* type) { int subtypes = SUBTYPE_KIND_NONE; size_t i = HASHMAP_BEGIN; reach_type_t* sub; while((sub = reach_type_cache_next(&type->subtypes, &i)) != NULL) { if(sub->can_be_boxed) { if(type->underlying == TK_PRIMITIVE) subtypes |= SUBTYPE_KIND_NUMERIC; else subtypes |= SUBTYPE_KIND_TUPLE; } else { subtypes |= SUBTYPE_KIND_UNBOXED; } if(subtypes == SUBTYPE_KIND_ALL) return subtypes; } return subtypes; }
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; } } } }
static void add_rmethod_to_subtypes(reach_t* r, reach_type_t* t, reach_method_name_t* n, reach_method_t* m, pass_opt_t* opt) { switch(ast_id(t->ast)) { case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(t->ast); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: { // Add to subtypes if we're an interface or trait. size_t i = HASHMAP_BEGIN; reach_type_t* t2; while((t2 = reach_type_cache_next(&t->subtypes, &i)) != NULL) add_rmethod_to_subtype(r, t2, n, m, opt); break; } default: {} } return; } case TK_UNIONTYPE: case TK_ISECTTYPE: { ast_t* child = ast_child(t->ast); while(child != NULL) { ast_t* find = lookup_try(NULL, NULL, child, n->name); if(find != NULL) { reach_type_t* t2 = add_type(r, child, opt); add_rmethod_to_subtype(r, t2, n, m, opt); ast_free_unattached(find); } child = ast_sibling(child); } return; } default: {} } assert(0); }
static int boxed_subtypes_overlap(reach_t* reach, ast_t* left_type, ast_t* right_type) { reach_type_t* r_left = reach_type(reach, left_type); reach_type_t* r_right = reach_type(reach, right_type); int subtypes = BOXED_SUBTYPES_NONE; size_t i = HASHMAP_BEGIN; reach_type_t* sub_left; while((sub_left = reach_type_cache_next(&r_left->subtypes, &i)) != NULL) { if(!sub_left->can_be_boxed) { subtypes |= BOXED_SUBTYPES_UNBOXED; if(subtypes == BOXED_SUBTYPES_ALL) return subtypes; continue; } size_t j = HASHMAP_BEGIN; reach_type_t* sub_right; while((sub_right = reach_type_cache_next(&r_right->subtypes, &j)) != NULL) { if(sub_left == sub_right) { if(sub_left->underlying == TK_PRIMITIVE) subtypes |= BOXED_SUBTYPES_NUMERIC; else subtypes |= BOXED_SUBTYPES_TUPLE; if(subtypes == BOXED_SUBTYPES_ALL) return subtypes; } } } return subtypes; }
static uint32_t trait_count(reach_type_t* t, uint32_t** list, size_t* list_size) { switch(t->underlying) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { uint32_t count = (uint32_t)reach_type_cache_size(&t->subtypes); if(count == 0) return 0; // Sort the trait identifiers. size_t tid_size = count * sizeof(uint32_t); uint32_t* tid = (uint32_t*)ponyint_pool_alloc_size(tid_size); size_t i = HASHMAP_BEGIN; size_t index = 0; reach_type_t* provide; while((provide = reach_type_cache_next(&t->subtypes, &i)) != NULL) tid[index++] = provide->type_id; qsort(tid, index, sizeof(uint32_t), cmp_uint32); count = (uint32_t)unique_uint32(tid, index); if(list != NULL) { *list = tid; *list_size = tid_size; } else { ponyint_pool_free_size(tid_size, tid); } return count; } default: {} } return 0; }
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 can_inline_message_send(reach_type_t* t, reach_method_t* m, const char* method_name) { switch(t->underlying) { case TK_CLASS: case TK_STRUCT: case TK_PRIMITIVE: return false; case TK_ACTOR: return true; default: {} } size_t i = HASHMAP_BEGIN; reach_type_t* sub; while((sub = reach_type_cache_next(&t->subtypes, &i)) != NULL) { reach_method_t* m_sub = reach_method(sub, m->cap, method_name, m->typeargs); if(m_sub == NULL) continue; switch(sub->underlying) { case TK_CLASS: case TK_PRIMITIVE: return false; case TK_ACTOR: if(ast_id(m_sub->r_fun) == TK_FUN) return false; break; default: {} } pony_assert(m->param_count == m_sub->param_count); for(size_t i = 0; i < m->param_count; i++) { // If the param is a boxable type for us and an unboxable type for one of // our subtypes, that subtype will take that param as boxed through an // interface. In order to correctly box the value the actual function to // call must be resolved through name mangling, therefore we can't inline // the message send. reach_type_t* param = m->params[i].type; reach_type_t* sub_param = m_sub->params[i].type; if(param->can_be_boxed) { if(!sub_param->can_be_boxed) return false; if(param->underlying == TK_TUPLETYPE) { ast_t* child = ast_child(param->ast); while(child != NULL) { if(contains_boxable(child)) return false; } } } } } return true; }