opuntiaOS - an operating system targeting x86 and ARMv7
at master 8.1 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include <assert.h> 10#include <libobjc/class.h> 11#include <libobjc/memory.h> 12#include <libobjc/module.h> 13#include <libobjc/objc.h> 14#include <libobjc/runtime.h> 15#include <libobjc/selector.h> 16#include <string.h> 17 18struct class_node { 19 const char* name; 20 int length; 21 Class cls; 22}; 23 24// FIXME: Allocate it dynamically. 25static class_node class_tabel_storage[512]; 26static int class_table_next_free = 0; 27 28static Class unresolved_classes[128]; 29static int unresolved_classes_next = 0; 30 31void class_table_init() 32{ 33} 34 35Class class_table_find(const char* name) 36{ 37 int len = strlen(name); 38 for (int i = 0; i < class_table_next_free; i++) { 39 if (len == class_tabel_storage[i].length) { 40 if (strcmp(name, class_tabel_storage[i].name) == 0) { 41 return class_tabel_storage[i].cls; 42 } 43 } 44 } 45 return Nil; 46} 47 48static void class_table_add(const char* name, Class cls) 49{ 50 int place = class_table_next_free++; 51 class_tabel_storage[place].name = name; 52 class_tabel_storage[place].length = strlen(name); 53 class_tabel_storage[place].cls = cls; 54} 55 56bool class_add(Class cls) 57{ 58 Class fnd = class_table_find(cls->name); 59 if (fnd) { 60 return false; 61 } else { 62 static int next_class_num = 1; 63 cls->set_number(next_class_num); 64 cls->get_isa()->set_number(next_class_num); 65 class_table_add(cls->name, cls); 66 next_class_num++; 67 return true; 68 } 69} 70 71static inline void class_disp_table_preinit(Class cls) 72{ 73 cls->disp_table = DISPATCH_TABLE_NOT_INITIALIZED; 74} 75 76static Method class_lookup_method_in_list(struct objc_method_list* objc_method_list, SEL sel) 77{ 78 if (!objc_method_list) { 79 return (Method)NULL; 80 } 81 82 if (!selector_is_valid(sel)) { 83 sel = sel_registerTypedName((char*)sel->id, sel->types); 84 } 85 86 while (objc_method_list) { 87 for (int i = 0; i < objc_method_list->method_count; i++) { 88 SEL method_name = objc_method_list->method_list[i].method_name; 89 if (method_name && method_name->id == sel->id) { 90 return &objc_method_list->method_list[i]; 91 } 92 } 93 objc_method_list = objc_method_list->method_next; 94 } 95 96 return (Method)NULL; 97} 98 99static Method class_lookup_method_in_hierarchy(Class cls, SEL sel) 100{ 101 if (!selector_is_valid(sel)) { 102 sel = sel_registerTypedName((char*)sel->id, sel->types); 103 } 104 105 Method method; 106 for (Class cli = cls; cli; cli = cli->superclass) { 107 method = class_lookup_method_in_list(cli->methods, sel); 108 if (method) { 109 return method; 110 } 111 } 112 113 return (Method)NULL; 114} 115 116// Add instance methods only to root class. 117static void class_root_add_instance_methods(Class cls) 118{ 119 int max_methods_allocated = 8; 120 struct objc_method_list* new_list = (struct objc_method_list*)objc_malloc(sizeof(struct objc_method_list) + sizeof(struct objc_method[max_methods_allocated])); 121 struct objc_method_list* objc_method_list = cls->methods; 122 123 new_list->method_count = 0; 124 125 while (objc_method_list) { 126 for (int i = 0; i < objc_method_list->method_count; i++) { 127 SEL method_name = objc_method_list->method_list[i].method_name; 128 if (method_name) { 129 // The instance method isn't a class method yet, so add it. 130 if (!class_lookup_method_in_list(cls->get_isa()->methods, method_name)) { 131 new_list->method_list[new_list->method_count++] = objc_method_list->method_list[i]; 132 if (new_list->method_count == max_methods_allocated) { 133 max_methods_allocated += 8; 134 new_list = (struct objc_method_list*)objc_realloc(new_list, sizeof(struct objc_method_list) + sizeof(struct objc_method[max_methods_allocated])); 135 } 136 } 137 } 138 } 139 objc_method_list = objc_method_list->method_next; 140 } 141 142 if (new_list->method_count) { 143 new_list->method_next = cls->get_isa()->methods; 144 cls->get_isa()->methods = new_list; 145 } else { 146 objc_free(new_list); 147 } 148 149 // TODO: Update dispatch table. 150} 151 152static void class_send_initialize(Class cls) 153{ 154 assert(cls->is_class() && !cls->is_meta()); 155 if (!cls->is_initialized()) { 156 cls->add_info(CLS_INITIALIZED); 157 if (cls->superclass) { 158 class_send_initialize(cls->superclass); 159 } 160 161 SEL sel = sel_registerName("initialize"); 162 Method method = class_lookup_method_in_hierarchy(cls->get_isa(), sel); 163 164 if (method) { 165 OBJC_DEBUGPRINT("start [%s +initialize]\n", cls->name); 166 (*method->method_imp)((id)cls, sel); 167 OBJC_DEBUGPRINT("end [%s +initialize]\n", cls->name); 168 } else { 169 OBJC_DEBUGPRINT("class %s has no +initialize\n", cls->name); 170 } 171 } 172} 173 174bool class_can_resolve(Class cls) 175{ 176 if (cls->is_resolved()) { 177 return true; 178 } 179 180 if (!objc_getClass(ROOT_CLASS)) { 181 return false; 182 } 183 184 const char* superclass = (char*)cls->superclass; 185 return !superclass || (superclass && objc_getClass(superclass)); 186} 187 188bool class_resolve_links(Class cls) 189{ 190 assert(cls->is_class()); 191 192 if (cls->is_resolved()) { 193 return true; 194 } 195 196 Class object_class = objc_getClass(ROOT_CLASS); 197 if (!object_class) { 198 return false; 199 } 200 201 cls->get_isa()->set_isa(object_class); 202 203 if (!cls->superclass) { 204 cls->superclass = nil; 205 cls->get_isa()->superclass = nil; 206 cls->set_info(CLS_RESOLVED); 207 cls->get_isa()->set_info(CLS_RESOLVED); 208 return true; 209 } 210 211 Class supcls = objc_getClass((char*)cls->superclass); 212 if (supcls) { 213 // TODO: Fill subclass list 214 cls->superclass = supcls; 215 cls->get_isa()->superclass = supcls->get_isa(); 216 cls->set_info(CLS_RESOLVED); 217 cls->get_isa()->set_info(CLS_RESOLVED); 218 return true; 219 } 220 221 return false; 222} 223 224void class_resolve_all_unresolved() 225{ 226 for (int i = 0; i < unresolved_classes_next; i++) { 227 class_resolve_links(unresolved_classes[i]); 228 } 229} 230 231bool class_init(Class cls) 232{ 233 if (class_add(cls)) { 234 selector_add_from_class(cls); 235 selector_add_from_class(cls->get_isa()); 236 237 class_disp_table_preinit(cls); 238 class_disp_table_preinit(cls->get_isa()); 239 240 // TODO: Init methods and dispatch tables. 241 if (cls->is_root()) { 242 class_root_add_instance_methods(cls); 243 } 244 245 class_resolve_links(cls); 246 247 return true; 248 } 249 250 return false; 251} 252 253Class objc_getClass(const char* name) 254{ 255 Class cls = class_table_find(name); 256 return cls; 257} 258 259void class_add_from_module(struct objc_symtab* symtab) 260{ 261 for (int i = 0; i < symtab->cls_def_cnt; i++) { 262 Class cls = (Class)symtab->defs[i]; 263 264 // Fix clang flags 265 if (cls->is_class()) { 266 cls->set_info(CLS_CLASS); 267 } else { 268 cls->set_info(CLS_META); 269 } 270 271 OBJC_DEBUGPRINT("Installing classes %x (%d of %d): %s :: %d\n", (uintptr_t)cls, i + 1, symtab->cls_def_cnt, cls->name, cls->get_info()); 272 273 if (class_init(cls)) { 274 if (!class_can_resolve(cls)) { 275 unresolved_classes[unresolved_classes_next++] = cls; 276 } 277 } 278 } 279} 280 281OBJC_EXPORT Class objc_lookup_class(const char* name) 282{ 283 return objc_getClass(name); 284} 285 286IMP class_get_implementation(Class cls, SEL sel) 287{ 288 // TODO: Can't init it here, since meta classes are passed here. 289 // if (!cls->is_initialized()) { 290 // class_send_initialize(cls); 291 // } 292 293 sel = sel_registerTypedName((char*)sel->id, sel->types); 294 Method method = class_lookup_method_in_hierarchy(cls, sel); 295 296 if (!method) { 297 return nil_method; 298 } 299 300 // TODO: Message forwarding 301 302 return method->method_imp; 303}