1# Runtime class 2 3Panda runtime uses `panda::Class` to store all necessary language independent information about class. Virtual table and region for static fields are embedded to the `panda::Class` object so it has variable size. To get fast access to them `Class Word` field of the object header points to the instance of this class. `ClassLinker::GetClass` also return an instance of the `panda::Class`. 4 5Pointer to the managed class object (instance of `panda.Class` or other in case of plugin-related code) can be obtained using `panda::Class::GetManagedObject` method: 6 7```cpp 8panda::Class *cls = obj->ClassAddr()->GetManagedObject(); 9``` 10 11We store common runtime information separately from managed object to give more flexebility for its layout. Disadvantage of this approach is that we need additional dereference to get `panda::Class` from mirror class and vice versa. But we can use composition to reduce number of additional dereferencies. For example: 12 13```cpp 14namespace panda::coretypes { 15class Class : public ObjectHeader { 16 17 ... // Mirror fields 18 19 panda::Class klass_; 20}; 21} // namespace panda::coretypes 22``` 23 24In this case layout of the `coretypes::Class` will be following: 25 26 27 mirror class (`coretypes::Class`) --------> +------------------+ <-+ 28 | `Mark Word` | | 29 | `Class Word` |-----+ 30 +------------------+ | | 31 | Mirror fields | | | 32 panda class (`panda::Class`) ---------> +------------------+ <-|-+ 33 | ... | | 34 | `Managed Object` |---+ 35 | ... | 36 +------------------+ 37 38Note: as `panda::Class` object has variable size it must be last in the mirror class. 39 40Such layout allows to get pointer to the `panda::Class` object from the `coretypes::Class` one and vice versa without dereferencies if we know language context and it's constant (some language specific code): 41 42```cpp 43auto *managed_class_obj = coretypes::Class::FromRuntimeClass(klass); 44... 45auto *runtime_class = managed_class_obj->GetRuntimeClass(); 46``` 47 48Where `coretypes::Class::FromRuntimeClass` and `coretypes::Class::GetRuntimeClass` are implemented in the following way: 49 50 51```cpp 52namespace panda::coretypes { 53class Class : public ObjectHeader { 54 ... 55 56 panda::Class *GetRuntimeClass() { 57 return &klass_; 58 } 59 60 static constexpr size_t GetRuntimeClassOffset() { 61 return MEMBER_OFFSET(Class, klass_); 62 } 63 64 static Class *FromRuntimeClass(panda::Class *klass) { 65 return reinterpret_cast<Class *>(reinterpret_cast<uintptr_t>(klass) - GetRuntimeClassOffset()); 66 } 67 68 ... 69}; 70} // namespace panda::coretypes 71``` 72 73In common places where language context can be different we can use `panda::Class::GetManagedObject`. For example: 74 75```cpp 76auto *managed_class_obj = klass->GetManagedObject(); 77ObjectLock lock(managed_class_obj); 78``` 79 80Instead of 81 82```cpp 83ObjectHeader *managed_class_obj; 84switch (klass->GetSourceLang()) { 85 case PANDA_ASSEMBLY: { 86 managed_class_obj = coretypes::Class::FromRuntimeClass(klass); 87 break; 88 } 89 case PLUGIN_SOURCE_LANG: { 90 managed_class_obj = plugin::JClass::FromRuntimeClass(klass); 91 break; 92 } 93 ... 94} 95ObjectLock lock(managed_class_obj); 96``` 97