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

Reply via email to