main uses I can think of are mostly for debugging...
<--
Debugging of this nature is a special purpose thing
that is properly not part of the language. It's
properly part of a development platform. Such a
platform may well insert lots of extra information
that is then visible to the debugging platform
when you are using it, things like stepping through
the code and so on.
But generally, in production code, you would not want
this huge overhead of extra information. For example,
such information would have to retain function names.
And such things are usually not retained in a compiled
executable, since they are not used by the executable.
Socks
-->
function names not used by executable:
this, of course, excludes certain useful things which can be done by a
program, especially when working in a hybrid VM environment (where a program
may be only partially statically compiled, and other parts are generated at
runtime).
things like being able to look up functions by name, and figure out to which
function a pointer belongs, are useful things to know, and have many uses
beyond simple debugging (however, backtraces tend to be much more limited in
use, as I am not really sure of many non-debugging uses for a stack frame).
on Windows, this basically means making every function one may want to be
able to access via dynamically compiled code be a DLL export. technically,
it works well enough. (on Linux, shared libraries tend to export everything
by name by default, so no issue here).
one also needs metadata, but this metadata is typically of a somewhat
different nature than that of debugging info (and debug info also makes it
easier for people to dig around in program internals, ...). so, this means
generating metadata in a different form (typically function and type
signatures gained by processing program headers, ...).
having to use a fixed-form program image is, limiting...
it is like, all of the code has to be built into the program at compile
time.
what about new code or situations which may not be known until runtime?...
with fixed-form programs, there is no good solution (apart from maybe
interpreters and manually exporting every possible API function to the
interpreter), but this is a painful solution (and requiring of much
boilerplate).
but, yes, dynamic code generation also has its fair share of costs...
an interpreter is simpler than a compiler, but leads to poor performance and
typically a large amount of jerkoff trying to interface code between it and
the outside world, ... but a compiler is complex, difficult to debug, and
tends to take longer to evaluate new code fragments (since it has to compile
the thing first). so one ends up needing both...
however, even then, IME the vast majority of the heavy-lifting still tends
to be left to statically compiled code, and personally I don't advocate
"complete VM" architectures (such as JVM), as these tend to needlessly force
all of the code into some often ill-performing and typically
not-very-capable HLL.
or such...