1# Runtime class 2 3Panda runtime uses `panda::Class` to store all necessary language independent information about classes. 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, the `Class Word` field of the object header points to the instance of this class. `ClassLinker::GetClass` also returns an instance of the `panda::Class`. 4 5Pointer to the managed class object (instance of `panda.Class` or `java.lang.Class` in case of Java, for example) can be obtained using `panda::Class::GetManagedObject` method: 6 7```cpp 8panda::Class *cls = obj->ClassAddr()->GetManagedObject(); 9``` 10 11Storing common runtime information separately from managed objects allows more flexibility for the layout but causes additional dereferences to get panda::Class from mirror classes and vice versa. However, we can use composition to reduce the number of additional dereferences. 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 24The layout of the `coretypes::Class` is as follows: 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: The `panda::Class` object must be the last in the mirror class because it has variable size. 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 JAVA_8: { 90 managed_class_obj = java::JClass::FromRuntimeClass(klass); 91 break; 92 } 93 ... 94} 95ObjectLock lock(managed_class_obj); 96``` 97