Reputation: 161
I'm making some kind of interpreter and I'm computing a static const jump table thanks to local label addresses.
You know the drill,
static const int JUMP_TABLE[] = { &&case0 - &&case0, &&case1 - &&case0
and so on.
For various reasons, mostly performance, I'd like to copy/compress this table in an object during init.
I'm hurting my head against the wall because I can't figure how to escape the lexical scoping of the function !
How can I somehow reference &&case0 from another function ?
Does somebody have a good trick for this ?
Thanks in advance
Upvotes: 7
Views: 932
Reputation: 186
Sometimes Goto is simply the best solution. Tho very rare. Its still part of c++ after many years for a good reason
So what i did was create a global bool and set it after I initialize my address array. So the first time my interpreter function is called, it loads a structure of addresses so everything is within the same function.
Then with a little study of the assemblers output i was able to save a few ticks by arranging my code as follows.
if(is_initialized) .. ex command else ... initialize stuff. Goto ex command
use a goto to jump back to the top and execute the command. My interpreter is using almost 200 commands.
With a switch statement it was taking 5-1100 ticks. Depending on how far down the list the command was
Using goto functions[command] has it down to 14 regardless of where the command is in the list
This provides a method that is purely c++ but not supported on all compilers
Upvotes: 0
Reputation: 21916
I'm not aware of ways to achieve this within pure GNU C so approaches below use other mechanisms.
You can compile your object file twice, collecting offsets on the first run and using them on the second. For example
int foo(int x) {
#ifdef GENERATE_ADDRESSES
static __attribute__((section(".foo_offsets"))) unsigned offsets[] = { &&case0 - &&case0, &&case1 - &&case0 };
#endif
switch (x) {
case0:
case 0:
return 1;
case1:
case 1:
return 2;
}
return 0;
}
Now you can compile, extract bytes from .foo_offsets
section and embed them to you app on second run
$ gcc tmp.c -c -DGENERATE_ADDRESSES
$ objcopy -j .foo_offsets -O binary tmp.o
$ xxd -i tmp.o | tee offsets.inc
unsigned char tmp_o[] = {
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00
};
unsigned int tmp_o_len = 8;
You can use inline assembly to globalize labels:
extern char foo_case0[];
extern char foo_case1[];
const void *foo_addresses[] = { &foo_case0[0], &foo_case1[0] };
int foo(int x) {
switch (x) {
case 0:
asm("foo_case0:");
return 1;
case 1:
asm("foo_case1:");
return 2;
}
return 0;
}
Unfortunately in this case you can only collect addresses (not offsets) so you'll need to manually compute offsets at startup.
Upvotes: 5