Skip to content

[VM] Remove synthetic mixin application classes and copying of mixin methods #46530

@alexmarkov

Description

@alexmarkov

Currently, for each mixin application front-end generates synthetic (anonymous) mixin application class.
Moreover, mixin_full_resolution transformation (pkg/kernel/lib/transformations/mixin_full_resolution.dart) copies members from mixin to each mixin application class.

For example:

class B {}

class M {
  void foo() => print('foo');
}

class A extends B with M {}

Kernel:

  class B extends core::Object {
    synthetic constructor •() → foo::B
      : super core::Object::•()
      ;
  }
  class M extends core::Object {
    synthetic constructor •() → foo::M
      : super core::Object::•()
      ;
    method foo() → void
      return core::print("foo");
  }
  abstract class _A&B&M extends foo::B implements foo::M /*isAnonymousMixin,isEliminatedMixin*/  {
    synthetic constructor •() → foo::_A&B&M
      : super foo::B::•()
      ;
    method foo() → void
      return core::print("foo");
  }
  class A extends foo::_A&B&M {
    synthetic constructor •() → foo::A
      : super foo::_A&B&M::•()
      ;
  }

This results in a large number of extra synthetic classes which increase AOT snapshot size, memory footprint of an application and compilation time.

There are a few mitigations for this problem in Dart VM/AOT:

  • mixin_deduplication transformation (pkg/vm/lib/transformations/mixin_deduplication.dart) which removes duplicate mixin application classes if same B with M mixin application is used multiple times. But it cannot eliminate duplication between B1 with M and B2 with M.
  • VM deduplicates methods with the same generated machine code, but that doesn't work if generated code is different, for example due to different object pool indices used for caches in distinct copies of mixin methods.

These optimizations help but there is still redundancy left even after all these deduplications.

Instead, we can redesign mixins in the VM, removing mixin application classes and copying of mixin methods entirely.

In such case, super calls will not be resolved at compile time. Instead, they will be dispatched at run time.
For example, we can treat super calls super.foo from class C similarly to interface calls, just with a special selector super:foo@C. Actual classes will have targets for these super: selectors in the dispatch table depending on their superclasses and mixins. Many of those super calls can be devirtualized and converted into direct calls (for example, if a class is not used as a mixin, or if mixin is always used with the same superclass).

Such implementation of mixins should result in a smaller AOT snapshot size, lower memory footprint and faster compilation, with the expense of slightly more expensive super calls. Hopefully the performance difference would be negligible.

/cc @mraleph @mkustermann @rmacnak-google @a-siva

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.vm-aot-code-sizeRelated to improvements in AOT code sizevm-aot-memory-footprintRelated to improvements of VM memory footprint for AOT deployments

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions