Re: Embedding assembler in a language



"Robbert Haarman" <comp.lang.misc@xxxxxxxxxxxxx> wrote in message
news:20091121232416.GB3429@xxxxxxxxxxxxxxxxxxxxx

On Sat, Nov 21, 2009 at 10:39:51PM +0000, bartc wrote:

I liked also the comment that threaded code is not really practical
in a high level language without 'first class labels', ie. indirect
labels. Apparently only some versions of gcc have this (which I
tried once but that wasn't quite enough for me).

gcc calls this "computed gotos".

I wonder in what sense they were "not quite enough" for you,

(Background: I had to choose between staying with my own compiled language,
which was generally old, slow, buggy, and crappy, but familiar and cosy (and had inline Nasm assembler!), and switching to C. )

As I understood how these gotos worked, the labels had to be in the same function. Since I had several hundred handlers, I wanted to have each one in it's own function. Trying to set up functions with no local params/variables and therefore no prolog code, and using the function address as the label, didn't work.

Maybe there were ways of doing that (one label per function, jumping
somewhere into the start of it), but I didn't spend too long on it. I'd also
planned on making use of the hardware stack and hardware frame pointer, but
that seemed awkward without using assembler. And if I was going to use gcc's
awful assembler syntax, I'd rather stay with my own language!

and if the
primitives offered by Voodoo would be more useful to you (in Voodoo, goto
works with any value you care to give it, be it a label, the value of
some variable, or even a plain integer).

You'll need to explain again where Voodoo might fit in to the model of
compiled language+assembler being used to implement an interpreter. Or
perhaps it is a target language to take the place of bytecode.

Unfortunately my language has quite a rich type-system so it has
other challenges than just dispatch, which I've got down to about a
2-instruction overhead.

Could you elaborate on that? What kind of dispatch are you doing, and
how are you doing it?

The opcode dispatch is straightforward: each bytecode instruction, once
fixed up in memory, is really a 32-bit function address, followed by 0 to 4
32-bit words of operands. I use a dedicated register EBX which holds the
program counter.

Dispatching after each opcode has finished, is something like:

add ebx,N
jmp [ebx]

(although I found that mov eax,[ebx]; jump eax was faster; but x86 is full
of strange things like that)

The execution model is, mostly, a stack machine, and manipulates variant
types, which are 12-byte values. These are pushed onto the normal stack
using ESP. And EBP is used for frame variables of the interpreted language.

The opcode handlers are functions, but defined with no params nor local
variables, so that I can jump straight into the start (and jump to the next
at the end). This way ESP/EBP still point to the interpreter's data, and
most handlers use inline assembler. To execute normal high level code, I
need to explicitly save EBX, and any operand pointers first.

The type system is complex, but manages to use a single small integer to represent
the type of a variant. For single operand codes, this is then used to index a jump table to get to the specific handler. For dual operand codes, the two codes have to be converted to a single linear value, then again a jump table is used. (For non-critical codes then just switch/case might be used.)

(However, while mainly dynamic, static typing hints can be used to avoid
this second dispatch. This might be considered a cheat..)

Also, not all instructions are created equal. In response to an earlier
thread started by cr, I wrote a little interpreter for a very very small
subset of the IA32 instruction set, and was surprised that the test
program I used took only 3 times as long in the interpreter than on
the real hardware. But that's for the loop instruction, which does
quite a lot of work and is easy to decode.

That's pretty good. I managed only 15x slowdown (on sub ebx,1; jnz l1)
during BGB's thread on his x86 interpreter (although I still didn't get the
need for such a thing).

Forth, from the little I remember about
(together with Euphoria, another fast one) was far simpler.

Yes. The reason there are so many variants of threaded code for Forth
is that you actually can implement most of the language constructs
without having to do any parsing. And Forth being typeless, you don't
have to write dispatching code for types, either.

It doesn't sound like a fun language to program though; I quite like my
types.

--
Bartc

.



Relevant Pages

  • Re: Wild Hair scheme #17
    ... no mysterious missing labels. ... if you translate the CCP assembler sources with a macro processor to ... some other language target, ... modifying code in vulnerable functions, to make it a lot harder to ...
    (comp.os.cpm)
  • Re: Wild Hair scheme #17
    ... applications -- even the CCP itself -- must follow the rules. ... But the rules are known, the addresses don't change, and therefore there are no mysterious missing labels. ... First, I never intended to imply that I'd translate the assembler language source to a new target CPU, using source that had no labels. ... We're not talking about an employer's programming style rules or rules about cleanliness of the desktop. ...
    (comp.os.cpm)
  • Re: Embedding assembler in a language
    ... in a high level language without 'first class labels', ... I had to choose between staying with my own compiled language, ... primitives offered by Voodoo would be more useful to you (in Voodoo, ... What kind of dispatch are you doing, ...
    (comp.lang.misc)
  • Re: mail merge wont print
    ... I have a Word document set up with merge codes, ... "Peter Jamieson" wrote: ... "propagate labels". ... You should be able to print that, or attach it. ...
    (microsoft.public.word.mailmerge.fields)
  • Re: Taking Ownership
    ... > have been able to determine is that the user id has the appropriate rights ... ostensibly on the language itself. ... When a function fails (and only if it ... fails so you need to check return codes or look at the EAX register if you ...
    (microsoft.public.dotnet.languages.vc)