Backend Development 26 min read

Understanding the Dart VM Main Function Startup and Message Mechanism

This article provides a detailed analysis of how the Dart VM initializes the main entry point, explains the role of RawReceivePort, SendPort, and the message‑passing mechanism that triggers the Dart main function, and traces the flow from C++ runtime to Dart code with code examples.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding the Dart VM Main Function Startup and Message Mechanism

The author investigates why Dart's garbage collector is unsuitable for long‑running server daemons and discovers that the Dart main function is not called directly by the runtime but is invoked through a message mechanism.

By examining the Dart VM source, the article shows that _delayEntrypointInvocation creates a RawReceivePort , registers a handler, and immediately sends a null message via sendPort.send . The handler then calls the entry point (the main function) when the message is processed.

Key Dart code snippets:

void _delayEntrypointInvocation(Function entryPoint, List
? args,
    Object? message, bool allowZeroOneOrTwoArgs) {
  final port = RawReceivePort();
  port.handler = (_) {
    port.close();
    if (allowZeroOneOrTwoArgs) {
      if (entryPoint is _BinaryFunction) {
        (entryPoint as Function)(args, message);
      } else if (entryPoint is _UnaryFunction) {
        (entryPoint as Function)(args);
      } else {
        entryPoint(); // triggers main
      }
    } else {
      entryPoint(message);
    }
  };
  port.sendPort.send(null);
}

The runtime side implements the native entry points for the port operations. For example, RawReceivePort_factory maps to the C++ function that creates a receive port in the isolate:

DEFINE_NATIVE_ENTRY(RawReceivePort_factory, 0, 2) {
  GET_NON_NULL_NATIVE_ARGUMENT(String, debug_name, arguments->NativeArgAt(1));
  return isolate->CreateReceivePort(debug_name);
}

The created ReceivePort registers a Dart_Port identifier in a global PortMap , which is later used by RawReceivePort_get_id to retrieve the port ID:

DEFINE_NATIVE_ENTRY(RawReceivePort_get_id, 0, 1) {
  const Instance& __port_instance__ = Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
  const ReceivePort& port = ReceivePort::Cast(__port_instance__);
  return Integer::New(port.Id());
}

When SendPort.send is called, it forwards the message to the C++ function SendPort_sendInternal_ , which posts the message to the isolate's MessageHandler :

DEFINE_NATIVE_ENTRY(SendPort_sendInternal_, 0, 2) {
  GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
  GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
  const Dart_Port destination_port_id = port.Id();
  const bool same_group = InSameGroup(isolate, port);
  PortMap::PostMessage(WriteMessage(same_group, obj, destination_port_id,
                                   Message::kNormalPriority));
  return Object::null();
}

The message is queued in MessageHandler::PostMessage , which may start a thread pool to process the queue. A MessageHandlerTask runs on a worker thread, eventually invoking MessageHandler::HandleMessage that calls the Dart-side _handleMessage function, completing the round‑trip and executing the original main entry point.

Finally, the article traces how the C++ main(int argc, char** argv) function of the Dart VM locates the Dart main closure, packages it as arguments, and invokes the Dart library function _startMainIsolate , which starts the whole message‑driven startup sequence described above.

Through this step‑by‑step analysis, the article clarifies the complete lifecycle from the native runtime entry point to the Dart main function, demonstrating that Dart's main is indeed triggered by a message rather than a direct call.

BackendDartRuntimeVMIsolatesMainFunctionMessagePassing
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.