Skip to content

Monomorphization? #52722

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
modulovalue opened this issue Jun 16, 2023 · 8 comments
Open

Monomorphization? #52722

modulovalue opened this issue Jun 16, 2023 · 8 comments
Labels
area-dart-model For issues related to conformance to the language spec in the parser, compilers or the CLI analyzer. type-question A question about expected behavior or functionality

Comments

@modulovalue
Copy link
Contributor

Consider, for example, any type-polymorphic construct (e.g. a generic function, method or class).

Is there a way to guarantee that any such construct is monomorphized (i.e. duplicated during compilation and optimized with the assumption that it is not polymorphic) when the type arguments are statically known?

In other words, I am looking for a way to selectively turn the "dial" from "prefer a smaller binary" to "prefer faster execution" for generics. This example might be more illustrative:

class Foo<U, V, W> {
  // ...
}

W bar<U, V, W>(U u, V v, ...) {
  // ...
}

@pragma("vm:always_monomorphize")
typedef IntFoo = Foo<int, int, int>();

@pragma("vm:always_monomorphize")
typedef IntBar = bar<int, int, int>();

void main() {
  // "IntFoo" and "IntBar" are equivalent to a "Foo" and "bar", respectively, with respect to runtime performance, where all type parameters have been manually instantiated to be int, inlined, and removed.
  final foo = IntFoo(...);
  final bar = IntBar(...);
}

I have tried searching for monomorphisation/monomorphization in the language and sdk repos, but I couldn't find much.

A google search for "dart monomorphization" did not bring up anything useful. Dart generics are reified, but, to me, that section doesn't appear to say anything about runtime performance. Rust seems to monomorphize everything by default, Java appears not to monomorphize anything because types are erased at runtime.

How does Dart behave with respect to monomorphization?

@lrhn
Copy link
Member

lrhn commented Jun 16, 2023

Each back-end and compilation strategy will have to answer that independently, there is no general rule.
(I'm not aware that any of the backends are doing that optimization, but there's a lot I'm not aware of.)

@lrhn lrhn added the type-question A question about expected behavior or functionality label Jun 16, 2023
@ds84182
Copy link
Contributor

ds84182 commented Jun 17, 2023

You can use mixins to monomorphize code on the VM but it's an implementation detail and is not guaranteed. Mixin applications copy their members into a new class instead of sharing the implementation across all classes iirc.

@modulovalue
Copy link
Contributor Author

Thank you very much for the hint to look at mixins, I have not considered that mixins could help here.

So generic mixins with a single method and separate applications with known types might be able to "simulate" function monomorphization. I am going to try that.

@modulovalue
Copy link
Contributor Author

modulovalue commented Jun 19, 2023

Erik wrote a comment that is highly relevant to this issue here.

The answer to the last section of the issue description appears to be that there is no general purpose mechanism for monomorphization.

@modulovalue
Copy link
Contributor Author

Erik discussed the implications of monomorphization on code size here.

Futhermore, he has also provided an interesting answer to the first question in this issue:

We could create a monomorphic subclass of any given generic class, and that could be a way to perform experiments with a very simple kind of monomorphization:

mixin NoOp {}

class C<X> {...}

// We want a monomorphic copy of `C` at `int`, and we even want to know
// that no members have been overridden.
final class C_int = C<int> with NoOp;

@lrhn
Copy link
Member

lrhn commented Jun 20, 2023

Not sure how the with NoOp differs from

final class C_int extends C<int> {
  C(...): super(...);
}

The one thing you get for free with mixin applications is constructor forwarding. With extends you have to write the forwarders manually (but you then get to control them).

@modulovalue
Copy link
Contributor Author

The one thing you get for free with mixin applications is constructor forwarding. With extends you have to write the forwarders manually (but you then get to control them).

Exactly, I think that's pretty cool. This way, the amount of extra code needed to monomorphize something (assuming that this indeed does help with monomorphization) is constant instead of linear with respect to some implementation specific detail such as the arguments of some constructor.

@modulovalue
Copy link
Contributor Author

Scala supports monomorphization via a @specialized annotation.
Swift also seems to have a @_specialize annotation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dart-model For issues related to conformance to the language spec in the parser, compilers or the CLI analyzer. type-question A question about expected behavior or functionality
Projects
None yet
Development

No branches or pull requests

4 participants