ForthHub / discussion

Discussion repository for Forth enthusiasts.
116 stars 4 forks source link

Which Forth-systems can handle hardware exceptions? #57

Open ruv opened 6 years ago

ruv commented 6 years ago

More precise, the fist question is which the open source 64bit Forth-systems can handle hardware exceptions?

bnoordhuis commented 6 years ago

Can you be more specific? What kind of hardware exceptions are you talking about and in what context? x86_64 in ring 0?

ruv commented 6 years ago

I mean exceptions in the user space, for example — integer division by zero, memory access violation, etc. By handling I mean that CATCH can catch such exceptions.

bnoordhuis commented 6 years ago

Gforth does. It catches some UNIX signals and turns them into exceptions. See the manual and engine/signals.c.

ruv commented 6 years ago

Yes, Gforth does it — in the version for Linux at least. But seemingly it doesn't work in the version for Windows.

Hope we will get all such Forth-systems to compose the list.

MitchBradley commented 6 years ago

Pretty much every Forth system I have ever done - Forthmacs, Sun Forth, CForth, Open Firmware - has been able to handle hardware exceptions. In some cases, the complete state can be made visible so it is possible to inspect it from Forth, modify things like register values, and then resume from the saved/modified state - so Forth can debug its own assembly language. In other cases, the best you can do is return to Forth.

The complete capability can be very difficult to implement under operating systems, which rarely provide a documented (or stable across versions) way to get at the saved state vector. With great effort, I have succeeded in some cases, but it tends to be fragile and difficult to maintain. On a bare machine, where Forth is the operating system, it is much easier, since the exception state is documented as part of the instruction set architecture.

ruv commented 6 years ago

In CForth 123 0 ' / catch . and 0 ' @ catch . don't print ior number. Apparently, CForth doesn't transform hardware exception into Forth's THROW — see signal_handler in main.c.

MitchBradley commented 6 years ago

I'm not convinced that making hardware exceptions do a THROW is the right thing. It opens up the possibility of THROW from code that does not explicitly contain instances of THROW, ABORT, or ABORT" .

I am aware that some people disagree, and I know of Forth systems that do fold hardware exceptions into the CATCH / THROW framework.

In the specific case of divide-by-zero, it would be easy enough to add an explicit check for zero divisor in the division words, with gotos to the throw code. Other exceptions would require moving the sigsetjmp() from main() (which is used in OS-hosted CForth builds, but often omitted in standalone/bare-metal/embedded builds) into forth.c, thus adding a system library dependency. If you wish to try that change, I will consider a patch.

AntonErtl commented 6 years ago

On Sun, Feb 04, 2018 at 03:51:09AM +0000, Mitch Bradley wrote:

I'm not convinced that making hardware exceptions do a THROW is the right thing. It opens up the possibility of THROW from code that does not explicitly contain instances of THROW, ABORT, or ABORT" .

Yes. And the problem is?

There were some languages that required declaring all exceptions that could be thrown, but even my collegue who is very much into static checking does not think that is a good idea. E.g., Java has both checked exceptions that need to be declared, and unchecked exceptions that do not need to be declared, so Java code may get an exception that is not declared (and the throw is not visible to the code that receives it, given that Java has separate compilation).

And standard Forth has throw codes for stuff like "Invalid memory access" and "Address alignment exception", and "User Interrupt" which are perfect for events without explicit THROW.

In the specific case of divide-by-zero, it would be easy enough to add an explicit check for zero divisor in the division words, with gotos to the throw code.

That's appropriate when the hardware does not check it. But when the hardware does, why add this overhead?