arkcompiler_runtime_core/docs/runtime-class.md
huangyu c658ccf319 Update runtime_core code
Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/I5G96F
Test: Test262 suit, ark unittest, rk3568 XTS, ark previewer demo

Signed-off-by: huangyu <huangyu76@huawei.com>
Change-Id: I3f63d129a07deaa27a390f556dcaa5651c098185
2022-07-17 10:20:32 +08:00

3.5 KiB

Runtime class

Panda 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.

Pointer 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:

panda::Class *cls = obj->ClassAddr()->GetManagedObject();

We 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:

namespace panda::coretypes {
class Class : public ObjectHeader {

    ... // Mirror fields

    panda::Class klass_;
};
}  // namespace panda::coretypes

In this case layout of the coretypes::Class will be following:

mirror class (`coretypes::Class`) --------> +------------------+ <-+
                                            |    `Mark Word`   |   |
                                            |    `Class Word`  |-----+
                                            +------------------+   | |
                                            |   Mirror fields  |   | |
    panda class (`panda::Class`) ---------> +------------------+ <-|-+
                                            |      ...         |   |
                                            | `Managed Object` |---+
                                            |      ...         |
                                            +------------------+

Note: as panda::Class object has variable size it must be last in the mirror class.

Such 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):

auto *managed_class_obj = coretypes::Class::FromRuntimeClass(klass);
...
auto *runtime_class = managed_class_obj->GetRuntimeClass();

Where coretypes::Class::FromRuntimeClass and coretypes::Class::GetRuntimeClass are implemented in the following way:

namespace panda::coretypes {
class Class : public ObjectHeader {
    ...

    panda::Class *GetRuntimeClass() {
        return &klass_;
    }

    static constexpr size_t GetRuntimeClassOffset() {
        return MEMBER_OFFSET(Class, klass_);
    }

    static Class *FromRuntimeClass(panda::Class *klass) {
        return reinterpret_cast<Class *>(reinterpret_cast<uintptr_t>(klass) - GetRuntimeClassOffset());
    }

    ...
};
}  // namespace panda::coretypes

In common places where language context can be different we can use panda::Class::GetManagedObject. For example:

auto *managed_class_obj = klass->GetManagedObject();
ObjectLock lock(managed_class_obj);

Instead of

ObjectHeader *managed_class_obj;
switch (klass->GetSourceLang()) {
    case PANDA_ASSEMBLY: {
        managed_class_obj = coretypes::Class::FromRuntimeClass(klass);
        break;
    }
    case PLUGIN_SOURCE_LANG: {
        managed_class_obj = plugin::JClass::FromRuntimeClass(klass);
        break;
    }
    ...
}
ObjectLock lock(managed_class_obj);