con: you will have to implement some VM stuff as runtime library (GC, dynload, dyn compilation etc.); some things are hard to do in C (continuations, backtracking, stack tracing, exceptions); some things are hard to do efficiently and portable in C (GC, dynamic types, stack layout dependence).

VM-wise, I think there is a relatively wide range of performance you can get as JVM, starting at pure slow bytecode interpreters up to high end sophisticated JITting VMs (IBM). I guess, CLR VM's will catch up, as MS is stealing and integrating all innovation anyway sooner or later, and the techniques to speedup dynamic translation are published (read the Self papers, for example). LLVM will probably progress a bit slower, but who knows. With C, you will benefit from better compilers for free, but things like dynamic retranslation etc. are hard to implement with C as target. My own system uses a mixture of precompiled and dynamically compiled code (having all: a slow bytecode interpreter, JITter and precompiled static C-code in one memory space).

Java ByteCode is something I've always been iffy about. Call it bad past experience. Do any of them have any perks regarding power of their internal VM (other than just library calls?)
–
user54650Jan 15 '09 at 15:27

Pro: target is an actual written language, not an API; you can easily inspect, debug, and edit your C-- code

Pro: design is reasonably mature and reasonably clean

Pro: supports accurate garbage collection

Pro: most users report it is very easy to use

Con: very small development team

Con: as of early 2009, supports only three hardware platforms (x86, PPC, ARM)

Con: does not ship with a garbage collector

Con: project has no future

C as target language

Pro: looks easy

Con: nearly impossible to get decent performance

Con: will drive you nuts in the long run; ask the long line of people who have tried to compile Haskell, ML, Modula-3, Scheme and more using this technique. At some point every one of these people gave up and built their own native code generator.

Summary: anything except C is a reasonable choice. For the best combination of flexibility, quality, and expected longevity, I'd probably recommend LLVM.

LLVM seems promising. The team claims better runtime performances on gcc with their backend compared to native. The ability to compile from the AST is really interesting (take a look at the tutorial). It can compile and optimize at runtime, which is a must for dynamic. It can also run as a pure interpreter.

I consider using LLVM in a project that involves creating a Tcl-like language. Tcl is heavily dynamic, so I don't know what this implies at this stage, but I'm confident that I'll get better performances than the current bytecode-based core.