Disadvantages of building a compiler and library on top of a specific memory management scheme
Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang at gmail.com>
Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang at gmail.com>
Sat Feb 8 07:33:16 PST 2014
On Saturday, 8 February 2014 at 05:43:44 UTC, logicchains wrote:
> apart from superior compile-time metaprogramming? Personally, I
> think working to improve the garbage collector could pay off in
> this regard; "Both Rust and D allow you to choose between using
> a garbage collector and using referencing counting, but D's
> garbage collector is a precise concurrent generational moving
> compacting collector, whereas Rust's is a non-parallel
> non-moving conservative collector that's orders of magnitude
> slower and uses much more memory." Currently, even Go has a
> better GC than D.
Well, I think the main problem with D is that it is not a spec
driven language, but an implementation driven language and that
the implementation is based on compiler backends with very
restrictive C semantics. D tries to bolt higher level
functionality on top of that without opening up for efficient
implementation of such features.
For instance:
1. You could have GC free lambdas if you require that they only
call functions that can work with fixed-size stack frames (so you
allocate stack frames off a thread local heap where all
allocation units are of a fixed size (say 1k)) and that they
avoid recursion.
2. You could avoid lots of temporary allocations and copies if
you could control what stack frames look like, by modifying the
parent frame.
3. You could have zero overhead exception handling if you could
get rid of the silly backwards-compatible driven design of Dwarf:
- If you fully control code gen you can have dual return points
with a fixed offset, so you can modify the return address on the
stack by adding an offset before returning to indicate an error
or just jumping. The penalty is low since predicted branches tend
to be cheap.
- If you don't need stack frames (by not having GC) you can
maintain only frame pointers for function bodies that contains
try blocks. Then jump straight to them on throw:
Throw becomes:
reg0 = exception_object
JMP *(framepointer+CATCHADDR)
Catch becomes:
switch(reg0.someid){
...
default:
framepointer = *(framepointer+NEXTPTR)
JMP *(framepointer+CATCHADDR)
}
This would make for very efficient exception handling with no
more setup cost than you have today for stack frames. I believe.
It isn't reasonable to require that you write a backend from
scratch, but I think it is reasonable to have a language spec
that does not tie you to an implementation that will never go
beyond C. If that makes adapting existing backends slightly less
efficient, then that should be ok. It is more important to have a
language spec that allows future compilers to be highly efficient.
- If you want mandatory GC, ok, but then change the language spec
to make it possible to write a powerful compiler.
- If you 100% C++ parity/compatibility, great, but then make it
just as easy (or easier) to write C++ type code without GC.
Basically, you would have a language that consists primarily of
syntactic sugar + some optimizing opportunities.
- If you want better performance than C. Great! But don't limit
the language to C-semantics in the backend.
Make a decision for where you want to go at the language
specification level. Forget about the current compiler/runtime.
Where do you want to go?
More information about the Digitalmars-d
mailing list