char* CFCBindMeth_method_def(CFCMethod *method, CFCClass *klass) { // If the method is final and the class where it is declared final is in // the same parcel as the invocant, we can optimize the call by resolving // to the implementing function directly. if (CFCMethod_final(method)) { CFCClass *ancestor = klass; while (ancestor && !CFCMethod_is_fresh(method, ancestor)) { ancestor = CFCClass_get_parent(ancestor); } if (CFCClass_get_parcel(ancestor) == CFCClass_get_parcel(klass)) { return S_optimized_final_method_def(method, klass); } } return S_virtual_method_def(method, klass); }
static char* S_method_def(CFCMethod *method, CFCClass *klass, int optimized_final_meth) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *PREFIX = CFCClass_get_PREFIX(klass); const char *invoker_struct = CFCClass_full_struct_sym(klass); const char *self_name = CFCParamList_param_name(param_list, 0); char *full_meth_sym = CFCMethod_full_method_sym(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_imp_sym = CFCMethod_imp_func(method, klass); // Prepare parameter lists, minus the type of the invoker. if (CFCParamList_variadic(param_list)) { CFCUtil_die("Variadic methods not supported"); } const char *arg_names = CFCParamList_name_list(param_list); const char *params_end = CFCParamList_to_c(param_list); while (*params_end && *params_end != '*') { params_end++; } // Prepare a return statement... or not. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *maybe_return = CFCType_is_void(return_type) ? "" : "return "; const char innards_pattern[] = " const %s method = (%s)cfish_obj_method(%s, %s);\n" " %smethod(%s);\n" ; char *innards = CFCUtil_sprintf(innards_pattern, full_typedef, full_typedef, self_name, full_offset_sym, maybe_return, arg_names); if (optimized_final_meth) { CFCParcel *parcel = CFCClass_get_parcel(klass); const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); char *invoker_cast = CFCUtil_strdup(""); if (!CFCMethod_is_fresh(method, klass)) { CFCType *self_type = CFCMethod_self_type(method); invoker_cast = CFCUtil_cat(invoker_cast, "(", CFCType_to_c(self_type), ")", NULL); } const char pattern[] = "#ifdef %s\n" " %s%s(%s%s);\n" "#else\n" "%s" "#endif\n" ; char *temp = CFCUtil_sprintf(pattern, privacy_sym, maybe_return, full_imp_sym, invoker_cast, arg_names, innards); FREEMEM(innards); innards = temp; FREEMEM(invoker_cast); } const char pattern[] = "extern %sVISIBLE uint32_t %s;\n" "static CFISH_INLINE %s\n" "%s(%s%s) {\n" "%s" "}\n"; char *method_def = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_end, innards); FREEMEM(innards); FREEMEM(full_imp_sym); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }
void CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) { if (CFCClass_inert(klass)) { return; } const char *class_name = CFCClass_get_name(klass); const char *class_var = CFCClass_full_class_var(klass); const char *ivars_offset_name = CFCClass_full_ivars_offset(klass); const char *flags = CFCClass_final(klass) ? "cfish_ClassSpec_FINAL" : "0"; char *ivars_size = S_ivars_size(klass); char *parent_ptr = NULL; CFCClass *parent = CFCClass_get_parent(klass); if (!parent) { parent_ptr = CFCUtil_strdup("NULL"); } else { if (CFCClass_in_same_parcel(klass, parent)) { parent_ptr = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent)); } else { parent_ptr = CFCUtil_strdup("NULL"); const char *class_name = CFCClass_get_name(klass); const char *parent_var = CFCClass_full_class_var(parent); const char *pattern = " /* %s */\n" " class_specs[%d].parent = &%s;\n"; char *init_code = CFCUtil_sprintf(pattern, class_name, self->num_specs, parent_var); self->init_code = CFCUtil_cat(self->init_code, init_code, NULL); FREEMEM(init_code); } } int num_new_novel = 0; int num_new_overridden = 0; int num_new_inherited = 0; CFCMethod **methods = CFCClass_methods(klass); for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) { CFCMethod *method = methods[meth_num]; if (CFCMethod_is_fresh(method, klass)) { if (CFCMethod_novel(method)) { int meth_index = self->num_novel + num_new_novel; S_add_novel_meth(self, method, klass, meth_index); ++num_new_novel; } else { int meth_index = self->num_overridden + num_new_overridden; S_add_overridden_meth(self, method, klass, meth_index); ++num_new_overridden; } } else { int meth_index = self->num_inherited + num_new_inherited; S_add_inherited_meth(self, method, klass, meth_index); ++num_new_inherited; } } char pattern[] = " {\n" " &%s, /* class */\n" " %s, /* parent */\n" " \"%s\", /* name */\n" " %s, /* ivars_size */\n" " &%s, /* ivars_offset_ptr */\n" " %d, /* num_novel */\n" " %d, /* num_overridden */\n" " %d, /* num_inherited */\n" " %s /* flags */\n" " }"; char *class_spec = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name, ivars_size, ivars_offset_name, num_new_novel, num_new_overridden, num_new_inherited, flags); const char *sep = self->num_specs == 0 ? "" : ",\n"; self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL); self->num_novel += num_new_novel; self->num_overridden += num_new_overridden; self->num_inherited += num_new_inherited; self->num_specs += 1; FREEMEM(class_spec); FREEMEM(parent_ptr); FREEMEM(ivars_size); }