This question comes once in a while and unfortunately I have never found a good high level document explaining the vm internals.
Dart is more than its VM. It is a programming language project led by google.
As pointed out, the original vm was originally designed to replace javascript on the browser, the language however is purpose free. Dartino implements a very different vm yet relying on the same language.
The dart vm which runs on the server and most recently has been adapted to run on mobile consists of a C++ runtime (memory manager, scheduler, profiler, snapshots, libraries...) and the compiler part (parser, compiler, optimizer, assembler). The core of the VM[1] can be easily embedded with only limited dependencies into their host OS. When running on the server (aka standalone[2]) dart exposes additional libraries to deal with IO. There is a considerable amount of dart written libraries as well[3]. Libraries written in dart use the same infrastructure as the code that the user writes.
the DartVM implements AOT, JIT and a Dart Byte Code (DBC) interpreter for a mix of architectures. The language was designed to rely on JIT techniques so performance for AOT may not compare. However keep in mind AOT part of the project is new and work has been done to speed it up[4]. In fact the whole introduction for AOT started when the project started pursuing the mobile platform rather than web.
The compiler infrastructure within the VM is robust and massive. IMO it is what makes reading the source code complicated. If you are not into compilers, it is very difficult to keep up with all the concepts (intrinsics, arity, canonicalization, class hierarchy, different call conventions). Nevertheless it is a very well designed project yet pragmatic given all it does.
The hello world program, gets parsed and compiled to the machine's architecture. Your console calls tie with the libraries for your operating system. In the end it is just the same kernel call you would see with your C code. There are lots of abstractions and layers for that to happen. The key for performance is to remove the abstraction as much as possible for heavily executed code. Once you have machine code the C++ runtime jumps into it and your compiled code takes over the CPU, for certain operations it goes back to the C++ runtime or even to something external to the vm.
There is a short video which helps to understand the single compiler[5]. Bear in mind that at that time there was a lot of comparisons with javascript, which IMO should not make sense at this point given their different goals.
HTH