Porting to Darwin

39 views
Skip to first unread message

Brian de Alwis

unread,
Jun 9, 2008, 1:06:50 PM6/9/08
to strongtal...@googlegroups.com
Hi everybody.

I've got the gcc-linux branch to build on Darwin (modulo thread per-time accounting), and the basic easyunit tests pass.  But running the actual VM crashes with what looks to be a NULL pointer dereference, which might be occurring because of a stack alignment issue.  Running with "+TraceLookupAtMiss" shows that the problem occurs when starting to run ProcessorScheduler::start.  See further below for the backtrace; the problem arises in __dyld_misaligned_stack_error, and frame #1 is very suspicious looking.  The call in DeltaProcess::last_frame is simply creating a 'frame' object:

840:    frame c(last_Delta_sp(), last_Delta_fp());

Although this could arise because of dynamic linking issues, I'm speculating that the NULL dereferencing is occurring because of Darwin's slightly different calling conventions.  In Darwin, EBX must be preserved within position-independent code and the stack must be 16-byte aligned:

The IA-32 environment uses a stack that—at the point of function calls—is 16-byte aligned, grows downward, and contains local variables and a function's parameters. Each routine may add linkage information to its stack frame, but it's not required to do so. Figure 1 shows the stack before and during a subroutine call.

<http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/IA32.html#//apple_ref/doc/uid/TP40002492-DontLinkElementID_9>

It's been ages since I've done an IA32 assembly, but I tried the obvious changes of pushing and popping ebx in MacroAssembler::enter and MacroAssembler::leave in vm/asm/assembler.cpp, and adjusting some of the calls in vm/code/stubRoutines.cpp to instead call masm->leave() rather than pop off ebp directly, but to no apparent avail.  I'm not quite sure how to ensure the stack is 16-byte aligned.

Or I just had another thought, that the DeltaProcess is tracing back through the stack and is unaware of ebx possibly having been pushed on the stack?

Does anybody have any pointers or advice?

Brian.

=================================
(gdb) run -b ../strongtalk.bst
Starting program: /Users/bsd/personal/Projects/Strongtalk/port-darwin/build/strongtalk -b ../strongtalk.bst
Reading symbols for shared libraries +++. done

Smalltalk Virtual Machine by LongView Technologies LLC
---------------------------------------------------------
(c) 1994-1997 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
Use and distribution of this software is subject to the
terms of the attached license.
---------------------------------------------------------
Version 1.1 (build Jun  8 2008 22:29:44)
(use argument -? for a list of flags)

- VM is in debug mode
[Reading in ../strongtalk.bst, n, 0.332 secs]
[Switching to process 66972 thread 0x317]

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x00000000
0x8fe18b42 in __dyld_misaligned_stack_error ()
(gdb) where
#0  0x8fe18b42 in __dyld_misaligned_stack_error ()
#1  0x00000001 in ?? ()
#2  0x00117cd2 in DeltaProcess::last_frame (this=0x400870) at process.cpp:840
#3  0x0009a101 in InterpretedIC::inline_cache_miss () at interpretedIC.cpp:589
#4  0x001cf1cc in interpreter_code ()
#5  0x0022285c in StubRoutines::_code ()
#6  0x0010d4a4 in Delta::call_generic (ic=0x221d20, receiver=0x100032d, selector=0x10a4029, nofArgs=0, args=0x0) at delta.cpp:114
#7  0x0010d52b in Delta::call (receiver=0x100032d, selector=0x10a4029) at delta.cpp:119
#8  0x00116601 in DeltaProcess::launch_delta (process=0x400870) at process.cpp:413
#9  0x00113e2f in mainWrapper (args=0x400900) at os_darwin.cpp:211
#10 0x903d86f5 in _pthread_start ()
#11 0x903d85b2 in thread_start ()
=================================

talksmall

unread,
Jun 9, 2008, 5:19:22 PM6/9/08
to Strongtalk-general
Hi Brian,
If you are pushing ebx in MacroAssembler::enter() this will very
likely cause problems. When the VM starts executing Smalltalk code
(either native nmethod code or interpreted code) is starts by calling
the StubRoutines call delta function generated in
StubRoutines::generate_call_delta(). This starts by calling masm-
>enter() and then pushes the frame pointers from the last delta (ie.
Smalltalk) frame that it was executing in the current process. If you
have changed masm->enter() to push ebx then these pointers will not be
in the expected locations. Additionally, you will be pushing ebx for
every delta method invocation which is almost certainly unnecessary.

A better approach would be to preserve ebx after the other registers
in the generated call_delta and restore it in the companion
_return_from_delta the code for which is generated by the same
generate_call_delta method. I have patched the generation code to do
this. I was going to attach it to this message, but it seems Google
doesn't want to let me, so I am including the contents of the patch
(it's quite small) at the end of this message. I applied this locally
within my Windows environment and everything continues to work. Let me
know if you have any luck with this.

BTW the reason that the easyunit tests pass is that none of them
execute any Smalltalk code. At the moment, they test very specific
behaviours within the VM itself. Over time I would expect us to expand
the coverage, possibly including the execution of Smalltalk code, but
we are not there yet.

From the stack trace I see that you have created a new os_ module for
darwin. You should make sure that the os::platform_class_name() still
returns "UnixPlatform". This is used in the startup code to specify
the platform class to bind to the global "Platform" in the system
dictionary. This acts as a hook for all platform-specific code in the
image (well it will do in the future, for now it just hooks in the
file access code). You will need to be using libc 6 or have a link
libc.so.6 that points to your libc.so, which cannot be a linker script
(as it sometimes is in linux).

Regards, Steve

Patch contents below. Beware of line wrapping.

Index: stubRoutines.cpp
===================================================================
--- stubRoutines.cpp (revision 139)
+++ stubRoutines.cpp (working copy)
@@ -823,6 +823,7 @@

masm->pushl(edi); // save registers for C calling convetion
masm->pushl(esi);
+ masm->pushl(ebx);

// reset last Delta frame
masm->reset_last_Delta_frame();
@@ -862,7 +863,8 @@
masm->movl(Address((int)&have_nlr_through_C,
relocInfo::external_word_type), 0);

masm->bind(_return);
- masm->leal(esp, Address(ebp, -4*oopSize));
+ masm->leal(esp, Address(ebp, -5*oopSize));
+ masm->popl(ebx);
masm->popl(esi); // restore registers for C calling convetion
masm->popl(edi);
masm->popl(Address((int)&last_Delta_sp,
relocInfo::external_word_type)); // reset _last_Delta_sp


Hyungjip Kim

unread,
Jun 12, 2008, 3:53:36 AM6/12/08
to Strongtalk-general
Hi Brian,

I worked on porting VM to Mac last summer, but stopped working on it
as I became rather busy.
It's not an easy job. I don't think the EBX is the problem, as it's
required only by position independent programs. But 16 byte alignment
is a big challenge.

MASM enter/leave would not help, methinks. As the assembly code uses
many tricks to switch between native code and VM emulation such as
jumps between asm functions and C++ functions and return with modified
stack, rather than regular call/return.

I think the best way is to port to 64 bit, as Mac OS X (darwin) uses
the same calling convention on 64 bit processors. But as my Mac was 32
bit at the time, I paused working on VM then got busy. Now I bought
myself a new 64 bit Intel Mac and I want to resume working on porting
to Mac / 64 bit ASAP, but not sure when it will be.

FYI, I think Apple chose 16 byte alignment so that they can utilize
SSE for floating point. As SSE requires 16 byte alignment for fp load/
store, it's inevitable. As all Intel Macs from Apple is SSE capable I
think it's good choice for them.

One more comment.
When I tried to port the ASM codes, I chose to use NASM which is free
and pre-installed with Mac dev tools. NASM is not fully MASM
compatible but much better than unix style asm. The last time I
checked, the linux port was changing all asm code to c++ code, which I
think is much harder to understand and maintain, and would be very
hard to port to 64 bit.
I think porting all asm codes to nasm should be the first step, and I
was in the middle of the job.
If anyone is interested in using NASM code, I'll try my best to finish
it (on a 32 bit linux first so that I can be sure it works fine).

Hyungjip Kim

talksmall

unread,
Jun 15, 2008, 10:05:27 AM6/15/08
to Strongtalk-general
Hi Hyungjip (or should that be "Hi Kim", please pardon my ignorance!),

On Jun 12, 8:53 am, Hyungjip Kim <hyung...@mac.com> wrote:
> I worked on porting VM to Mac last summer, but stopped working on it
> as I became rather busy.
> It's not an easy job. I don't think the EBX is the problem, as it's
> required only by position independent programs. But 16 byte alignment
> is a big challenge.

Maybe, maybe not. I believe that the 16-byte alignment requirement is
a requirement of the C ABI, so it should only be necessary in order to
call C/C++ code.

Calls within the VM to non-C/C++ code whilst executing interpreted
code or native nmethod code should not need to be 16-byte aligned.
Calls from interpreter's assembler code to C/C++ should go via the
InterpreterGenerator's call_C function (more accurately call_C
generates assembler instructions for calling C code) which in turn
calls MacroAssembler::call_C. Typically this saves the last delta
frame pointer and sets up an inline cache. It could do more, such as
aligning the stack frame for a C call. Most (but sadly not all) such
calls are parameterless, which simplifies things. Where parameters are
passed to C code (such as in the compiled IC lookups) the calling code
could be modified to ensure 16-byte frame alignment (eg. in
StubRoutines::generate_ic_lookup() or
PrimitivesGenerator::allocateContext_var()).

>
> MASM enter/leave would not help, methinks. As the assembly code uses
> many tricks to switch between native code and VM emulation such as
> jumps between asm functions and C++ functions and return with modified
> stack, rather than regular call/return.

Generally speaking such stack manipulation is in the context of delta
(ie. Smalltalk) frames called from other delta frames, or C functions
manipulating the contents of delta frames that invoked them. The delta
frames themselves are linked together by framepointers, even to the
extent that new calls to delta methods from C/C++ code are linked to
the last delta frame on the stack prior to the call to C/C++ code. I
think that the main tricky case is NLRs that fall through the stack
and hit C/C++ frames (or, more generally non-delta frames). In this
case the code sets the flag have_nlr_through_C and returns to the
calling function. Typically the C/C++ code will return to the prior
delta frame, cleaning up as it goes.

>
> I think the best way is to port to 64 bit, as Mac OS X (darwin) uses
> the same calling convention on 64 bit processors. But as my Mac was 32
> bit at the time, I paused working on VM then got busy. Now I bought
> myself a new 64 bit Intel Mac and I want to resume working on porting
> to Mac / 64 bit ASAP, but not sure when it will be.
>

I think porting to 64-bit is actually quite a bit bigger job. It is
not just a question of changing oopSize and you're done ;) (I know you
know that!) All of the compiler and assembler code would need to be
modified to use 64 bit registers and instructions.

> FYI, I think Apple chose 16 byte alignment so that they can utilize
> SSE for floating point. As SSE requires 16 byte alignment for fp load/
> store, it's inevitable. As all Intel Macs from Apple is SSE capable I
> think it's good choice for them.
>
> One more comment.
> When I tried to port the ASM codes, I chose to use NASM which is free
> and pre-installed with Mac dev tools. NASM is not fully MASM
> compatible but much better than unix style asm. The last time I
> checked, the linux port was changing all asm code to c++ code, which I
> think is much harder to understand and maintain, and would be very
> hard to port to 64 bit.

But nevertheless essential, since the code generator uses the macro
assembler for all of its generated code.

> I think porting all asm codes to nasm should be the first step, and I
> was in the middle of the job.
> If anyone is interested in using NASM code, I'll try my best to finish
> it (on a 32 bit linux first so that I can be sure it works fine).
>

The reason for porting the assembler routines to the built-in macro
assembler was partially to unify the assembler code in the VM. Short
of linking in an assembler into the Strongtalk VM we cannot get rid of
the existing macro assembler that is used by the code generator, and
that would create all sorts of complications (not least license
complications) and quite probably make the code generation slower.
Rather than have four languages to code in - Smalltalk, C/C++, the
built in macro assember and NASM(or TASM or some other assembler
variant) - using the built-in macro assembler to generate the stub and
interpreter routines allows us to reduce this to three.

Regards, Steve

Brian de Alwis

unread,
Jun 17, 2008, 1:35:31 AM6/17/08
to Strongtalk-general
I'm only able to work on this in spurts, which makes for rather slow
going. Hyungyip Kim is right: according to the apple docs and other
webpages I've found, the 16-byte stack alignment is necessary for SSE.

What I've done right now is hack MacroAssembler::call_C to align the
stack before the call like the following:

void MacroAssembler::call_C(Register entry) {
set_last_Delta_frame_before_call();
- call(entry);
+#ifdef ALIGN_STACK
+ // align stack to N-byte boundary; assumes esp grows down
+ // which is true on intel. Assumes ebx is preserved across
+ // the call
+ pushl(ebx);
+ movl(ebx,esp); // remember unaligned esp
+ subl(esp,4); // add space for unaligned esp
+ andl(esp, -ALIGN_STACK); // with the subl, we have at least 4 bytes
avail
+ addl(esp,4);
+ pushl(ebx);
+ call(entry);
+ popl(ebx);
+ movl(esp,ebx); // restore stack pointer prior to alignment
+ popl(ebx);
+#else
+ call(entry);
+#endif
reset_last_Delta_frame();
}

This allows execution to progress a bit further, but the VM crashes as
the program counter (PC) obtained from the last_frame (that is
frame::_pc) of the delta process is out of range. This frame is being
spoofed up from the following constructor (vm/runtime/frame.hpp lines
72--76):

frame(oop* sp, int* fp) {
_sp = sp;
_fp = fp;
_pc = (char*) sp[-1];
}

That last line is returning a pointer with address 0x89, which I
suspect indicates that the stack layout assumed of the delta processes
is different from the reality.

(gdb) down
#0 frame::frame (this=0xb0102da4, sp=0xb0102e60, fp=0xb0102e6c) at
frame.hpp:76
76 _pc = (char*) sp[-1];
(gdb) p sp[-1]
$7 = (oopDesc *) 0x89
(gdb) p sp[0]
$8 = (oopDesc *) 0x10a1b29

Those sp and fp values don't match the values I see for the frames in
gdb though.

I need to figure out more about the delta processes and what they're
recording on the stack.

Brian.

Hyungjip Kim

unread,
Jun 17, 2008, 5:41:59 AM6/17/08
to Strongtalk-general
Hi Steve,

The whole problem is that strongtalk implementation has too many
clever tricks, and the assembly code and C++ functions are really
interleaved. I tried to make a simple stub that align stack. But there
are too much code (assembly) that simply jump to C/C++ function
address, often indirectly.

Another problem is that the VM use system stack pointer (ESP) for VM
operand stack and even put bytecodes to system stack, making the
alignment hard to keep.

I fixed most of the call stubs including call_C many code generated in
C functions, yet it was not sufficient. I stopped while modifying
codes for bytecode primitives.

Yet I think we can make the 32 bit code work. What I'm saying is that
it's a long and hard work. Just fixing a few functions or making a
clever macro doesn't work. I tried.

Anyway, the reason I recommend using NASM is that it's less intuitive
to read and write asm code mapped to c functions, making it less
productive and error prone. And it has limitation on forward reference
to labels, if I recall correctly.

The runtime code generator is there already and it doesn't depend on
external assembler.
I'm not proposing to get rid of code generator written in C. What I'm
saying is that we'd better translate static assembly code which was
written in external MASM syntax to NASM, and keep static linking those
modules. For dynamically generated code we have no other way than
using code generator in C, and there is no reason to call external
assembler at run time.

But as you've done a lot of work already, it's up to you which way to
take.

Regards,
Hyungjip

PS> I want to send you my code so that you can take a look. But I'm
out of town now and will be for more than a month, that I can't access
the code at my home.
I'll resume working on Strongtalk VM as soon as possible. But it's not
before August.

Brian de Alwis

unread,
Jun 17, 2008, 1:46:53 PM6/17/08
to Strongtalk-general
On Jun 17, 3:41 am, Hyungjip Kim <hyung...@mac.com> wrote:
> The whole problem is that strongtalk implementation has too many
> clever tricks, and the assembly code and C++ functions are really
> interleaved. I tried to make a simple stub that align stack. But there
> are too much code (assembly) that simply jump to C/C++ function
> address, often indirectly.
>
> Another problem is that the VM use system stack pointer (ESP) for VM
> operand stack and even put bytecodes to system stack, making the
> alignment hard to keep.

I just discovered gcc's -mstackalign option. Compiling strongtalk
with that flag certainly lets it get further:

===========================
- VM is in debug mode
[Reading in ../strongtalk.bst, n, 0.389 secs]

[A Runtime Error Occurred]
assert(handle != __null, "could not find library: dlopen(KERNEL32.DLL,
1): image not found")
os_darwin.cpp, 301
Last 10 internal VM events:
- creating process 0x500870
- creating process 0x500980
DLL lookup GetCommandLineA in kernel failed.

[A Runtime Error Occurred]
assert(!is_scheduler(), "active must be other than scheduler")
process.cpp, 289
Last 10 internal VM events:
- creating process 0x500870
- creating process 0x500980
Bus Error
===========================

Credit to: <http://0xced.blogspot.com/2006/06/using-gnu-lightning-on-
intel-mac.html>. I came across that blog while looking at using a
different machine language backend like GNU Lightning or even building
on the LLVM JIT framework.

talksmall

unread,
Jun 17, 2008, 3:30:47 PM6/17/08
to Strongtalk-general
Brian,
Excellent. Good find. It looks like you are actually executing
Smalltalk code!

The particular error you are seeing is due to a DLL lookup failure
which is called from the DLL lookup primitives from Smalltalk.

Which image are you using? If it is just the image checked out of SVN,
that would explain why you are trying to load "KERNEL32.DLL" which is
a Windows DLL that is, unsurprisingly, not on your system. You should
download the image and sources zip file from the downloads page on the
WIKI and unzip them into your strongtalk installation directory.

You should also make sure that os::platform_class_name() looks like
the following in your os_darwin.cpp.

char* os::platform_class_name() { return "UnixPlatform"; }

This class is looked up in Smalltalk system dictionary on start-up and
installed as the alias Platform, allowing the same image file to be
shared across different OSes, which is a real boon when editing
Smalltalk code for the image, as you can edit it on Windows where
there is a UI, until we port the UI code for other OSes.

Another thing to look out for is the fact that the UnixPlatform code
assumes that if you are looking for libc, then the file name should be
libc.so.6. This is to work around a problem with Linux linker scripts.
Unfortunately dlopen does not process these, it only deals with proper
shared object files. If you have a different version of libc, you may
need to create a link named libc.so.6 somewhere in your
LD_LIBRARY_PATH in order for dlopen to find the libc shared object
file.

At the moment, about all you can do on non-Windows platforms is to run
a script to execute Smalltalk code from the command line. That said,
that is quite a lot and you should still be able to use most non-UI
functionality. As an exercise in masochism I developed most of the
ANSI exception handling code on Linux just using a text editor and
then filing in from the command line. So you can do useful stuff even
without the UI, though of course a UI will make things much more
productive.

To use the command line script you pass an argument like "-script
tools/test.dlt" at the end of the command that you use to start
Strongtalk. This tells the image to load and run a script file named
test.dlt in directory tools and exit when complete. If an error occurs
during execution then the command line evaluator should kick in and
display a trace of the top 20 frames from the process that was
executing at the time.

I'll be interested to see how you get on. At some stage we will want
to do something about 16-byte alignment, since from the looks of it
you may see a significant hit on performance with the extended
prologue and epilogue which rather defeats the purpose of a high
performance VM, but we've got to start somewhere and this seems like a
big step forward.

Regards, Steve

Brian de Alwis

unread,
Jun 17, 2008, 9:07:42 PM6/17/08
to Strongtalk-general
Hi Steve. You're right -- I was using the wrong image. Using your
previously-provided image for Unix with the VM compiled with -
mstackalign, running with +TraceLookup, confirms that I'm definitely
running lots of ST code. If I run with '-script ...' I'll eventually
break into the built-in debugger as the unix image fails when it tries
to load libc.so.6. (Perhaps we should change the ST code to catch the
DLL lookup failure and log the failure instead?)

Linking Darwin's equivalent to that name (/usr/lib/libSystem.B.dylib)
causes a bus error and with rampant corruption of the stack. I
suspect this is occurring as the stack isn't aligned, and my stack-
alignment patch above doesn't seem to do the right thing. I'll try
poking at this some more tonight.

Brian.


talksmall

unread,
Jun 18, 2008, 3:31:19 PM6/18/08
to Strongtalk-general


On Jun 18, 2:07 am, Brian de Alwis <briandeal...@gmail.com> wrote:
> Hi Steve. You're right -- I was using the wrong image. Using your
> previously-provided image for Unix with the VM compiled with -
> mstackalign, running with +TraceLookup, confirms that I'm definitely
> running lots of ST code. If I run with '-script ...' I'll eventually
> break into the built-in debugger as the unix image fails when it tries
> to load libc.so.6. (Perhaps we should change the ST code to catch the
> DLL lookup failure and log the failure instead?)

Actually, a failure to find a shared library (DLL or .so) results in
an assertion failure being logged in the console. So does a failure to
find a named function within a library. The problem here is that we
are very early in the image start up code, and if it can't load libc
(or equivalent) then if can't open the test script, and since there is
no UI yet for non-Windows it can't do diddly! One issue is that the
Foreign Function interface in Smalltalk (see this page on the Wiki -
http://code.google.com/p/strongtalk/wiki/ForeignFunctions ) doesn't
provide a Smalltalk fail block for DLL lookup failures. It just
assumes that the DLL is available. If the DLL is missing, it is
essentially a pretty major error. Going forward we should probably add
some generic failure code to throw an appropriate Smalltalk exception.
We can then add an exception handler to handle this in the normal way,
when it makes sense.

>
> Linking Darwin's equivalent to that name (/usr/lib/libSystem.B.dylib)
> causes a bus error and with rampant corruption of the stack. I
> suspect this is occurring as the stack isn't aligned, and my stack-
> alignment patch above doesn't seem to do the right thing. I'll try
> poking at this some more tonight.
>
> Brian.

The -mstackrealign flag is fine for the code being compiled by GCC,
but it won't do anything for code not compiled with that setting. -
mstackrealign alters the prologue and epilogue of the functions
compiled by the compiler to align the arguments appropriately. Since,
presumably, your library has not been compiled with these options it
won't do the realignment which results in the failure.

To fix this we need to update the code that calls the DLL to ensure
that the arguments are aligned. To that end I've created the following
patch to the DLL call routine to align the stack. Can you apply it and
try it out? Since the resulting code still appears to work in Windows
(I tried it without any issues), if this works for you we may as well
keep it in the mainline code. Note that I have commented out the
pushing of ebx in line with Hyungjip's comments re position
independent code.

Let me know how you get on.

Regards, Steve

Index: stubRoutines.cpp
===================================================================
--- stubRoutines.cpp (revision 139)
+++ stubRoutines.cpp (working copy)
@@ -509,6 +509,14 @@
//slr mod: push a fake stack frame to support cdecl calls
masm->enter();
//slr mod end
+ // following is to allow 16-byte stack alignment for Darwin (OSX)
+ masm->movl(eax, ebx);
+ masm->negl(eax);
+ masm->leal(eax, Address(esp, eax, Address::times_4)); // esp - 4 x
nargs
+ masm->andl(eax, 0xf); // padding required for 16-byte alignment
+ masm->subl(esp, eax); // align stack
+ // end stack alignment mod
+
masm->testl(ebx, ebx); // if number of arguments != 0 then
masm->jcc(MacroAssembler::notZero, loop_entry);// convert arguments

@@ -823,6 +831,7 @@

masm->pushl(edi); // save registers for C calling convetion
masm->pushl(esi);
+ //masm->pushl(ebx);

// reset last Delta frame
masm->reset_last_Delta_frame();
@@ -863,6 +872,7 @@

masm->bind(_return);
masm->leal(esp, Address(ebp, -4*oopSize));
+ //masm->popl(ebx);

Brian de Alwis

unread,
Jun 19, 2008, 1:29:51 AM6/19/08
to Strongtalk-general
Hi Steve. Your patch works. Execution proceeds further, and now the
start up fails as '__fxstat' cannot be resolved. Which is good news:
it means that the previously-failing open call was completed
successfully -- the stack alignment code works.

Re: __fxstat is a Linuxism, unfortunately. With the plethora of unix-
like OSs and their different representations (e.g., 32-bit or 64-bit
file offsets), it seems to me that we're better off trying to define a
minimal spec for handling files and embed those as primitives. I
think it would greatly simplify moving to bootstrapping the VM.

> Actually, a failure to find a shared library (DLL or .so) results in
> an assertion failure being logged in the console. So does a failure to
> find a named function within a library. The problem here is that we
> are very early in the image start up code, and if it can't load libc
> (or equivalent) then if can't open the test script, and since there is
> no UI yet for non-Windows it can't do diddly! One issue is that the
> Foreign Function interface in Smalltalk (see this page on the Wiki -http://code.google.com/p/strongtalk/wiki/ForeignFunctions) doesn't
> provide a Smalltalk fail block for DLL lookup failures. It just
> assumes that the DLL is available. If the DLL is missing, it is
> essentially a pretty major error. Going forward we should probably add
> some generic failure code to throw an appropriate Smalltalk exception.
> We can then add an exception handler to handle this in the normal way,
> when it makes sense.

I see -- and once your ANSI exceptions are in there, then
Object>>#error: can be redefined and handled properly. Sound cool.

If I can trouble you with one more question: what's the easiest or
recommended way to modify the ST code (e.g., so as to fixup the
__fxstat problem above) and dump a new image? A quick scan of the
strongtalk web and googlecode sites didn't show anything. I assume it
has to be done from Windows...?

Brian.

talksmall

unread,
Jun 19, 2008, 1:53:51 PM6/19/08
to Strongtalk-general
On Jun 19, 6:29 am, Brian de Alwis <briandeal...@gmail.com> wrote:
> Hi Steve. Your patch works. Execution proceeds further, and now the
> start up fails as '__fxstat' cannot be resolved. Which is good news:
> it means that the previously-failing open call was completed
> successfully -- the stack alignment code works.

Excellent. A step in the right direction at least.

>
> Re: __fxstat is a Linuxism, unfortunately. With the plethora of unix-
> like OSs and their different representations (e.g., 32-bit or 64-bit
> file offsets), it seems to me that we're better off trying to define a
> minimal spec for handling files and embed those as primitives. I
> think it would greatly simplify moving to bootstrapping the VM.
>

Actually, I think it's a libc-ism, but it doesn't really matter. The
core problem is the same - it doesn't work in OSX. I'm not sure that I
agree with the remedy though. I would prefer to avoid adding file
support primitives which would then need to hook into additional os::
functions for each platform. This implies more work in C++ to get each
platform up and running. It seems better to try to minimise the
additional work in C++ in order to port to a new platform. I had to
add one primitive for the Linux port, in order to give access to the
command line arguments, since Linux doesn't provide access to these
via a library function, but that primitive doesn't rely on any new OS-
related functionality - it just picks up the previously saved values.

The next thing would be to add primitives for UI support, so that we
can plugin XYZ whizzy UI framework and thus begins the slippery slope
to primitive overload.

We have a hook - through the os::platform_class_name() function - to
plug in different platform classes in the Smalltalk image. In this
case we appear to need to override the platform class with a new
"OSXPlatform" or "DarwinPlatform", which could possibly subclass the
existing UnixPlatform if the differences are small enough. Not that
the UnixPlatform class is not complete. I took a very opportunistic
approach with the Linux port.

Basically, I cloned the original Platform class as Win32Platform and
UnixPlatform and then modified those things that I needed to to get
the Linux VM to run the command line test script. I also created
clones of the Win32FilePath and Win32FilePattern classes for file
handling.

> > Actually, a failure to find a shared library (DLL or .so) results in
> > an assertion failure being logged in the console. So does a failure to
> > find a named function within a library. The problem here is that we
> > are very early in the image start up code, and if it can't load libc
> > (or equivalent) then if can't open the test script, and since there is
> > no UI yet for non-Windows it can't do diddly! One issue is that the
> > Foreign Function interface in Smalltalk (see this page on the Wiki -http://code.google.com/p/strongtalk/wiki/ForeignFunctions) doesn't
> > provide a Smalltalk fail block for DLL lookup failures. It just
> > assumes that the DLL is available. If the DLL is missing, it is
> > essentially a pretty major error. Going forward we should probably add
> > some generic failure code to throw an appropriate Smalltalk exception.
> > We can then add an exception handler to handle this in the normal way,
> > when it makes sense.
>
> I see -- and once your ANSI exceptions are in there, then
> Object>>#error: can be redefined and handled properly. Sound cool.

Actually the ANSI exception support already does this for error:,
doesNotUnderstand: and halt to signal the relevant exceptions (Error,
MessageNotUnderstood and Halt, respectively). Actually Halt is not an
ANSI exception, but it seemed to make sense. I haven't yet touched any
of the other process errors.

>
> If I can trouble you with one more question: what's the easiest or
> recommended way to modify the ST code (e.g., so as to fixup the
> __fxstat problem above) and dump a new image? A quick scan of the
> strongtalk web and googlecode sites didn't show anything. I assume it
> has to be done from Windows...?
>
> Brian.

At the moment UI-based development (ie. using the programming
environment) has to be done from Windows. If you have access to a
Linux environment you can file-in changes and save the image using the
command line script, but that gets old quite quickly and I wouldn't
recommend it unless you are rabidly anti-Windows. I found it much
easier to make changes in the UI programming environment under
Windows.

Do you have Parallels or dual boot access to Windows?

In any case, I feel quite strongly that we should avoid forking the VM
code in order to support a new platform (not that anyone has suggested
it yet). We have precious few people contributing to the VM at the
moment and we don't want to make that work any harder. For that reason
we need to ensure that when we do make changes in order to support a
new platform that those changes don't break our existing platforms. In
particular, since the Windows environment is by far the most complete
we should make every effort to avoid breaking it. That means that
everyone who is tinkering with the VM code really needs access to a
Win32 environment (ideally all platforms, but most people don't have
the resources for that) where they can check that they haven't broken
anything.

Regards, Steve

Brian de Alwis

unread,
Jun 19, 2008, 9:41:11 PM6/19/08
to Strongtalk-general
You're right, __fxstat is a glibcism. It won't work in the *BSDs
either.

I do have VMWare Fusion. I tried rebuilding an image last night from
the Strongtalk 2.0 binary distribution, but it failed and I didn't
have time to investigate why. From searching on the newsgroups, it
appeared that rebuilding the image only used the in-memory source
code, and not the changes on disk. Is that correct? Is there a way
to instead load the file-outs from disk?

I'm only pushing file prims as I'm seeking a way for new ports to
escape from my same bootstrapping catch-22: I can't get a headless VM
running because of the __fxstat issue causes it to crash, but I can't
file in a change (even if only a hack) to rewrite the file I/O code to
get the VM working as filing in uses the file I/O code which refers to
non-existent OS functions like __fxstat. Perhaps we could have just
two simple primitive for bootstrapping purposes only: get-directory-
contents and read-file-contents. And port SWIG to access everything
else.

Porting the VM to Darwin was pretty trivial thanks to your help and -
mstackrealign -- the heavy lifting has been done in the port to
Linux. The os_darwin.cpp I've made is a lightly modified copy of the
os_linux.cpp. To make porting to new platforms a bit easier, I'd
suggest is instead of having to reimplement os for each new platform,
we provide an implementation for posix systems that Linux, Darwin,
etc. can specialize as necessary. The appropriate `os' instance would
be set in main().

Brian.

talksmall

unread,
Jun 19, 2008, 10:31:13 PM6/19/08
to Strongtalk-general
On Jun 20, 2:41 am, Brian de Alwis <briandeal...@gmail.com> wrote:
> You're right, __fxstat is a glibcism. It won't work in the *BSDs
> either.
>
> I do have VMWare Fusion. I tried rebuilding an image last night from
> the Strongtalk 2.0 binary distribution, but it failed and I didn't
> have time to investigate why. From searching on the newsgroups, it
> appeared that rebuilding the image only used the in-memory source
> code, and not the changes on disk. Is that correct? Is there a way
> to instead load the file-outs from disk?

I'm not sure I know what you mean when you talk about "rebuilding an
image". Do you mean recompileWorld? If so, that works not from source
code in memory, but from the source code in the source database in the
source directory. This contains a largish strongtalkchange.log that
contains the filed-in source, a strongtalkrestore.log that contains
sources filed in since the image was last saved and lots of little
files describing the source locations within the change log of all the
classes and methods in the image.

Recompile world was broken, but is fixed in later images including the
one on the download page of the wiki, though this won't work with the
Strongtalk 2.0 binary.

To obtain a Windows binary that does work with later images you will
probably need to build one. That's not as bad as it sounds, since MS
now offer an edition of VC++ Express 2008 that you can download for
free. You can then use that to build the binary. As I mentioned in my
earlier email, this would be a good thing to have anyway as it would
let you check that any VM changes you make don't break the Windows
build.

If that is too daunting, I can build you a stripped binary that you
should be able to use for image editing. It will have to wait until
the weekend though.
>
> I'm only pushing file prims as I'm seeking a way for new ports to
> escape from my same bootstrapping catch-22: I can't get a headless VM
> running because of the __fxstat issue causes it to crash, but I can't
> file in a change (even if only a hack) to rewrite the file I/O code to
> get the VM working as filing in uses the file I/O code which refers to
> non-existent OS functions like __fxstat. Perhaps we could have just
> two simple primitive for bootstrapping purposes only: get-directory-
> contents and read-file-contents. And port SWIG to access everything
> else.

I understand the reasoning but it's not just a couple of functions.
From my somewhat hazy memory there were about 6 or so foreign function
calls that were necessary in order to be able to execute the script.
Additionally it would look a little odd to have the bootstrap script
read in by one set of file handling functions and then use a different
set for the file handling abstractions used by ordinary code. Of
course we could mix and match, but that would probably be even worse.
The primitives and the foreign functions would need to be consistent.

I have another, perhaps more pragmatic reason for not wanting to go
down this route. I actually don't mind if there is a little inertia
involved in porting to a new platform. A certain amount of diversity
is good, but when we have as few people actively involved in the
project as we do it is very easy to stretch resources too thin.

>
> Porting the VM to Darwin was pretty trivial thanks to your help and -
> mstackrealign -- the heavy lifting has been done in the port to
> Linux. The os_darwin.cpp I've made is a lightly modified copy of the
> os_linux.cpp. To make porting to new platforms a bit easier, I'd
> suggest is instead of having to reimplement os for each new platform,
> we provide an implementation for posix systems that Linux, Darwin,
> etc. can specialize as necessary. The appropriate `os' instance would
> be set in main().
>
> Brian.

It depends how you do it. One approach would be to create a posixOS
base class, in a posixOS.cpp module. The code in this file would be
bracketed with #ifdef _POSIX ... #endif, or something similar. In
separate files named as now - ie. os_linux.cpp, os_darwin.cpp, etc. -
we would put code for a derived class named os that would contain the
platform-specific differences from the POSIX base class. The advantage
of this approach is that we don't need to determine which platform we
are running on anywhere outside of the os_* modules, since we can just
reference the os class in all cases.

I don't see much point in defining the os:: functions as virtual.
There will only be one version appropriate to a given binary.

Regards, Steve

Brian de Alwis

unread,
Jun 20, 2008, 1:48:09 AM6/20/08
to Strongtalk-general
On Jun 19, 8:31 pm, talksmall <StephenLR...@googlemail.com> wrote:
> I'm not sure I know what you mean when you talk about "rebuilding an
> image". Do you mean recompileWorld? If so, that works not from source
> code in memory, but from the source code in the source database in the
> source directory. This contains a largish strongtalkchange.log that
> contains the filed-in source, a strongtalkrestore.log that contains
> sources filed in since the image was last saved and lots of little
> files describing the source locations within the change log of all the
> classes and methods in the image.

Ah, I see. Ok, I'll compile up a windows version and tinker with the
source. Thanks for your patience in answering questions.

Brian.

talksmall

unread,
Jun 29, 2008, 12:21:54 PM6/29/08
to Strongtalk-general
Hi Brian,
Just wondering how you were getting on with creating new Smalltalk
platform classes for the OSX port. Did your windows build work OK? If
not, I can still generate a binary for you to use. Let me know if you
would like me to do this.

Regards, Steve

Brian de Alwis

unread,
Jun 30, 2008, 12:15:55 AM6/30/08
to Strongtalk-general
Hi Steve. Thanks for asking. I've managed to build a new VM under
VisualStudio. Unfortunately my Darwin-patched sources leads to a
failed assertion when filing in code, such as your ANSI exceptions.
But a VM built from a fresh set of sources works fine. So I'm in the
middle of figuring out what part of my patches causes the issue. (I
can't seem to figure out how to get VisualStudio to load the .pdb file
for debugging symbols though.)

Even with fresh sources, however, recompiling the world (File ->
Recompile world) fails in DeltaCompiler>>#copyParameters: as a method-
scope's toHeap block is being fired, and the block is raising an
error. I'm finding it a bit difficult to navigate the UI to figure
out what source object is causing the problem though.

Otherwise, I've been figuring out the UI environment, and trying to
figure out how to move forward. I've currently created a
'DarwinPlatform' class and rewrote DLLMapName: to instead return an
array of library names (and modify its dependents). I'm trying to
figure out what to do with StatBuffer and its indices.

I'm also trying to figure out how to manage source code: I'm from an
ENVY background and am finding the ball'o'wax file-in/file-out model a
big perplexing. For example, your ANSI exception source includes
SUnit test methods -- I don't dispute that they have a purpose being
on Exception, but they shouldn't be in the file-in.

So I'm making progress, slowly but surely.

Brian.

talksmall

unread,
Jun 30, 2008, 8:05:53 PM6/30/08
to Strongtalk-general
On Jun 30, 5:15 am, Brian de Alwis <briandeal...@gmail.com> wrote:
> Hi Steve. Thanks for asking. I've managed to build a new VM under
> VisualStudio. Unfortunately my Darwin-patched sources leads to a
> failed assertion when filing in code, such as your ANSI exceptions.

Which assertion fails? Is it an assertion in Smalltalk or an assertion
in the VM? Can you send me your patches?

> But a VM built from a fresh set of sources works fine. So I'm in the
> middle of figuring out what part of my patches causes the issue. (I
> can't seem to figure out how to get VisualStudio to load the .pdb file
> for debugging symbols though.)

Strange about the symbols. Are you using the solution file under the
build.win32 directory?

>
> Even with fresh sources, however, recompiling the world (File ->
> Recompile world) fails in DeltaCompiler>>#copyParameters: as a method-
> scope's toHeap block is being fired, and the block is raising an
> error. I'm finding it a bit difficult to navigate the UI to figure
> out what source object is causing the problem though.
>
> Otherwise, I've been figuring out the UI environment, and trying to
> figure out how to move forward. I've currently created a
> 'DarwinPlatform' class and rewrote DLLMapName: to instead return an
> array of library names (and modify its dependents). I'm trying to
> figure out what to do with StatBuffer and its indices.

Pardon my ignorance, but I have no knowledge of the Darwin
environment. Is StatBuffer relevant to Darwin? Does Darwin have a libc
equivalent? If so, one option would be to create a DarwinStatBuffer,
which may or not subclass the existing StatBuffer, and just override
the offset and length accessors with appropriate values for Darwin.

>
> I'm also trying to figure out how to manage source code: I'm from an
> ENVY background and am finding the ball'o'wax file-in/file-out model a
> big perplexing. For example, your ANSI exception source includes
> SUnit test methods -- I don't dispute that they have a purpose being
> on Exception, but they shouldn't be in the file-in.

Oops. That was careless of me. Bit of a chicken and egg situation
though. I wanted to use SUnit tests to express the intent of the
Exception handling, however SUnit depends on Exception handling. I
wrote a little utility to help with managing the fileouts, but it is
inclusive rather than exclusive (by which I mean it is much easier to
include more of something than exclude a part).

Going forward Smalltalk source code management will be an issue. Quite
apart from anything else if you file things in in the wrong order the
later file ins may break. Consider, for example, class Foo which
contains a reference to a global Bar. Bar happens to be another class.
If you file in Bar before Foo, everything is good. If you file in Foo
before Bar, the Foo file in will create a global variable named bar
with value nil. A subsequent attempt to file in Bar will fail as it
attempts to redefine the global Bar.

One option for the longer term might be something like Monticello
which is what Squeak uses. I haven't looked into whether that is
practical, though.

Colin Putney

unread,
Jun 30, 2008, 9:42:06 PM6/30/08
to strongtal...@googlegroups.com

On 30-Jun-08, at 5:05 PM, talksmall wrote:

> One option for the longer term might be something like Monticello
> which is what Squeak uses. I haven't looked into whether that is
> practical, though.

Shouldn't be too difficult. I'm not a VM hacker, but if you guys get
Strongtalk running on Darwin, I can port Monticello.

Colin

Brian de Alwis

unread,
Jul 1, 2008, 1:50:57 AM7/1/08
to Strongtalk-general
Hi Steve. I've attached my Darwin patches here. I've rearranged your
posting slightly to explain Darwin first. I think that will help in
interpreting my comments about the patches.

> Pardon my ignorance, but I have no knowledge of the Darwin
> environment. Is StatBuffer relevant to Darwin? Does Darwin have a libc
> equivalent? If so, one option would be to create a DarwinStatBuffer,
> which may or not subclass the existing StatBuffer, and just override
> the offset and length accessors with appropriate values for Darwin.

You can think of Darwin as a BSD Unix user space overlaid on top of
the Mach microkernel. From a development perspective, it looks like a
Unix/POSIX world with a bunch of extra libraries, called frameworks,
that provide windowing, inter-app communication, preferences,
accelerated graphics, etc. That's why the Darwin port was so easy: it
leveraged the heavy lifting from the Linux port, with the help of
gcc's -mstackrealign.

So Darwin has stat/fstat and a 'struct stat', just like any other
Unix. It has a libc, though it's really called libSystem.dylib, but
there's a symlink to libc.dylib too. So the calling interface is the
same, with the same structures, etc. But the order of a structure's
elements may be different, and that's true of other unices too. So
Darwin will likely need a StatBuffer and so will any other new OS.

My concern with having a DarwinStatBuffer (and a NetBSDStatBuffer, and
FreeBSDStatBuffer, ...) is that we suffer an explosion and start
pushing environment details into the Smalltalk code. But that's
something that can be dealt with later.

> > Unfortunately my Darwin-patched sources leads to a
> > failed assertion when filing in code, such as your ANSI exceptions.
>
> Which assertion fails? Is it an assertion in Smalltalk or an assertion
> in the VM? Can you send me your patches?

It's a VM assertion in Klass::local_lookup(symbolOop) at line 271:

assert(mixin()->is_mixin(), "mixin must exist");

I've attached my patches here; the changes are in two parts, and are
straightforward:

1. darwin independent: fixing minor issues to do with the build
process
a) there are two copies of makedeps, in /makedeps and /tools/
makedeps:
I removed /makedeps
b) some minor win32 build issues, and use /tools/makedeps
c) some additions to header files to get them to build
2. darwin related:
a) patched /tools/makedeps for Darwin/MacOSX
b) cp -r build.linux build.darwin; hack appropriately
c) cp vm/runtime/os_linux.cpp vm/runtime/os_darwin.cpp and hack
appropriately
d) some Darwin-related #ifdefs to header files to get them to
build

You'll see in vm/prims/prim.cpp that I commented out the ebx stack
checking -- this was causing compilation issues on Darwin.

But there's nothing that jumps out at me as to why the Win32 VM is
failing that assertion.

> > But a VM built from a fresh set of sources works fine. So I'm in the
> > middle of figuring out what part of my patches causes the issue. (I
> > can't seem to figure out how to get VisualStudio to load the .pdb file
> > for debugging symbols though.)
>
> Strange about the symbols. Are you using the solution file under the
> build.win32 directory?

Yes.

The patches follow.

Brian.

=== removed directory 'makedeps'
=== removed directory 'build.win32/makedeps'

=== added directory 'build.darwin'
=== added file 'build.darwin/makedeps-platform.txt'
--- build.darwin/makedeps-platform.txt 1970-01-01 00:00:00 +0000
+++ build.darwin/makedeps-platform.txt 2008-06-19 04:19:50 +0000
@@ -0,0 +1,1 @@
+os = darwin

=== added file 'build.darwin/makefile'
--- build.darwin/makefile 1970-01-01 00:00:00 +0000
+++ build.darwin/makefile 2008-06-19 04:19:50 +0000
@@ -0,0 +1,94 @@
+# makefile for Strongtalk
+#
+# revision history
+#
-----------------------------------------------------------------------
+# 2007.02.20 dave....@gmail.com file created
+#
-----------------------------------------------------------------------
+
+include ../build.darwin/makefile-macros.incl
+
+LIB_DIR = $(BIN_DIR)/asm_objs/COFF/converted
+TEST_DIRECTORIES = $(TEST_SRC_DIR)/utilities \
+$(TEST_SRC_DIR)/runtime \
+$(TEST_SRC_DIR)/prims \
+$(TEST_SRC_DIR)/main \
+$(EASYUNIT_DIR)/src
+TEST-EXECUTABLE = $(BUILD_DIR)/strongtalk-test
+TEST_SHARED_LIB = $(BUILD_DIR)/strongtalk-test.so
+EXECUTABLE = $(BUILD_DIR)/strongtalk
+SHARED_LIB = $(BUILD_DIR)/strongtalk.so
+DIRECTORIES = $(TEST_DIRECTORIES) \
+$(VM_SRC_DIR)/asm \
+$(VM_SRC_DIR)/code \
+$(VM_SRC_DIR)/compiler \
+$(VM_SRC_DIR)/disasm \
+$(VM_SRC_DIR)/interpreter \
+$(VM_SRC_DIR)/lookup \
+$(VM_SRC_DIR)/memory \
+$(VM_SRC_DIR)/oops \
+$(VM_SRC_DIR)/prims \
+$(VM_SRC_DIR)/recompiler \
+$(VM_SRC_DIR)/runtime \
+$(VM_SRC_DIR)/utilities
+WRK=$(shell pwd)
+
+ifneq ($(WRK),$(BUILD_DIR))
+$(warning "Running in $(WRK)")
+$(error "Must be run from build directory: $(BUILD_DIR)")
+endif
+
+#default: dependencies objects link test
+default: objects link test
+
+test:
+ export LD_LIBRARY_PATH=$(WRK)
+ $(TEST-EXECUTABLE) -b ../strongtalk.bst
+
+link:
+ g++ $(OPT) -o $(EXECUTABLE) -L/usr/lib `find $(VM_SRC_DIR) -name
"*.o"` -lpthread
+ g++ $(OPT) -o $(TEST-EXECUTABLE) $(TEST_SRC_DIR)/main/main.o \
+ `find $(VM_SRC_DIR) -name "*.o"|grep -v main.o` \
+ `find $(TEST_SRC_DIR) -name "*.o"|grep -v main.o` $
(EASYUNIT_DIR)/src/*.o \
+ -lpthread
+
+# g++ -v $(OPT) -shared -o $(SHARED_LIB) -L/usr/lib `find $
(VM_SRC_DIR) -name "*.o"|grep -v main.o` -lpthread
+# g++ -v $(OPT) -o $(EXECUTABLE) -L/usr/lib $(VM_SRC_DIR)/*/main.o $
(SHARED_LIB)
+# g++ -v $(OPT) -shared -o $(TEST_SHARED_LIB) -L/usr/lib `find $
(TEST_SRC_DIR) -name "*.o"|grep -v main.o` $(EASYUNIT_DIR)/src/*.o
+# g++ -v $(OPT) -o $(TEST-EXECUTABLE) $(SHARED_LIB) $
(TEST_SHARED_LIB) $(TEST_SRC_DIR)/main/main.o
+
+objects: incls/_precompiled.incl.gch
+ for i in $(DIRECTORIES);\
+ do \
+ $(MAKE) $(MAKEFLAGS) -C $$i -f $(MAKE_DIR)/makefile.incl $@ || exit
$$?;\
+ done
+
+incls/_precompiled.incl.gch: $(BUILD_DIR)/includeDB.all
+ $(C++) -c -x c++-header -o $(BUILD_DIR)/incls/_precompiled.incl.gch -
g $(OPT) $(C++OPTIONS) $(DEFINES) $(INCL_PATH) incls/_precompiled.incl
+
+$(BUILD_DIR)/makedeps: $(TOOLS_SRC_DIR)/makedeps/makeDeps.cpp
+ $(C++) -o $@ $^
+# $(C++) -fno-write-strings -o $@ $^
+
+dependencies: $(BUILD_DIR)/makedeps $(INCL_PLATFORM) $(BUILD_DIR)/
includeDB.all
+ $(BUILD_DIR)/makedeps $(INCL_PLATFORM) $(BUILD_DIR)/includeDB.all
+
+$(BUILD_DIR)/includeDB.all: $(INCL_DB1) $(INCL_DB2)
+ $(RMDIR) $(INCL_DIR)
+ $(RM) Dependencies.hh $(BUILD_DIR)/includeDB.all includeDB.current
+ $(MKDIR) $(INCL_DIR)
+ $(CAT) $(INCL_DB1) $(INCL_DB2) >> $(BUILD_DIR)/includeDB.all
+
+$(INCL_PLATFORM):
+ $(TOUCH) $@
+
+clean:
+ $(RMDIR) $(INCL_DIR)
+ $(RM) Dependencies.hh $(BUILD_DIR)/includeDB.all includeDB.current
+ $(RM) *~
+ for i in $(DIRECTORIES);\
+ do \
+ $(MAKE) $(MAKEFLAGS) -C $$i -f $(MAKE_DIR)/makefile.incl clean;\
+ done
+
+pristine: clean
+ $(RM) $(BUILD_DIR)/makedeps

=== added file 'build.darwin/makefile-macros.incl'
--- build.darwin/makefile-macros.incl 1970-01-01 00:00:00 +0000
+++ build.darwin/makefile-macros.incl 2008-06-19 04:19:50 +0000
@@ -0,0 +1,52 @@
+# common defs for makefiles
+
+
+# ROOT_DIR = $(HOME)/strongtalk-r36-noasm6
+TEST_SRC_DIR = $(ROOT_DIR)/test
+VM_SRC_DIR = $(ROOT_DIR)/vm
+EASYUNIT_DIR = $(ROOT_DIR)/easyunit
+TOOLS_SRC_DIR = $(ROOT_DIR)/tools
+MAKE_DIR = $(ROOT_DIR)/build.darwin
+BUILD_DIR = $(ROOT_DIR)/build
+BIN_DIR = $(ROOT_DIR)/bin
+OPT=
+
+#C++OPTIONS= -fno-rtti -Wno-write-strings -fno-for-scope -fno-
operator-names -fms-extensions -ffriend-injection
+C++OPTIONS= -fno-rtti -Wno-write-strings -fno-for-scope -fno-operator-
names -fms-extensions
+
+INCL_PATH = -I$(BUILD_DIR) \
+ -I$(VM_SRC_DIR)/asm -I$(VM_SRC_DIR)/code \
+ -I$(VM_SRC_DIR)/compiler -I$(VM_SRC_DIR)/disasm \
+ -I$(VM_SRC_DIR)/interpreter -I$(VM_SRC_DIR)/lookup \
+ -I$(VM_SRC_DIR)/memory -I$(VM_SRC_DIR)/oops \
+ -I$(VM_SRC_DIR)/prims -I$(VM_SRC_DIR)/recompiler \
+ -I$(VM_SRC_DIR)/runtime -I$(VM_SRC_DIR)/topIncludes \
+ -I$(VM_SRC_DIR)/utilities \
+ -I$(EASYUNIT_DIR)/easyunit
+
+INCL_DIR = $(BUILD_DIR)/incls
+
+OS = $(shell uname)
+
+RMDIR = rm -rf
+MKDIR = mkdir
+RM = rm -rf
+CAT = cat
+MV = mv
+TOUCH = touch
+
+ifeq ($(OS),Linux)
+OS_DEF = -D__LINUX__
+else ifeq ($(OS),Darwin)
+OS_DEF = -D__DARWIN__
+endif
+DEFINES = -DDELTA_COMPILER -DASSERT -DDEBUG $(OS_DEF)
+
+CC = gcc -mstackrealign
+C++ = g++ -mstackrealign
+ASM = gcc -mstackrealign
+CFLAGS = -Wall
+
+INCL_DB1 = $(VM_SRC_DIR)/deps/includeDB
+INCL_DB2 = $(VM_SRC_DIR)/deps/includeDB2
+INCL_PLATFORM = $(MAKE_DIR)/makedeps-platform.txt

=== added file 'build.darwin/makefile.incl'
--- build.darwin/makefile.incl 1970-01-01 00:00:00 +0000
+++ build.darwin/makefile.incl 2008-06-19 04:19:50 +0000
@@ -0,0 +1,27 @@
+# makefile for strongtalk object files
+#
+# revision history
+#
----------------------------------------------------------------------
+# 2007.02.20 dave....@gmail.com file created
+# based on on work by cat...@gmail.com as posted to strongtalk
+# mailing list
+#
----------------------------------------------------------------------
+
+include ../../build.darwin/makefile-macros.incl
+
+SRCS = $(wildcard *.cpp)
+OBJS = $(patsubst %.cpp,%.o,$(SRCS))
+
+#CXXOPTS= -fno-rtti -fno-const-strings -fno-for-scope -fno-operator-
names \
+# -fms-extensions -ffriend-injection
+CXXOPTS= -fno-rtti -fno-const-strings -fno-for-scope -fno-operator-
names \
+ -fms-extensions
+
+%o: %cpp
+ $(C++) -c -g $(OPT) $(CXXOPTS) $(DEFINES) $(INCL_PATH) $<
+
+objects: $(OBJS)
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) *~

=== modified file 'build.linux/makefile'
--- build.linux/makefile 2008-05-28 23:33:59 +0000
+++ build.linux/makefile 2008-06-19 04:19:50 +0000
@@ -52,7 +52,7 @@
objects: incls/_precompiled.incl.gch
for i in $(DIRECTORIES);\
do \
- make -C $$i -f $(MAKE_DIR)/makefile.incl $@;\
+ $(MAKE) $(MAKEFLAGS) -C $$i -f $(MAKE_DIR)/makefile.incl $@ || exit
$?;\
done

incls/_precompiled.incl.gch: includeDB.all
@@ -79,7 +79,7 @@
$(RM) *~
for i in $(DIRECTORIES);\
do \
- make -C $$i -f $(MAKE_DIR)/makefile.incl clean;\
+ $(MAKE) $(MAKEFLAGS) -C $$i -f $(MAKE_DIR)/makefile.incl clean ||
exit $?;\
done

pristine: clean

=== modified file 'build.win32/strongtalk.sln'
--- build.win32/strongtalk.sln 2008-05-29 00:55:59 +0000
+++ build.win32/strongtalk.sln 2008-06-28 16:27:46 +0000
@@ -8,12 +8,10 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EasyUnit",
"easyunit\EasyUnit.vcproj", "{C594C167-71C2-4019-8A3B-F8C28069A0E6}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makedeps",
"makedeps\makedeps.vcproj", "{4C63951D-97E7-4846-8DD0-764CC4753D73}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strongtalk",
"strongtalk\strongtalk.vcproj", "{BFE5409B-5B2B-4667-A91A-
D5A5E7DC8A83}"
ProjectSection(ProjectDependencies) = postProject
- {4C63951D-97E7-4846-8DD0-764CC4753D73} =
{4C63951D-97E7-4846-8DD0-764CC4753D73}
{C594C167-71C2-4019-8A3B-F8C28069A0E6} = {C594C167-71C2-4019-8A3B-
F8C28069A0E6}
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233} = {FD5B94F7-55C2-4C96-
B89E-32DC1A737233}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strongtalk-
test", "strongtalk-test\strongtalk-test.vcproj",
"{DDDCEC02-9CCF-4178-9596-E00D6F71C083}"
@@ -22,6 +20,8 @@
{BFE5409B-5B2B-4667-A91A-D5A5E7DC8A83} = {BFE5409B-5B2B-4667-A91A-
D5A5E7DC8A83}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makedeps", "..
\tools\makedeps\makedeps.vcproj", "{FD5B94F7-55C2-4C96-
B89E-32DC1A737233}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -46,14 +46,6 @@
{C594C167-71C2-4019-8A3B-F8C28069A0E6}.Product|Win32.Build.0 =
Release|Win32
{C594C167-71C2-4019-8A3B-F8C28069A0E6}.Release|Win32.ActiveCfg =
Release|Win32
{C594C167-71C2-4019-8A3B-F8C28069A0E6}.Release|Win32.Build.0 =
Release|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Debug|Win32.ActiveCfg =
Debug|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Debug|Win32.Build.0 = Debug|
Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Fast|Win32.ActiveCfg =
Release|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Fast|Win32.Build.0 = Release|
Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Product|Win32.ActiveCfg =
Release|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Product|Win32.Build.0 =
Release|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Release|Win32.ActiveCfg =
Release|Win32
- {4C63951D-97E7-4846-8DD0-764CC4753D73}.Release|Win32.Build.0 =
Release|Win32
{BFE5409B-5B2B-4667-A91A-D5A5E7DC8A83}.Debug|Win32.ActiveCfg =
Debug|Win32
{BFE5409B-5B2B-4667-A91A-D5A5E7DC8A83}.Debug|Win32.Build.0 = Debug|
Win32
{BFE5409B-5B2B-4667-A91A-D5A5E7DC8A83}.Fast|Win32.ActiveCfg = Fast|
Win32
@@ -70,6 +62,14 @@
{DDDCEC02-9CCF-4178-9596-E00D6F71C083}.Product|Win32.Build.0 =
Release|Win32
{DDDCEC02-9CCF-4178-9596-E00D6F71C083}.Release|Win32.ActiveCfg =
Release|Win32
{DDDCEC02-9CCF-4178-9596-E00D6F71C083}.Release|Win32.Build.0 =
Release|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Debug|Win32.ActiveCfg =
Debug|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Debug|Win32.Build.0 = Debug|
Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Fast|Win32.ActiveCfg =
Release|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Fast|Win32.Build.0 = Release|
Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Product|Win32.ActiveCfg =
Release|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Product|Win32.Build.0 =
Release|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Release|Win32.ActiveCfg =
Release|Win32
+ {FD5B94F7-55C2-4C96-B89E-32DC1A737233}.Release|Win32.Build.0 =
Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

=== modified file 'build.win32/strongtalk/Makefile.win32'
--- build.win32/strongtalk/Makefile.win32 2008-05-29 00:55:59 +0000
+++ build.win32/strongtalk/Makefile.win32 2008-06-28 16:27:25 +0000
@@ -40,7 +40,7 @@
-@$(RMDIR) /s/q incls
@$(MKDIR) incls
@$(CP) $(DB1) +$(DB2) includeDB.all
- ..\build.win32\makedeps\debug\makedeps $(PLATFORM) includeDB.all
+ ..\tools\makedeps $(PLATFORM) includeDB.all
@$(MV) includeDB.all includeDB.current

# numbers:

=== modified file 'build.win32/strongtalk/makedeps.bat'
--- build.win32/strongtalk/makedeps.bat 2008-05-29 00:55:59 +0000
+++ build.win32/strongtalk/makedeps.bat 2008-06-28 17:01:34 +0000
@@ -1,2 +1,2 @@
@cd ..\..\build
-nmake /f ../build.win32/strongtalk/Makefile.win32
\ No newline at end of file
+nmake /nologo /f ../build.win32/strongtalk/Makefile.win32

=== modified file 'contributorLicenses.html'
--- contributorLicenses.html 2007-12-08 10:31:24 +0000
+++ contributorLicenses.html 2008-06-19 04:19:46 +0000
@@ -23,6 +23,7 @@
<li>Dave Raymer - dave....@gmail.com</li>
<li>Marc Fauconneau Dufresne - prune...@gmail.com</li>
<li>Stephen Rees - Stephe...@gmail.com</li>
+ <li>Brian de Alwis - briand...@gmail.com</li>
</ul>
</body>
</html>

=== modified file 'easyunit/easyunit/alloceasy.h'
--- easyunit/easyunit/alloceasy.h 2008-05-28 23:33:59 +0000
+++ easyunit/easyunit/alloceasy.h 2008-06-19 04:19:50 +0000
@@ -1,7 +1,9 @@
#ifndef _EASYUNIT_ALLOC_
#define _EASYUNIT_ALLOC_
#include <string.h>
+#ifndef __DARWIN__
#include <malloc.h>
+#endif
#include <stdlib.h>

namespace easyunit {

=== modified file 'tools/makedeps/makeDeps.cpp'
--- tools/makedeps/makeDeps.cpp 2008-05-28 23:33:59 +0000
+++ tools/makedeps/makeDeps.cpp 2008-06-19 04:19:51 +0000
@@ -313,7 +313,8 @@
public:
void setupFileTemplates() {
InclFileTemplate = new FileName( "incls/", "_", "", ".incl", "",
"");
- GIFileTemplate = new FileName( "incls/", "", "_precompiled",
".h", "", ".p");
+ //GIFileTemplate = new FileName( "incls/", "", "_precompiled",
".h", "", ".p");
+ GIFileTemplate = new FileName( "incls/", "", "_precompiled",
".incl", "", "");
GDFileTemplate = new FileName( "", "", "Dependencies.hh",
"", "", "");
}


=== modified file 'tools/makedeps/makedeps.vcproj'
--- tools/makedeps/makedeps.vcproj 2006-11-01 13:53:10 +0000
+++ tools/makedeps/makedeps.vcproj 2008-06-28 16:20:24 +0000
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="8.00"
+ Version="9.00"
Name="makedeps"
ProjectGUID="{FD5B94F7-55C2-4C96-B89E-32DC1A737233}"
+ TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
@@ -48,6 +49,8 @@
/>
<Tool
Name="VCLinkerTool"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
/>
<Tool
Name="VCALinkTool"
@@ -68,9 +71,6 @@
Name="VCAppVerifierTool"
/>
<Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
@@ -108,6 +108,8 @@
/>
<Tool
Name="VCLinkerTool"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
/>
<Tool
Name="VCALinkTool"
@@ -128,9 +130,6 @@
Name="VCAppVerifierTool"
/>
<Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
Name="VCPostBuildEventTool"
/>
</Configuration>

=== modified file 'vm/code/stubRoutines.cpp'
--- vm/code/stubRoutines.cpp 2008-01-15 00:22:13 +0000
+++ vm/code/stubRoutines.cpp 2008-06-19 04:20:34 +0000
=== modified file 'vm/deps/includeDB'
--- vm/deps/includeDB 2008-05-29 00:55:59 +0000
+++ vm/deps/includeDB 2008-06-19 04:19:51 +0000
@@ -948,6 +948,7 @@
oop_prims.cpp memOop.inline.hpp
oop_prims.cpp lookupCache.hpp
oop_prims.cpp delta.hpp
+oop_prims.cpp associationOop.hpp

oopFactory.cpp associationKlass.hpp
oopFactory.cpp oopFactory.hpp
@@ -967,11 +968,11 @@
os.hpp longInt.hpp

os.cpp no_precompiled_headers
+os.cpp os.hpp
os.cpp allocation.hpp
os.cpp error.hpp
os.cpp lprintf.hpp
os.cpp macros.hpp
-os.cpp os.hpp
os.cpp growableArray.hpp

ostream.hpp std_includes.hpp
@@ -1374,6 +1375,7 @@
timer.cpp os.hpp

timer.hpp top.hpp
+timer.hpp longInt.hpp

top.hpp asserts.hpp
top.hpp allocation.hpp

=== modified file 'vm/memory/error.cpp'
--- vm/memory/error.cpp 2006-10-26 16:36:34 +0000
+++ vm/memory/error.cpp 2008-06-19 04:19:51 +0000
@@ -69,7 +69,7 @@
}
}

-void report_assertion_failure(char* code_str, char* file_name, int
line_no, char* message) {
+void report_assertion_failure(const char* code_str, const char*
file_name, int line_no, const char* message) {
report_error("Assertion Failure", "assert(%s, \"%s\")\n%s, %d",
code_str, message, file_name, line_no);
}

=== modified file 'vm/memory/error.hpp'
--- vm/memory/error.hpp 2008-05-28 23:33:59 +0000
+++ vm/memory/error.hpp 2008-06-19 04:19:51 +0000
@@ -65,7 +65,7 @@
#define Unimplemented() { report_unimplemented
(FILE_INFO, LINE_INFO); DEBUG_EXCEPTION; }


-void report_assertion_failure(char* code_str, char* file_name, int
line_no, char* message);
+void report_assertion_failure(const char* code_str, const char*
file_name, int line_no, const char* message);
void report_fatal(char* file_name, int line_no, char* format, ...);
void report_should_not_call(char* file_name, int line_no);
void report_should_not_reach_here(char* file_name, int line_no);

=== modified file 'vm/prims/prim.cpp'
--- vm/prims/prim.cpp 2008-04-23 01:48:41 +0000
+++ vm/prims/prim.cpp 2008-06-19 04:19:52 +0000
@@ -47,6 +47,7 @@
oop primitive_desc::eval(oop* a) {
const bool reverseArgs = true; // change this when changing
primitive calling convention
oop res;
+#ifdef DEBUG_CHECK_EBX
int ebx_on_stack;

// %hack: see below
@@ -55,6 +56,7 @@
#else
asm("movl %%ebx, %0" : "=b"(ebx_on_stack));
#endif
+#endif
if (reverseArgs) {
switch (number_of_parameters()) {
case 0: res = ((prim_fntype0)_fn)(); break;
@@ -85,6 +87,7 @@
}
}

+#ifdef DEBUG_CHECK_EBX
// %hack: some primitives alter EBX and crash the compiler's
constant propagation
int ebx_now;
#ifndef __GNUC__
@@ -99,6 +102,7 @@
std->print_cr("ebx changed (%X -> %X) in :", ebx_on_stack,
ebx_now);
print();
}
+#endif

return res;
}

=== modified file 'vm/runtime/main.cpp'
--- vm/runtime/main.cpp 2008-05-28 23:33:59 +0000
+++ vm/runtime/main.cpp 2008-06-28 17:19:04 +0000
@@ -10,7 +10,7 @@
os::set_args(__argc, __argv);
return vm_main(__argc, __argv);
}
-#elif defined(__LINUX__) || defined(WIN32)
+#elif defined(__DARWIN__) || defined(__LINUX__) || defined(WIN32)
int main(int argc, char* argv[]) {
os::set_args(argc, argv);
return vm_main(argc, argv);

=== modified file 'vm/runtime/os.hpp'
--- vm/runtime/os.hpp 2008-04-23 01:48:41 +0000
+++ vm/runtime/os.hpp 2008-06-19 04:19:53 +0000
@@ -21,6 +21,8 @@

*/

+#ifndef __OS_HPP__
+#define __OS_HPP__
// os defines the interface to operating system

typedef void (*dll_func)(...);
@@ -127,3 +129,5 @@
ThreadCritical();
~ThreadCritical();
};
+
+#endif /* __OS_HPP__ */

=== added file 'vm/runtime/os_darwin.cpp'
--- vm/runtime/os_darwin.cpp 1970-01-01 00:00:00 +0000
+++ vm/runtime/os_darwin.cpp 2008-06-30 05:20:54 +0000
@@ -0,0 +1,690 @@
+/* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.50
$ */
+/* Copyright (c) 2006, Sun Microsystems, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the
+following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
with the distribution.
+ * Neither the name of Sun Microsystems nor the names of its
contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+
+
+*/
+#ifndef __OS_DARWIN__
+#define __OS_DARWIN__
+#ifdef __DARWIN__
+# include <pthread.h>
+# include <unistd.h>
+# include <semaphore.h>
+# include <sys/times.h>
+# include <sys/time.h>
+# include <time.h>
+# include <stdio.h>
+# include <dlfcn.h>
+# include <signal.h>
+# include <ucontext.h>
+# include "incls/_precompiled.incl"
+# include "incls/_os.cpp.incl"
+
+void os_dump_context2(ucontext_t *context) {
+#if 0
+ mcontext_t mcontext = context->uc_mcontext;
+ printf("\nEAX: %x", mcontext.gregs[REG_EAX]);
+ printf("\nEBX: %x", mcontext.gregs[REG_EBX]);
+ printf("\nECX: %x", mcontext.gregs[REG_ECX]);
+ printf("\nEDX: %x", mcontext.gregs[REG_EDX]);
+ printf("\nEIP: %x", mcontext.gregs[REG_EIP]);
+ printf("\nESP: %x", mcontext.gregs[REG_ESP]);
+ printf("\nEBP: %x", mcontext.gregs[REG_EBP]);
+ printf("\nEDI: %x", mcontext.gregs[REG_EDI]);
+ printf("\nESI: %x", mcontext.gregs[REG_ESI]);
+#endif
+}
+void os_dump_context() {
+ ucontext_t context;
+ getcontext(&context);
+ os_dump_context2(&context);
+}
+
+static int main_thread_id;
+class Lock {
+ private:
+ pthread_mutex_t* mutex;
+
+ public:
+ Lock(pthread_mutex_t* mutex) : mutex(mutex) {
+ pthread_mutex_lock(mutex);
+ }
+ ~Lock() {
+ pthread_mutex_unlock(mutex);
+ }
+};
+
+static int _argc;
+static char** _argv;
+
+int os::argc() {
+ return _argc;
+}
+
+char** os::argv() {
+ return _argv;
+}
+
+void os::set_args(int argc, char* argv[]) {
+ _argc = argc;
+ _argv = argv;
+}
+
+class Event: public CHeapObj {
+ private:
+ bool _signalled;
+ pthread_mutex_t mutex;
+ pthread_cond_t notifier;
+ public:
+ void inline signal() {
+ Lock mark(&mutex);
+ _signalled = true;
+ pthread_cond_signal(&notifier);
+ }
+ void inline reset() {
+ Lock mark(&mutex);
+ _signalled = false;
+ pthread_cond_signal(&notifier);
+ }
+ bool inline waitFor() {
+ Lock mark(&mutex);
+ while (!_signalled)
+ pthread_cond_wait(&notifier, &mutex);
+ }
+ Event(bool state) {
+ _signalled = state;
+ pthread_mutex_init(&mutex, NULL);
+ pthread_cond_init(&notifier, NULL);
+ }
+ ~Event() {
+ pthread_mutex_destroy(&mutex);
+ pthread_cond_destroy(&notifier);
+ }
+};
+
+class Thread : CHeapObj {
+ public:
+ static Thread* find(pthread_t threadId) {
+ for (int index = 0; index < _threads->length(); index++) {
+ Thread* candidate = _threads->at(index);
+ if (candidate == NULL) continue;
+ if (pthread_equal(threadId, candidate->_threadId))
+ return candidate;
+ }
+ return NULL;
+ }
+ void suspend() {
+ suspendEvent.waitFor();
+ }
+ void resume() {
+ suspendEvent.signal();
+ }
+ private:
+ Event suspendEvent;
+ static GrowableArray<Thread*>* _threads;
+ pthread_t _threadId;
+ int _thread_index;
+
+ static void init() {
+ ThreadCritical lock;
+ _threads = new(true) GrowableArray<Thread*>(10, true);
+
+ }
+ Thread(pthread_t threadId) : _threadId(threadId),
suspendEvent(false) {
+ ThreadCritical lock;
+ _thread_index = _threads->length();
+#if 0
+ pthread_getcpuclockid(_threadId, &_clockId);
+#endif
+ _threads->push(this);
+ };
+ ~Thread() {
+ ThreadCritical lock;
+ _threads->at_put(_thread_index, NULL);
+ }
+ double get_cpu_time() {
+#if 0
+ struct timespec cpu;
+ clock_gettime(_clockId, &cpu);
+ return ((double)cpu.tv_sec) + ((double)cpu.tv_nsec)/
1000000000.0;
+#else
+ return 0;
+#endif
+ }
+ friend class os;
+};
+
+GrowableArray<Thread*>* Thread::_threads = NULL;
+static Thread* main_thread;
+
+extern void intercept_for_single_step();
+
+// No references in VM
+int os::getenv(char* name,char* buffer,int len) {
+ return 0;
+}
+
+// 1 reference (lprintf.cpp)
+bool os::move_file(char* from, char* to) {
+ return false;
+}
+
+// 1 reference (inliningdb.cpp)
+bool os::check_directory(char* dir_name) {
+ return false;
+}
+
+// 1 reference (memory/util.cpp)
+void os::breakpoint() {
+}
+
+// 1 reference process.cpp
+Thread* os::starting_thread(int* id_addr) {
+ *id_addr = main_thread->_thread_index;
+ return main_thread;
+}
+
+typedef struct {
+ int (*main)(void* parameter);
+ void* parameter;
+} thread_args_t;
+
+void* mainWrapper(void* args) {
+ thread_args_t* wrapperArgs = (thread_args_t*) args;
+ int* result = (int*) malloc(sizeof(int));
+ *result = wrapperArgs->main(wrapperArgs->parameter);
+ free(args);
+ return (void *) result;
+}
+
+// 1 reference process.cpp
+Thread* os::create_thread(int threadStart(void* parameter), void*
parameter, int* id_addr) {
+ pthread_t threadId;
+ thread_args_t* threadArgs = (thread_args_t*)
malloc(sizeof(thread_args_t));
+ threadArgs->main = threadStart;
+ threadArgs->parameter = parameter;
+ int status = pthread_create(&threadId, NULL, &mainWrapper,
threadArgs);
+ if (status != 0) {
+ fatal("Unable to create thread");
+ }
+ Thread* thread = new Thread(threadId);
+ *id_addr = thread->_thread_index;
+ return thread;
+}
+
+// 1 reference process.cpp
+void os::terminate_thread(Thread* thread) {
+}
+
+// 1 reference process.cpp
+void os::delete_event(Event* event) {
+ delete event;
+}
+
+// 1 reference process.cpp
+Event* os::create_event(bool initial_state) {
+ return new Event(initial_state);
+}
+
+tms processTimes;
+
+// 2 references - prims/system_prims.cpp, timer.cpp
+int os::updateTimes() {
+ return times(&processTimes) != (clock_t) -1;
+}
+
+// 2 references - prims/system_prims.cpp, timer.cpp
+double os::userTime() {
+ return ((double) processTimes.tms_utime)/ CLOCKS_PER_SEC;
+}
+
+// 2 references - prims/system_prims.cpp, timer.cpp
+double os::systemTime() {
+ return ((double) processTimes.tms_stime)/ CLOCKS_PER_SEC;
+}
+
+// 1 reference - process.cpp
+double os::user_time_for(Thread* thread) {
+ //Hack warning - assume half time is spent in kernel, half in user
code
+ return thread->get_cpu_time()/2;
+}
+
+// 1 reference - process.cpp
+double os::system_time_for(Thread* thread) {
+ //Hack warning - assume half time is spent in kernel, half in user
code
+ return thread->get_cpu_time()/2;
+}
+
+static int has_performance_count = 0;
+static long_int initial_performance_count(0,0);
+static long_int performance_frequency(0,0);
+
+// 2 references - memory/error.cpp, evaluator.cpp
+void os::fatalExit(int num) {
+ exit(num);
+}
+
+class DLLLoadError {
+};
+
+class DLL : CHeapObj {
+ private:
+ char* _name;
+ void* _handle;
+
+ DLL(char* name) {
+ _handle = dlopen(name, RTLD_LAZY);
+ checkHandle(_handle, "could not find library: %s");
+ _name = (char*)malloc(strlen(name) + 1);
+ strcpy(_name, name);
+ }
+ void checkHandle(void* handle, const char* format) {
+ if (handle == NULL) {
+ char* message = (char*) malloc(200);
+ sprintf(message, format, dlerror());
+ assert(handle != NULL, message);
+ free(message);
+ }
+ }
+ ~DLL() {
+ if (_handle) dlclose(_handle);
+ if (_name) free(_name);
+ }
+ bool isValid() {
+ return (_handle != NULL) && (_name != NULL);
+ }
+ dll_func lookup(char* funcname) {
+ dll_func function = dll_func(dlsym(_handle, funcname));
+ checkHandle((void*) function, "could not find function: %s");
+ return function;
+ }
+ friend class os;
+};
+
+// 1 reference - prims/dll.cpp
+dll_func os::dll_lookup(char* name, DLL* library) {
+ return library->lookup(name);
+}
+
+// 1 reference - prims/dll.cpp
+DLL* os::dll_load(char* name) {
+ DLL* library = new DLL(name);
+ if (library->isValid()) return library;
+ delete library;
+ return NULL;
+}
+
+// 1 reference - prims/dll.cpp
+bool os::dll_unload(DLL* library) {
+ delete library;
+ return true;
+}
+
+int nCmdShow = 0;
+
+// 1 reference - prims/system_prims.cpp
+void* os::get_hInstance() { return (void*) NULL; }
+// 1 reference - prims/system_prims.cpp
+void* os::get_prevInstance() { return (void*) NULL; }
+// 1 reference - prims/system_prims.cpp
+int os::get_nCmdShow() { return 0; }
+
+extern int bootstrapping;
+
+// 1 reference - prims/debug_prims.cpp
+void os::timerStart() {}
+
+// 1 reference - prims/debug_prims.cpp
+void os::timerStop() {}
+
+// 1 reference - prims/debug_prims.cpp
+void os::timerPrintBuffer() {}
+
+// Virtual Memory
+class Allocations {
+ private:
+ int allocationSize;
+ char** allocations;
+ char** reallocBoundary;
+ char** next;
+ bool released;
+
+ void checkCapacity() {
+ if (next == reallocBoundary) {
+ reallocate();
+ }
+ }
+ void reallocate() {
+ char** oldAllocations = allocations;
+ int oldSize = allocationSize;
+ allocationSize *= 2;
+ allocations = (char**)malloc(sizeof(char*) * allocationSize);
+ memcpy(allocations, oldAllocations, oldSize * sizeof(char*));
+ next = allocations + oldSize;
+ reallocBoundary = allocations + allocationSize;
+ free(oldAllocations);
+ }
+ void initialize() {
+ allocationSize = 10;
+ allocations = (char**)malloc(sizeof(char*) * allocationSize);
+ reallocBoundary = allocations + allocationSize;
+ next = allocations;
+ }
+ void release() {
+ if (released) return;
+ for (char** current = allocations; current < next; current++)
+ free(*current);
+ free(allocations);
+ allocations = next = reallocBoundary = NULL;
+ released = true;
+ }
+ public:
+ Allocations() {
+ initialize();
+ }
+ ~Allocations() {
+ release();
+ }
+ void remove(char* allocation) {
+ if (released) return;
+ for (char** current = allocations; current < next; current++)
+ if (*current == allocation) {
+ for (char** to_move = current; to_move < next; to_move++)
+ to_move[0] = to_move[1];
+ next--;
+ return;
+ }
+ }
+ void add(char* allocation) {
+ if (released) return;
+ checkCapacity();
+ *next = allocation;
+ next++;
+ }
+ bool contains(char* allocation) {
+ if (released) return false;
+ for (char** current = allocations; current < (allocations +
allocationSize); current++)
+ if (*current == allocation) return true;
+ return false;
+ }
+};
+
+Allocations allocations;
+
+// 1 reference - virtualspace.cpp
+char* os::reserve_memory(int size) {
+ ThreadCritical tc;
+ char* allocation = (char*) valloc(size);
+ allocations.add(allocation);
+ return allocation;
+}
+
+// 1 reference - virtualspace.cpp
+bool os::commit_memory(char* addr, int size) {
+ return true;
+}
+
+// 1 reference - virtualspace.cpp
+bool os::uncommit_memory(char* addr, int size) {
+ return true;
+}
+
+// 1 reference - virtualspace.cpp
+bool os::release_memory(char* addr, int size) {
+ ThreadCritical tc;
+ if (allocations.contains(addr)) {
+ allocations.remove(addr);
+ free(addr);
+ }
+ return true;
+}
+
+// No references
+bool os::guard_memory(char* addr, int size) {
+ return false;
+}
+
+// 1 reference - process.cpp
+void os::transfer(Thread* from_thread, Event* from_event, Thread*
to_thread, Event* to_event) {
+ from_event->reset();
+ to_event->signal();
+ from_event->waitFor();
+}
+
+// 1 reference - process.cpp
+void os::transfer_and_continue(Thread* from_thread, Event*
from_event, Thread* to_thread, Event* to_event) {
+ from_event->reset();
+ to_event->signal();
+}
+
+// 1 reference - process.cpp
+void os::suspend_thread(Thread* thread) {
+ os_dump_context();
+ pthread_kill(thread->_threadId, SIGUSR1);
+}
+
+void suspendHandler(int signum) {
+ Thread* current = Thread::find(pthread_self());
+ assert(current, "Suspended thread not found!");
+ current->suspend();
+}
+// 1 reference - process.cpp
+void os::resume_thread(Thread* thread) {
+ thread->resume();
+}
+
+// No references
+void os::sleep(int ms) {
+}
+
+// 1 reference - process.cpp
+void os::fetch_top_frame(Thread* thread, int** sp, int** fp, char**
pc) {
+}
+
+// 1 reference - callBack.cpp
+int os::current_thread_id() {
+ Thread* currentThread = Thread::find(pthread_self());
+ if (currentThread == NULL) return -1;
+ return currentThread->_thread_index;
+}
+
+// 1 reference - process.cpp
+void os::wait_for_event(Event* event) {
+ event->waitFor();
+}
+
+// 1 reference - process.cpp
+void os::reset_event(Event* event) {
+ event->reset();
+}
+
+// 1 reference - process.cpp
+void os::signal_event(Event* event) {
+ event->signal();
+}
+
+// 1 reference - process.cpp
+bool os::wait_for_event_or_timer(Event* event, int timeout_in_ms) {
+ return false;
+}
+
+extern "C" bool WizardMode;
+
+void process_settings_file(char* file_name, bool quiet);
+
+static int number_of_ctrl_c = 0;
+
+// 2 references - memory/universe, runtime/virtualspace
+int os::_vm_page_size = getpagesize();
+
+// 1 reference - timer.cpp
+long_int os::elapsed_counter() {
+#if 0
+ struct timespec current_time;
+ clock_gettime(CLOCK_REALTIME, &current_time);
+ int64_t current64 = ((int64_t)current_time.tv_sec) * 1000000000 +
current_time.tv_nsec;
+#else
+ struct timeval current_time;
+ gettimeofday(&current_time, NULL);
+ int64_t current64 = ((int64_t)current_time.tv_sec) * 1000000000
+ + current_time.tv_usec * 1000;
+#endif
+ uint high = current64 >> 32;
+ uint low = current64 & 0xffffffff;
+ long_int current(low, high);
+ return current;
+}
+
+// 1 reference - timer.cpp
+long_int os::elapsed_frequency() {
+ return long_int(1000000000, 0);
+}
+
+static struct timespec initial_time;
+
+// 1 reference - prims/system_prims.cpp
+double os::elapsedTime() {
+#if 0
+ struct timespec current_time;
+ clock_gettime(CLOCK_REALTIME, &current_time);
+ long int secs = current_time.tv_sec - initial_time.tv_sec;
+ long int nsecs = current_time.tv_nsec - initial_time.tv_nsec;
+ if (nsecs < 0) {
+ secs--;
+ nsecs += 1000000000;
+ }
+ return secs + (nsecs / 1000000000.0);
+#else
+ return 0.0;
+#endif
+}
+
+// No references
+double os::currentTime() {
+ return 0;
+}
+
+static void initialize_performance_counter() {
+#if 0
+ clock_gettime(CLOCK_REALTIME, &initial_time);
+#endif
+}
+
+// No references
+void os::initialize_system_info() {
+ Thread::init();
+ main_thread = new Thread(pthread_self());
+ initialize_performance_counter();
+}
+
+// 1 reference - memory/error.cpp
+int os::message_box(char* title, char* message) {
+ return 0;
+}
+
+char* os::platform_class_name() { return "DarwinPlatform"; }
+
+extern "C" bool EnableTasks;
+
+pthread_mutex_t ThreadSection;
+
+void ThreadCritical::intialize() { pthread_mutex_init(&ThreadSection,
NULL); }
+void ThreadCritical::release()
{ pthread_mutex_destroy(&ThreadSection); }
+
+ThreadCritical::ThreadCritical() {
+ pthread_mutex_lock(&ThreadSection);
+}
+
+ThreadCritical::~ThreadCritical() {
+ pthread_mutex_unlock(&ThreadSection);
+}
+
+void real_time_tick(int delay_time);
+
+void* watcherMain(void* ignored) {
+ const struct timespec delay = { 0, 10 * 1000 * 1000 };
+ const int delay_interval = 10; // Delay 10 ms
+ while(1) {
+ int status = nanosleep(&delay, NULL);
+ if (!status) return 0;
+ real_time_tick(delay_interval);
+ }
+ return 0;
+}
+
+void segv_repeated(int signum, siginfo_t* info, void* context) {
+ printf("SEGV during signal handling. Aborting.");
+ exit(-2);
+}
+
+void install_dummy_handler() {
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART |SA_SIGINFO;
+ sa.sa_sigaction = segv_repeated;
+ if (sigaction(SIGSEGV, &sa, NULL) == -1)
+ /* Handle error */;
+}
+
+void trace_stack(int thread_id);
+
+static void handler(int signum, siginfo_t* info, void* context) {
+// install_dummy_handler();
+// trace_stack(os::current_thread_id());
+ printf("\nsignal: %d\ninfo: %x\ncontext: %x", signum, (int) info,
(int) context);
+ os_dump_context2((ucontext_t*) context);
+ exit(-1);
+}
+
+void install_signal_handlers() {
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART; /* Restart functions if
+ interrupted by handler */
+ sa.sa_handler = suspendHandler;
+ if (sigaction(SIGUSR1, &sa, NULL) == -1)
+ /* Handle error */;
+ sa.sa_flags |= SA_SIGINFO;
+ sa.sa_sigaction = handler;
+ if (sigaction(SIGSEGV, &sa, NULL) == -1)
+ /* Handle error */;
+}
+
+void os_init() {
+ ThreadCritical::intialize();
+
+ install_signal_handlers();
+ os::initialize_system_info();
+
+ if (EnableTasks) {
+ pthread_t watcherThread;
+ int status = pthread_create(&watcherThread, NULL, &watcherMain,
NULL);
+ if (status != 0) {
+ fatal("Unable to create thread");
+ }
+ }
+}
+
+void os_exit() {
+ ThreadCritical::release();
+}
+#endif /* __DARWIN__ */
+#endif

=== modified file 'vm/topIncludes/types.hpp'
--- vm/topIncludes/types.hpp 2007-11-12 22:26:32 +0000
+++ vm/topIncludes/types.hpp 2008-06-19 04:19:53 +0000
@@ -34,6 +34,7 @@
// most portable way of dealing with bools is to treat them as ints;
// the new basic bool type isn't goodness.
typedef int _bool_type_;
+#undef bool
#define bool _bool_type_

typedef int smi;


Brian de Alwis

unread,
Jul 1, 2008, 1:52:31 AM7/1/08
to Strongtalk-general
On Jun 30, 7:42 pm, Colin Putney <cput...@wiresong.ca> wrote:
> Shouldn't be too difficult. I'm not a VM hacker, but if you guys get  
> Strongtalk running on Darwin, I can port Monticello.

That would be cool. I took a quick gander at the Monticello2 package
on source.wiresong.ca/mc, and the fileins make reference to Squeak
classes like Notification.

Colin Putney

unread,
Jul 1, 2008, 2:10:27 AM7/1/08
to strongtal...@googlegroups.com

Yes, there are bound to be quite a few Squeakisms in the code. I'm
currently working on a port to Gemstone, which is helping to identify
and isolate them, but Gemstone has quite a bit of the Squeak
environment present, since several packages of Squeak origin have
already been ported.

Usually, porting Squeak code to another Smalltalk involves porting
parts of the Squeak libraries as well. With Strongtalk we have an
opportunity to go the other way as well, since the Strongtalk license
is compatible with the licenses of Monticello and Squeak.

Colin

talksmall

unread,
Jul 1, 2008, 4:02:17 AM7/1/08
to Strongtalk-general
Actually Notification is an ANSI Smalltalk class, so it's included in
my exceptions filein.

Regards, Steve

talksmall

unread,
Jul 1, 2008, 4:24:31 AM7/1/08
to Strongtalk-general
The SUnit code I ported over from CampSmalltalk was the Squeak
version. There were a number of issues (not least the differences in
filein formats), but non was insurmountable. The biggest obstacle was
the TestRunner. Obviously none of the Squeak UI framework classes was
present so this had to be largely rewritten.

Of course SUnit is a much smaller codebase, and I would expect more
issues from a Monticello port. The Strongtalk Smalltalk code is
relatively sparse in the protocol that it supports. I haven't done a
comprehensive comparison against ANSI, but you can expect quite a few
methods that you think should be there to be missing. Not a major
problem most of the time, 'cos we can just implement them. Just
something to be aware of. Any reflection stuff in particular is highly
likely to differ. Strongtalk uses Mirrors to perform reflection
(geddit?). This means no instVarAt: (for one thing), which is a
violation of encapsulation anyway, and a number of other capabilities
are embedded in the Mirror hierarchy somewhere. Performs are supported
though.

Getting a usable environment on Darwin might be tricky though. The
critical step will be the UI implementation. I've tried developing
without a UI via a text editor and fileins, and it's no fun. For the
time being I would recommend holding one's nose and doing Smalltalk
development in Windows.

Regards, Steve

Colin Putney

unread,
Jul 1, 2008, 4:52:07 AM7/1/08
to strongtal...@googlegroups.com

On 1-Jul-08, at 1:24 AM, talksmall wrote:

> Getting a usable environment on Darwin might be tricky though. The
> critical step will be the UI implementation. I've tried developing
> without a UI via a text editor and fileins, and it's no fun. For the
> time being I would recommend holding one's nose and doing Smalltalk
> development in Windows.


The Monticello 2 UI is based on OmniBrowser, which supports remote
interfaces. So getting at least basic tools and versioning wouldn't
require native widgets, just socket support and maybe a web server.
I'm busy with the Gemstone port at the moment, but when that's done,
I'll see what it would take to support Strongtalk as well.

Colin

talksmall

unread,
Jul 1, 2008, 5:52:08 AM7/1/08
to Strongtalk-general
Colin,
I wasn't so much thinking of the Monticello UI, but of the development
environment generally. Even once Brian has basic file level support
running, none of the UI will work, so the only way to update the image
would be to file in code using the scripting interface and save the
image. This is not a very productive environment to work in. I tried
it for the first part of my ANSI exceptions development, but then I'm
a bit of a masochist ;). It gets old pretty quickly and I wouldn't
really recommend it.

Regards, Steve

talksmall

unread,
Jul 1, 2008, 5:57:28 PM7/1/08
to Strongtalk-general
Brian,
I tried to extract your patch from the email, but Google mangled lots
of stuff and it's a real pain to sort out. Is there any chance you can
stick it on sendspace, or something similar?

Regards, Steve

talksmall

unread,
Jul 2, 2008, 5:54:37 AM7/2/08
to Strongtalk-general
Brian,
I hand patched the C++ files from patch you attached and applied them
to a fresh checkout from SVN.

Actually, I didn't apply all of your C++ changes. In particular, I
kept the makedeps/makedeps.cpp version. It has some changes that I
applied, in particular to get precompiled headers working with the
Linux build. I agree that it doesn't make sense to have two versions
of the same code. I'd actually forgotten about the version under
tools. If we are going to remove one (and I agree we should) I'd
prefer to remove the one under tools. In any case, I applied your
modification to my version, even though it won't affect the Win32
compile.

Although for me the changes to includeDB and the header files are not
necessary, I applied them anyway.

I can see two problems when I try recompile world.

1. With compilation turned on I get a compilation failure at certain
points - it seems to vary exactly which method is affected. I've
already got this one on my list of todos, but I haven't got round to
it yet. The brings up a StackTraceInspector on the compile all
process. This leads to the second problem.

2. With the 16-byte alignment patch in place I get an access violation
if I try to click on something in the stack trace. This is probably
because the primitive that generates the Activations for the stack
frames doesn't understand about the 16-byte alignment yet. Commenting
out the 16-byte alignment patch fixes this issue.

If I turn off recompilation (by setting -UseRecompilation in the
strongtalkrc file; this refers to generation of native code from
compiled bytecode, rather than recompilation of Smalltalk source into
bytecode), recompile world completes without a problem, even with the
16-byte alignment patch in place.

Regards, Steve
Reply all
Reply to author
Forward
0 new messages