• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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