datique@pcs.usp.br wrote:
When I first thought of having Self run on an Intel platform, I thought of Windows, which was the system I had then. Then, I noticed that it would be too much work at once to bring all the Unix facilities to Windows (I tried the excellent Cygwin32 and mingw32 ports of gcc, but that was not enough). Then I thought of having Self on SCO OpenServer, of which I had a noncommercial copy. As things were not easy, I cut all down to the smallest step I could think of. And that was Solaris x86. It looks like Gordon has solved the biggest problems of the port on Linux, but now I have spent the last six months studying the inner workings of the Self system and I think it's not time to stop. I always wanted to learn how such a great system works. And who knows what else can be achieved when more people try different solutions to the same problem...
Maybe we could get earlier to working system if we share our results.
How did you handle the stuff with the code generator? What did you do with the stack frame?
Do you think, recompile.c or convert.c have to be functional as long as SIC is disabled?
-gordon
Gordon, I (and maybe many more members of the list) was very excited about your quick progress. The fact is that many people have tried to port and many of these have given up (as Jecel told me once). I took great care to avoid giving up by designing a plan. I am in the first steps, which consist of studying the source code and the Self papers and understanding why things are the way they are. I have had great difficulties in understanding all the runtime stuff because I have never seriously programmed in assembly, neither for SPARC nor for Intel. One of the key pieces of knowledge one should have to do this port (and it seems that you have it) is know assembly and the inner workings of the stack and function calls. I haven't yet written or changed a single line of Self VM code, but I have printed all those files on paper to form a big book (still without any bindings) which is one of my favourites. All this explained, let me see your questions...
On Wed, 3 Feb 1999, Gordon Cichon wrote:
datique@pcs.usp.br wrote:
When I first thought of having Self run on an Intel platform, I thought of Windows, which was the system I had then. Then, I noticed that it would be too much work at once to bring all the Unix facilities to Windows (I tried the excellent Cygwin32 and mingw32 ports of gcc, but that was not enough). Then I thought of having Self on SCO OpenServer, of which I had a noncommercial copy. As things were not easy, I cut all down to the smallest step I could think of. And that was Solaris x86. It looks like Gordon has solved the biggest problems of the port on Linux, but now I have spent the last six months studying the inner workings of the Self system and I think it's not time to stop. I always wanted to learn how such a great system works. And who knows what else can be achieved when more people try different solutions to the same problem...
Maybe we could get earlier to working system if we share our results.
How did you handle the stuff with the code generator?
What stuff?
What did you do with the stack frame?
I don't understand the stack, frame, vframe, halfFrame, and all that yet. I think this is one of the hardest parts of the VM (yes, harder than the SIC).
Do you think, recompile.c or convert.c have to be functional as long as SIC is disabled?
Very simply stated, it seems that the SIC will only run if the lookup system (or someone else) decides that a method has run frequently enough to be considered a critical method. I don't remember exactly in which file this is. But if you don't want SIC running, why don't you make it think that no method has been called frequently enough so that it never thinks about recompiling? Feel free to ask me questions, I will answer them as far as I know the answers. In this respect, I think we could try to get some help from the Self Group members who read this list. Douglas
-gordon
--
Gordon Cichon email: Gordon@Cichon.de
------------------------------------------------------------------------ eGroup home: http://www.eGroups.com/list/self-interest Free Web-based e-mail groups by eGroups.com
Gordon, I have been recalling my notes (I didn't have them around when I last answered your mail) and came to the conclusion that maybe a recompilation can take place without the SIC. I think it is so because of customization. When you call a method, it is compiled and the nmethod is attached to a PIC for that method. If you call a method with the same name for a receiver of a different type (map) that cached code is not adequate for simply running. Then, a new nmethod must be compiled. What I don't know is whether this situation is what you call a recompilation. As far as I understand it right now, a recompilation is both 1) the polymorphic situation I described and 2) when a method has been called (with the same receiver) frequently enough so that it deserves to be optimized. Then SIC comes into scene. I guess Jecel (or someone else) can help. About conversions, I still don't understand conversions to tell you anything useful. I'd rather listen. I've been looking in the VM code and thought of the following idea: to turn off the SIC, I would make the VM think that even when some code is recompiled, it doesn't want to optimize. Though this may seem strange (I mean, recompiling the same method with the NIC), it is a way to put the SIC aside for now. Exactly, what I would do is modify the method SendDesc::isOptimized to always return false. I think that may work (at a first glance, at least). Another thing I was thinking about is deoptimization when one invokes the debugger on an optimized method. Maybe that should be turned off, too. One thing I didn't understand in your port is that there is a lot of SPARC assembly code bundled in the VM code. Did you change all that or it compiles on i386 unchanged?
Regards, Douglas
------------------------------------------------------------------------ eGroup home: http://www.eGroups.com/list/self-interest Free Web-based e-mail groups by eGroups.com
Douglas Atique wrote:
- the polymorphic situation I described and
- when a method has been called
Douglas,
The problem with this kind of lookup cache is not really one because at this point. If a method is called where the map does not fit, control is transferred to `lookup´ - there is not yet an executing stack frame that has to be converted into a new one.
I've been looking in the VM code and thought of the following idea: to turn off the SIC, I would make the VM think that even when some code is
Turning off SIC seems to be quite easy: Somewhere there is a table of active compilers that is initialized to use both SIC and NIC. Either this initialization can be changed, or there is a primitive method that can be used for configuring this array. I did not yet spend time for trying it because I did not have problems with it so far.
One thing I didn't understand in your port is that there is a lot of SPARC assembly code bundled in the VM code. Did you change all that or it compiles on i386 unchanged?
I changed it everywhere besides SIC. I plugged in gas (the GNU assembler) to emit the code, and I rewrote the places where code is actually generated. I already went through - fixing the build system - fixing the Unix library - rewriting most assembly primitives and runtime code - plugging in a new assembler - switching all what´s necessary to run NIC
SIC, as well as recompile/convert is currently disabled with `#ifdefs' and guarded by `abort()'. Blocks are not yet tested because cloning (executing) then does not work yet.
Yesterday, I got an evaluation license for Sniff. Let´s see if I can `domesticate' the stack frame with it. :-)
To imagine how difficult it is to evaluate `1´ with NIC, I attached the assembler code that it is generating.
-gordon
Gordon, 1) Just out of curiosity: Did you write a new assembler or did you adapt gas to be called by the NIC? 2) Cooperation: tell me what you know about the stack and what the problem with it is. Maybe this can help me understand it better and help you. Regards, Douglas
On Thu, 4 Feb 1999, Gordon Cichon wrote:
Douglas Atique wrote:
- the polymorphic situation I described and
- when a method has been called
Douglas,
The problem with this kind of lookup cache is not really one because at this point. If a method is called where the map does not fit, control is transferred to `lookup� - there is not yet an executing stack frame that has to be converted into a new one.
I've been looking in the VM code and thought of the following idea: to turn off the SIC, I would make the VM think that even when some code is
Turning off SIC seems to be quite easy: Somewhere there is a table of active compilers that is initialized to use both SIC and NIC. Either this initialization can be changed, or there is a primitive method that can be used for configuring this array. I did not yet spend time for trying it because I did not have problems with it so far.
One thing I didn't understand in your port is that there is a lot of SPARC assembly code bundled in the VM code. Did you change all that or it compiles on i386 unchanged?
I changed it everywhere besides SIC. I plugged in gas (the GNU assembler) to emit the code, and I rewrote the places where code is actually generated. I already went through
- fixing the build system
- fixing the Unix library
- rewriting most assembly primitives and runtime code
- plugging in a new assembler
- switching all what�s necessary to run NIC
SIC, as well as recompile/convert is currently disabled with `#ifdefs' and guarded by `abort()'. Blocks are not yet tested because cloning (executing) then does not work yet.
Yesterday, I got an evaluation license for Sniff. Let�s see if I can `domesticate' the stack frame with it. :-)
To imagine how difficult it is to evaluate `1� with NIC, I attached the assembler code that it is generating.
-gordon
--
Gordon Cichon email: Gordon@Cichon.de
--------- 8< ------ 8< ------ 8< ----------
movl 4(%esp), %ecx movl 3(%ecx), %ecx cmpl $0x20b1211, %ecx je L0 jmp 0x80c88f4 <Lookup> (p) L0: // verified entry point: // DI entry point: // test for recompilation movl 0x1fe00000 <??>, %ecx incl %ecx movl %ecx, 0x1fe00000 <??> cmpl $10240, %ecx jne L2 call 0x80f1fc0 <Recompile> (p) L2: pushl %ebp movl %esp, %ebp nop 6 movl %ebx, -12(%ebp) // flush incoming args to stack // End Prologue L3: // stack overflow/interrupt check cmpl %esp, 124(%esi) jl L4 .align 4, 3 call 0x80eb0f0 <InterruptCheck> (p) jmp L5 nop 3 .align 4 .data 0 movl -12(%ebp), %ebx movl %ebp, %esp popl %ebp popl %ecx jmpl *12(%ecx) L5: L4: L6: movl $0x4 (1), %ebx movl %ebx, %eax movl -12(%ebp), %ebx movl %ebp, %esp popl %ebp ret // patching stack frame creation code subl $16, %esp nop 3 // NLR code cmpl %esp, 156(%esi) je L7 movl -12(%ebp), %ebx movl %ebp, %esp popl %ebp popl %ecx jmpl *12(%ecx) L7: movl 152(%esi), %eax movl -12(%ebp), %ebx movl %ebp, %esp popl %ebp ret
------------------------------------------------------------------------ eGroup home: http://www.eGroups.com/list/self-interest Free Web-based e-mail groups by eGroups.com
Douglas Atique wrote:
- Just out of curiosity: Did you write a new assembler or did you adapt
gas to be called by the NIC?
I adapted gas :-)
- Cooperation: tell me what you know about the stack and what the problem
with it is. Maybe this can help me understand it better and help you.
Thank's for your interest :-) The main problem is still that I don´t know what´s the problem with it. In the mean time, I found out that the situation is actually different from Sparc. Sparc obviously stores its saved registers (incoming and local) one frame above than i386. On Sparc, FP points to extra incoming arguments, SP points to extra outgoing arguments, and the registers are going to be saved by the called function at to topmost end of the newly created frame. These three form a linked list: new stack frame -> SP -> FP. Since the size of the stack frame of the called function is not known in advance, the entire stack has to be searched. On i386, the situation is different in two aspects: 1) The registers are saved at the bottommost end of the newly created stack frame and can therefore be accessed using SP. So, there are only two pointers involved, namely SP and FP, that can be precomputedat call time. Since Self´s multithreading is not as preemtive as I considered it in the first place, growing and shrinking stack frames are not as interfering as I thought. 2) The second difference is about the interface between Self and C code. In i386´s calling convention, the called function does not have to save registers on the stack. The garbage collector would therefore not find them when traversing the stack. The integration of Self with C code on the stack can therefore not be as seemless as I originally wanted it.
I am considering intoducing a kind of `dummy' stack frame for interfacing with C that contains the saved registers at a predictable position, and that is maybe marked with a special return address. Outgoing arguments have also to be copied into this frame. (Should solve problem #2)
For problem #1, I have difficulties to predict what happens if I change the stuff in there. The implementation of classes `frame' and `halfFrame' is influenced by `process.c', `stack.c', and `frame.c'. And still, there a many other places around that access frames directly. I thought that maybe the frame chaining behavior could be changed with the constant `localsInBottomHalfFrame', unfortunately the system broke when I changed the value of it. I do not want to break the garbage collector under any circumstances because debugging it would be very tedious.
So, my question is: What has to be done to adapt the system to the new stack format?
-gordon
self-interest@lists.selflanguage.org