Hi,
this is a followup to "Retrospective Thoughts on BitC" by Jonathan S.
Shapiro. I mailed him, because
I had some questions regarding my own language project, that is designed for
large scale numerical
computations and is aimed to be a replacement of Fortran/C/C++, since many of
the problems Jonathan
mentioned sound familiar to me. Jonathan asked me to ask my questions on
bitc-dev to have the discussions
public.
While I'm most interested in the problems of modular compilation in combination
with universal types,
my first mail to Jonathan instantly rised questions. So I would be glad for
every hint, that saves me from
running into problems, that already occurred in my project.
Before I actually go into detailed questioning, I'll try to sketch what and how
I'm developing.
I begun to write my compiler prototypes in Haskell and emitting low level
human readable C.
So I had simultaneously handle 3 languages. Haskell,C and the one I developed.
This worked
for fist Ideas, but made my Head hurting, when trying to keep the language
simple and the compile
skaleable. Haskell is very good in hiding complexities with mighty
abstractions.
To test the runtime environment I decided to write my last prototype in C using
the runtime-environment
the generated code will used. Further C gives me a rough metric on bad design
decisions that are not
easy to implement. I avoid C++ though I really miss templates and overloading -
but C++ abi just
caused to much trouble, and C is easier to access from other languages,like
C,Fortran, Python.
The primary goals of my language are
- Simplicity and conceptual coherence and consistence
- Simplicity in terms of compiler implementation
- Speed, especially Array acces and tuple member access must be as fast as
possible.
- Meta-Programmable - i.e. Extending the language should be simple.
- A strong strict type system (with an explicit unsafe escape)
So roughly I aimed for something like scheme, but with static typing and
human/mathematician friendly syntax.
My project name is "metacore" just the case I mention that name, but I try to
keep my questions generic,
so that the answers can be of value for any language developer.
The impact of a (guided) garbage collector:
Question: How big is the speed impact of a guided garbage collector regarding
speed?
Rationale: Trying to avoid GC would, to my experience, immensely increase the
complexity
of the required type system. However GC has speed penalties, that I tried to
avoid:
To handle this problem, I introduced an allocation type, e.g. the
metacore-programmer
can force allocation to occur on the call stack, like C automatic variables.
i.e.
tmp var x:FooDataType ;
will force x of data-type FooDataType to be allocated on the stack. In
conjunction with call by ref procedures
this allows write C style code regarding local memory. This temp memories
allows closures and
dictionaries for (type) classes to be be allocated on the stack if possible, by
using some simple form of
allocation-type-inference.
A generic allocation
var x:Foo ;
will allocate memory onto the heap. Of course the type system prohibits
returning a pointer to temporary memory.
Question: What do you think, regarding to your experiences with BitC, of the
following Garbage collector interface design?
Basic Design:
The rootset is represented by using a stack of tuples
(pointer-to-memory-area,type-descriptor-for-memory-area) for each thread.
Each heap allocation will automatically push an according tuple to the
root-set-stack. Stack allocations must be "manually"
pushed onto the root-set-stack, if necessary.
The root-stack-pointer is then pushed and restored like the frame pointer in
C/C++. If possible this can be optimized away, either
if the Interface is used by a human who knows, that nothing happened to the
rootset, or by
the analog to the -fomit-frame-pointer optimization of gcc.
Further there is a resource set , i.e. a set of pointers, where I have not jet
definitely decided how to present this, that holds pointers
to all data that are on the heap.
The root-stacks and ressource-set can be used to reconstruct the root-set and
data-set. A mark or sweep pass can use
the data-set to check whether or not it should follow a pointer, to do this
only the type-tags in the rootset are required,
regarding all other allocations this gc is tagless. This allows to use the gc
with uninitialized data, since it will not follow pointers to places not in the
dataset. Thus
as a consequence the gc on itself does not support and initialization or
finalization. Adding finalization for
entities in the ressource set, should be cheap. Initialization is, for this
design, nothing I have to bother with in the gc.
To implement the rootstack efficiently mmap() and signalhanding can be used to
make it almost as fast as the
callstack - a rootstackregister would make it practically equivalent.
The interface basically is (somewhat simplified from my working prototype):
void save_rootstackptr(void** addr_of_saved_ptr);
void restore_rootstackptr(void* saved_ptr);
void* gc_malloc(type_desc_t* tydesc);
The biggest problem I have with this is making it adequately concurrent. Well,
as long as a thread
does not access the ressource-set or its root-set-stack it does not need to be
stopped for gc, since
the gc will ignore invalid pointers, that can be produce by the actions of the
active thread.
Thats not too bad for the start I think, but can probably be better.
This are the questions for in my fist mail. I'm thankful too anyone who answers.
Best Regards,
Eike Scholz
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev