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