🎯

Dart゜ヌスコヌドが実行されるたでの構造を理解する

に公開
2025/02/21
3ä»¶
CHANGELOG
  • 2025.02.21
    • Flutter Wiki が移行したこずによるリンク切れの修正

背景

たたたた React/React Native に぀いお少し調べる機䌚があり、その掟生で React Native ず Flutter の違いを調べおいくうちに「普段曞いおいる Flutter/Dart の゜ヌスコヌドが iOS/Android などネむティブプラットフォヌム䞊で実行されるたで䜕が行われおいるのか」が気になり、呚蟺情報を調査しおいたした。これたでも䜕ずなく党䜓像はむメヌゞしおいたものの曖昧で、改めお調べた内容を自分なりにたずめおみた備忘録に近い内容ずなっおおりたす。

動機は Flutter ですが、調べおいくうちに Dart や Dart VM を掘っおいった圢になっおいるため、あたり Flutter の話Engine 等は出おきたせん。ただ、Flutter ず Dart で倚少異なる郚分はあるず思い぀぀、実行に Dart VM を䜿っおいる以䞊根本は倉わらないず思いたすので倚少参考になるかもしれたせん。
※本蚘事はアプリケヌションの開発スキル向䞊に盎接寄䞎するような内容ではありたせん= 知らなくずも普通にアプリは䜜れる点をご容赊ください。

抂芁

本蚘事での芁点は䞋蚘です。Flutter → Dart → Dart VM の順にコンパむルを䞭心に実行たでの流れを芋おいきたす。

  • Dart VM には JIT&AOT のパむプラむンがある
  • Dart コヌドアプリケヌションコヌドおよび Flutter Framework も含むは、JIT/AOT いずれも Kernel AST ず呌ばれる䞭間衚珟を介しお機械語ネむティブコヌドに倉換されおいる
    • 䟋ARM, x86_64
  • Dart コヌドを実行するには゜ヌスコヌドからコンパむルする方法ずスナップショットから䜜成する方法の2皮類がある
  • Flutter のリリヌスモヌドAOT コンパむルにおいおも Dart VM はランタむムに絞った軜量な圢で利甚されおいる
    • デバッグモヌドのみ Dart VM が利甚されおいるわけではない

Flutter 芳点での実行

Flutter の 3 局レむダヌのおさらい

前提知識ずしお、Flutter Engine に぀いお軜くおさらいしたす。
Flutter には Flutter Framework ず Flutter Engine が存圚しおいるのは有名な話ですねFlutter に関するリポゞトリは こちら に䞀芧化されおいたす。Framework は普段私たちが Widgetは開発した Flutter アプリケヌションを実行するための環境です。

この Flutter Engine は䞀蚀でいうず「Flutter アプリケヌションを実行するためのポヌタブルなランタむム」です。アニメヌションやグラフィック、Dart ランタむムなさたざたな Flutter コアラむブラリが実装されおいたす。有名どころだず、2D グラフィックラむブラリの Skia近い将来、新しいレンダリングレむダの Impeller に眮き換わるはずや iOS や Android などのプラットフォヌムデバむスの䞭で Engine をホストできる Dart VM埌述などがありたす。本蚘事では Dart VM を䞭心にその構造を蚘茉しおいたす。
䞀応、公匏ドキュメント蚘茉の芋慣れた図を再掲しおおきたす。

ネむティブアプリずしお実行されるたで

iOS/Android でどのようにコヌドが実行されるのか、に぀いおは公匏ドキュメントの FAQ にある How does Flutter run my code on XXX ? で蚘茉されおいたす。䟋ずしお iOS のリンクを貌っおおきたす。誰かに質問されたずきは、この内容を䌝えられればたず問題ないでしょう。
https://docs.flutter.dev/resources/faq#run-ios

内容を以䞋に蚘茉したすが、党䜓的にラむトな曞きぶりずなっおいたすFAQ なので。

リリヌスモヌド

1パラグラフ目はリリヌスモヌドの話ずなっおいたす。
たず、Dart コヌドアプリケヌションコヌドず SDK 䞡方は機械語ARMに AOT コンパむルされたす。コンパむルされたバむナリは iOS プロゞェクトの「Runner」に含たれ、.ipa ファむルずしおビルドされたす。ちなみにアプリケヌションコヌドは Frameworks/App.framework ずしおコンパむルされおいたす。そしおアプリが起動するず同時に、Flutter ラむブラリを読み蟌みたす。レンダリングやナヌザヌによるむンプット操䜜やむベントハンドリングなどはすべお、コンパむルされた Flutter アプリに含たれおいたす。Unity などのゲヌム゚ンゞンず同じような挙動になりたす。
䞊蚘をたずめるず以䞋の図のようなむメヌゞだず思いたす。

デバッグモヌド

FAQ の2パラグラフ目はデバッグモヌドの話ずなっおいたす。
Dart VM 䞊で実行されおおり、お銎染みの Hot Reload再コンパむル無しで倉曎を反映する特城も玹介されおいたす。残りはデバッグモヌドではパフォヌマンスが劣るこずを意識しおください、皋床の曞きぶりずなっおいたす。

䞊蚘が䞀応 Flutter 目線で蚘茉されおいるネむティブアプリ実行たでのプロセスずなりたす。党䜓像が把握できたずころで本蚘事での埌半では、AOT コンパむルや Dart VM に぀いお蚀及しながらコンパむルの仕組みを詳现に芋おいこうず思いたす。

䜙談React Native のコンパむル方法ずの違い

話はやや脱線したすが、良く比范される同じクロスプラットフォヌムである React Native ずはいく぀か差異があり、AOT コンパむルの可吊もその1぀です。React Native では Flutter ずは異なり、ネむティブの UI コンポネントを利甚するアプロヌチであるため、ナヌザヌ操䜜やむベントハンドリングはBridge を䜿っおネむティブず JavaScript を行き来する必芁がありたした。その点が、ナヌザヌむンタフェヌスもすべお機械語に事前コンパむルされおいる Flutter ずの倧きな違いで、実行速床の点でもさたざたな議論がありたしたね。
https://medium.com/inloopx/native-apps-with-flutter-and-react-native-8d300805b3c6

最近では、JSIJavaScript Interfaceによる Bridge の解消や、軜量か぀高速な JavaScript ゚ンゞンである Hermes の登堎によりこの蟺りの課題を解消し぀぀あるようです。
https://reactnative.dev/docs/hermes

Dart 芳点での実行

今床は Dart の公匏ドキュメントからコンパむルの詳现を芋おいきたす。Flutter 芳点での情報よりも詳现に蚘茉されおいたす。
ドキュメントに蚘茉もありたすが、そもそも Dart ずいう蚀語のゎヌルは「アプリ甚の柔軟なランタむムを掻甚し、マルチプラットフォヌム開発の生産的なプログラミング蚀語を提䟛するこず」ずなっおいたす。「どのプラットフォヌム䞊でもアプリケヌションを実行できる」点を匷みずした䜍眮づけになっおいたすね。

Dart is a client-optimized language for developing fast apps on any platform. Its goal is to offer the most productive programming language for multi-platform development, paired with a flexible execution runtime platform for app frameworks.

その特城は以䞋の図からもわかる通り、プラットフォヌムに合わせお実行可胜な機械語に柔軟に倉換されたす。

  1. すべおのプラットフォヌムで実行できる
    • プラットフォヌムに合わせお機械語 or JavaScript に倉換する
  2. 開発甚ずプロダクション甚のツヌルチェむンが分かれおいる
    • Hot Reload やデバッグツヌルの提䟛により生産性 UP

https://dart.dev/overview#platform

JIT ず AOT

Dart Native はモバむル、デスクトップ、サヌバなどを指し、Dart Web はブラりザを指したす。前者が機械語に倉換するのに察し、埌者は JavaScript ぞのトランスパむルずなるため異なるアプロヌチでコンパむルされたす。たずめるず以䞋のマトリックスずなりたす。

コンパむラ衚 開発モヌド プロダクションモヌド
Dart Native JITjust-in-time AOTahead-of-time
Dart Web dartdevc dart2js

ご存知の通り、Flutter でのビルドには Debug / Release / Profile の3぀のモヌドがありたすが、それらに察応する圢で Dart のモヌドも切り替わっお実行されおおり、Debug/Profile ビルドでは JIT コンパむルが、Relase ビルドでは AOT コンパむルがそれぞれ行われおいたす。

JIT ず AOT の特城を簡単にテヌブルにしたした。

項目 JIT AOT
実行速床 りォヌムアップが必芁のため起動が遅いが、時間経過ずずもに最倧パフォヌマンスに達する 起動埌すぐにピヌクパフォヌマンスぞ達する最倧パフォヌマンスは JIT の方が高い堎合もある
コンパむルのタむミング 実行時 実行前
コンパむル時間 短い 長い
目的 Hot Reload などの玠早く安定な開発フロヌを提䟛 利甚者ナヌザヌ䜓隓を重芖

Dart はこの䞡方のコンパむル圢匏をサポヌトしおいるずいうわけですね。詳现はこちらの蚘事が分かりやすいです。
https://qiita.com/kurun_pan/items/15a64ed67f3e68613cf2

dart compile

Dart のコンパむルも圓然手元で実行でき、その手順は公匏ドキュメントに蚘茉されおいたす。かなりシンプルですが、適圓に手元で動かしおみるずむメヌゞがしやすいず思いたす。
https://dart.dev/tools/dart-compile

単玔ですが、以䞋のプリントするだけの Dart ファむルでコンパむルしおみたした。

hello.dart
void main() {
  print('Hello World!');
}

実行結果です。出力された成果物や特城に぀いおはコメントで蚘茉しおいたす。

❯ dart compile exe hello.dart
Info: Compiling with sound null safety
# output: 4.9MB
# スタンドアロヌンな実行ファむル
# ランタむムも含たれるので最もサむズが倧きい
-> hello.exe

❯ dart compile aot-snapshot hello.dart
Info: Compiling with sound null safety
# output: 954KB
# ランタむムは含たれず機械語のみのためもっずも軜量
-> hello.aot

❯ dart compile jit-snapshot hello.dart
Compiling hello.dart to jit-snapshot file hello.jit.
Info: Compiling with sound null safety
Hello World! # JITコンパむラで同時に実行もされる
# output: 4.8MB
# 党゜ヌスコヌドの䞭間衚珟 + JITコンパむルの最適化
-> hello.jit

今回実行したコマンドに぀いお公匏ドキュメントのテヌブルに分かりやすく蚘茉されおいたす。䞻に゜ヌスコヌドからそのたた実行するのが exe コマンドで、スナップショットから生成しお実行するのが aot-snapshot, jit-snapshot であり、Dart コヌドを実行するアプロヌチは倧きく2皮類存圚するこずがわかりたす。それぞれどういった違いがあるのか、スナップショットがい぀䜿われるのか等に぀いおは、埌述の Introduction to Dart VM セクションにお蚘茉したす。

生成物の特城は公匏ドキュメントのテヌブルにも蚘茉されおいたす䞀郚抜粋。

Note: You don’t need to compile Dart programs before running them. Instead, you can use the dart run command, which uses the Dart VM’s JIT (just-in-time) compiler—a feature that’s especially useful during development. For more information on AOT and JIT compilation, see the platforms discussion.

たた、普段私たちはコンパむルをあたり意識するこずはなく dart run コマンドを䜿甚しおいる思いたすが、これはコマンド実行時に内郚的には Dart VM の JIT コンパむラを䜿っおいるず明蚘されおいたすね。

ドキュメントにも床々でおいたすが、これら JIT & AOT コンパむラは Dart VM にお実行されおいたす。次のセクションではこの Dart VM に぀いお芋おいきたす。

Introduction to Dart VM

Vyacheslav Egorov@mralephさんずいう Google の䞭の人を䞭心に Dart VM チヌムが曞いおいる Dart VM の詳现が蚘茉されおいるドキュメントです。珟圚 WIP ずいう䜍眮づけであるもののかなり詳しく蚘茉されおいたす。本蚘事では芁所のみを抜粋しお蚘茉しおおりたすので、詳现や党容は蚘事を芋おいただければず思いたす。

https://mrale.ph/dartvm/

VM ずいう混乱を招く名称

The name "Dart VM" is historical.

この蚘茉の通り、その名称は歎史的なもので「VM」ずいう名称ではありたすが、実行環境だけではなく AOT パむプラむンが存圚するなど、その意味は広矩であるこずを知っおおくずその埌の理解が進みたす。

私も最初勘違いしおいた点で、「Dart VM」ず蚘茉されるず䞀般に JVM のような実行環境ずしおのみの圹割をむメヌゞしおしたいたすが、Dart VM の堎合は少し異なりたす。Dart VM はバヌチャルマシンでもあるのですがそれは単に1぀の芁玠であり、垞に JIT コンパむルがされるわけでは有りたせん。
リリヌスモヌド実行時には AOT コンパむルが行われたすが、これも Dart VM の AOT パむプラむン の䞭で行われたす。コンパむルされた機械語は、precompiled runtime ず呌ばれる軜量なJIT パむプラむンのサブセットDart VM 䞊のランタむム䞊で実行されたす。぀たり、VM に留たらない倚様な機胜を Dart VM は提䟛しおいるこずになりたす。

Dart VM の特城

  • Dart ランタむムの提䟛
    • ガベヌゞコレクションやメモリ管理、Isolate 管理などを行う
  • Dart コアラむブラリのネむティブメ゜ッドを提䟛
  • 優れた開発者䜓隓の提䟛
    • デバッグツヌル
    • ホットリロヌドデバッグ/プロファむル時のみ
  • JIT & AOT コンパむラの䞡方のパむプラむンを提䟛

ちなみに、Dart VM のディレクトリはこちらです。
https://github.com/dart-lang/sdk/tree/f83c6d5e999eed7318ab4e39c6e58b6062ba7ddd/runtime/vm

Dart VM がコヌドを実行する仕組み

前セクションの「dart compile」でも蚘茉したしたが、Dart コヌドの実行には䞋蚘の2パタヌンがありたす。これらの倧きな違いは ゜ヌスコヌドをい぀どのように実行可胜なコヌドに倉換するか であり、ランタむム環境は同じです。

  1. ゜ヌスコヌドから JIT で実行する方法
  2. スナップショットAOT/JIT スナップショットから実行する方法

前述した dart compile のコマンドず察応させるず䞋蚘ずなりたす。

1.゜ヌスコヌドから実行
  - JIT: $ dart run
2.スナップショットから実行
  - JIT: $ dart compile jit-snapshot
  - AOT: $ dart compile aot-snapshot & dartaotruntime

1. ゜ヌスコヌドから JIT で実行するステップ

以䞋のようなコマンドラむンから Dart コヌドを実行する際に、䜕が起こっおいるのかに぀いお蚘茉したす。

hello.dart
$ dart hello.dart
-> Hello World!

Dart VM は Dart コヌドをそのたた実行しおいるわけではない

圓初、JIT コンパむラでは Dart の゜ヌスコヌドをそのたた実行しおいるのかず思っおいたのですが、Dart VM でそれはできたせん。代わりに、Kernel ASTs .dillず呌ばれる䞭間衚珟抜象構文朚のバむナリに䞀床倉換し、それを VM 䞊で実行したす。平たく蚀うず Kernel AST は、「Dart VM 䞊で実行するためのバむナリ」ずいうこずになりたす。
※AST: Abstruct Syntax Tree

図䞭にもありたすが、Dart ゜ヌスコヌドの Kernel AST ぞの倉換は common front-end (CFE) ず呌ばれる Dart で曞かれた䜎レベル API で行われおいたす。Common ずいう名称は、Dart Native(VM)ず Dart Web(dart2js, dartdevc)で共通利甚されおいるためだず思われたす。

ちなみに、䞋蚘のように手元で Dart コヌドを Kernel AST に倉換できたす。

❯ dart compile kernel hello.dart
Compiling hello.dart to kernel file hello.dill.
Info: Compiling with sound null safety
# output
-> hello.dill

実行結果はこのようになりたす。.dill ファむルは抜象構文朚のバむナリなので芋おも䞭身は良くわかりたせんが、これが Kernel AST そのものです。

Flutter での Kernel AST の凊理

具䜓的なむメヌゞができるように、Flutter のケヌスで Kernel AST の動きを芋おみたす。Flutter では Dart 実行ず異なり、䞋蚘の通りカヌネルぞのコンパむルず実行はそれぞれ別の堎所で行われたす。HOST ず曞かれおいる郚分が、ビルドする私たちのマシンや CI/CD 環境を指し、DEVIVE は iOS/Android などの実行するプラットフォヌムを指しおいたす。この間の Kernel AST の移動は flutter_tool によっお行われおいたす。

flutter_tool は Dart コヌドをパヌスできたせんが、Kernel AST ぞの倉換を frontend_server(CFE) のプロセスを氞続化でき、これによっお Flutter のカヌネル倉換ができるようになっおいたす。
frontend_server のプロセスは氞続しおいるためステヌトフルであり、前回のコンパむル結果を持っおいたす。これによっお開発者が出した Hot Reload のリク゚ストを怜知しお、前回のコンパむル結果を再利甚し差分のみの再コンパむルが行われおいたす。
たずめるず、私たちが倉曎した Dart コヌドは frontend_server(CFE)によっお動的に怜知され差分バむナリを生成埌、VM 䞊に倉曎分が行き枡るこずで、倉曎結果が即時に反映される䜓隓ができおいるわけですね。

2. スナップショットから実行するステップ

たた、VM にはバむナリのスナップショットを䜜成する機胜がありたす。スナップショットを䜜成するこずで、別の Isolate で VM を起動する際、スナップショットを元に高速か぀同じ状態で起動できるようになりたす。

このスナップショットの機胜を䜿うこずで、本来りォヌムアップが必芁な JIT コンパむラでも起動時間を短瞮できたすAppJIT snapshots。

少しスタミナが切れおしたったのず、この蟺りは解釈に自信がないので気になる方は元蚘事をご参照ください 🙏改めお远蚘するかもしれたせん

結局 Dart VM はどこで䜿われおいるのか

AOT モヌドでも実行時に Dart VM が利甚されおいるのか、が個人的に躓いたポむントでした。JIT モヌドではコンパむルず実行が同じタむミングで分かりやすいですが、AOT モヌドにおいおも事前コンパむルした機械語を実行するために、 Dart VM はランタむムに絞った軜量な圢で利甚されおいるそうです。

この点に぀いおは、前述の Introduction to Dart VM で玹介した著者の Vyacheslav Egorov さんによる䞋蚘 StackOverflow コメントが非垞にわかりやすかったです。
https://stackoverflow.com/questions/46961097/is-the-dart-vm-still-used/46988481#46988481

In the JIT mode Dart VM is capable of dynamically loading Dart source, parsing it and compiling it to native machine code on the fly to execute it. This mode is used when you develop your app and provides features such as debugging, hot reload, etc.

JIT モヌドではフル装備の Dart VM が利甚されおおり、プログラム実行䞭に動的に Dart コヌドのパヌスやコンパむルJIT コンパむルができる圢になっおいたす。これによりホットリロヌドの恩恵を受けるなど、スムヌズな開発環境が提䟛されおいたす。

JIT に関しおは分かりやすいですね。以䞋が AOT に関する蚘述です。

In the AOT mode Dart VM does not support dynamic loading/parsing/compilation of Dart source code. It only supports loading and executing precompiled machine code. However even precompiled machine code still needs VM to execute, because VM provides runtime system which contains garbage collector, various native methods needed for dart:* libraries to function, runtime type information, dynamic method lookup, etc. This mode is used in your deployed app.

事前コンパむルされた機械語が動くための環境ずしおAOTモヌドでもVMのランタむムは必芁です。理由は、ガベヌゞコレクタや Dart ラむブラリのネむティブメ゜ッドの提䟛などで、これらはデプロむされたアプリケヌション䞊にも存圚したす。

Where does precompiled machine code for the AOT mode comes from? This code is generated by (a special mode of the) VM from your Flutter application when you build your app in the release mode.

機械語の事前コンパむルも Dart VMスペシャルモヌドず衚珟しおいる箇所の䞭で行われおいたす。VM はランタむムだけではなく、プログラム実行前でも単玔なコンパむラずしお機胜しおいるずいうこずですね。

このようにリリヌスモヌドでは、デバッグモヌドの JIT で䜿うフル装備 Dart VM の䞭から実行に必芁な最䜎限のランタむム郚分のみを䜿甚し、機械語を実行しおいたす。JIT の VM には Hot Reload などの開発に必芁な郚品が含たれおいたすが、AOT の VM にはそれら開発に必芁な郚分を削ったサブセットのような VM ずなりたす。

図にするず䞋蚘のようなむメヌゞでしょうか
JIT モヌドから AOT モヌドぞ向かう矢印は実際にそのプロセスがあるずいうわけではなく、AOT モヌドの VM は JIT モヌドのサブセットであるこずを意図しおいたす。JIT モヌドでは存圚しおいた、開発に必芁な郚品が AOT モヌドだず欠萜良くドキュメントでは stripped ず衚珟されおいたすしおいるのが芁点です。

たずめ

Dart ゜ヌスコヌドが実行されるたでステップをたずめたす。

  1. Dart ゜ヌスコヌドは CFE ず呌ばれる front_end ツヌルによっお Kernel AST ず呌ばれる䞭間衚珟抜象構文朚に倉換される
  2. Kernel AST.dillは抜象構文朚のバむナリ衚珟
  3. AOT モヌドでは TFA により Kernel AST が最適化される
  4. Dart VM にお Kernel AST を解釈する
    • JIT の堎合:
      • Hot Reload や Debug を行うための開発郚品をすべお含んだフルの VM がデバむスに枡る
      • JIT compiler/interpreter により実行時にプログラムが逐䞀凊理される
    • AOT の堎合:
      • VM の䞭の AOT パむプラむンで機械語に pre-compile される
      • 機械語を実行するための軜量なランタむムのみを含んだ VM 䞊でプログラムが実行される
  5. スナップショットにより起動時間の短瞮

実際アプリケヌション開発で意識するこずは少ないですが、Flutter、Dart、Dart VM の関係性が芋え、実行プロセスの解像床が少し䞊がったず思いたす。個人的に䜎レむダヌの話はあたり明るくなく、解釈誀っおいる箇所などありたしたらフィヌドバックいただけたすず幞いです 🙏

参考

Discussion

cartcart

dart2nativeで䜜られた実行ファむルはVMずは無関係に動䜜しおるんでしょうか

1
ツルオカツルオカ

コメントありがずうございたす。実行環境を内包したコンパむルでは、VMがランタむムずなっおDartコヌドが実行されおいるのだず思いたす。

A standalone, architecture-specific executable file containing the source code compiled to machine code and a small Dart runtime.
https://dart.dev/tools/dart-compile#subcommands

1
cartcart

返信ありがずうございたす。サむズが倧きめになる理由はここがポむントぜいですね

2