HELP: How to write a function pointer to memory?

BlitzMax Forums/BlitzMax Beginners Area/HELP: How to write a function pointer to memory?

ImaginaryHuman(Posted 2004) [#1]
Hi folks.

I'm trying to put a function pointer in memory at a given address. The code I'm trying to use to do this is a slight rework of code taken from BlitzMax's PokeInt command. However, it doesn't compile and complains of some problem not being able to convert types. I can't figure out what's wrong with it? Can you help?

myfuncitonsbuf is an address in memory - a byte pointer
offset is an offset in bytes from that base address - an integer
funct1() is previously defined as a function - a function pointer

(Int Ptr(myfunctionsbuf+offset))[0]=Int(funct1) ' Something wrong with this line

I haven't used type casting much so I am a bit confused.

Please don't evaluate whether or not I should be trying to do this, I DO need to do it this way, I just need to know how to make it work. Thanks.

I wondered if maybe it's a problem because the base address of the buffer is a byte pointer and should be an integer? Or maybe I am changing to the wrong types?

Thanks for your help.


Dreamora(Posted 2004) [#2]
Compile Error:Unable to convert from 'Int()' to 'Int'

looks to me like functionpointers can only be saved into something that holds function pointers not into "banks"


Robert(Posted 2004) [#3]
I have found a way of doing it, but it isn't very neat. It basically involves placing the function pointer inside a type:


Type TrigFunctionContainer
	Field trigFunction:Double(x:Double) 
End Type

Local containerBank:TBank=CreateBank(SizeOf(TrigFunctionContainer)*3)

Local trigSin:TrigFunctionContainer = New TrigFunctionContainer
Local trigCos:TrigFunctionContainer = New TrigFunctionContainer
Local trigTan:TrigFunctionContainer = New TrigFunctionContainer

trigSin.trigFunction=Sin
trigCos.trigFunction=Cos
trigTan.trigFunction=tan

PokeInt(containerBank,0,Int(Varptr(trigSin)))
PokeInt(containerBank,4,Int(Varptr(trigCos)))
PokeInt(containerBank,8,Int(Varptr(trigTan)))

'Test that it is working:

Local func:Double(x:Double)

func=TrigFunctionContainer((Object Ptr(PeekInt(containerBank,0)))[0]).trigFunction

'These statements should print the same result
Print func(120)
Print Sin(120)



Robert(Posted 2004) [#4]
I need to explain this line a little:

func=TrigFunctionContainer((Object Ptr(PeekInt(containerBank,0)))[0]).trigFunction


The int is first converted to an object pointer, and then dereferenced using [0] to give an object. Because all custom types are derived from Object, this object can be casted to a TrigFunctionContainer, and we can access the trigFunction field to get the function pointer. Whew!


ImaginaryHuman(Posted 2004) [#5]
Hmm, if that works that's certainly a clever effort. I don't know if it's going to be as fast as I was hoping, but at least if it works I can use it for some of the functionality I was hoping for. Thanks!

You know what, it almost looks as though an array of function pointers might end up being faster than this. Hmm. Something like arr[i]=func to store the function pointers and arr[i]() to call them looks like being a lot simpler and faster. I was hoping to access a bank directly and quickly for optimium speed but if it involves a lot of extra stuff it isn't going to be worth it.

I wonder if something like

For i=0 to 9
   myfunctions[i]()   'or myfunctions[i]
Next


would compile down to some kind of optimized form that keeps the array base pointer in a register to be used by each call, instead of re-loading it each time? Oh .. I guess I could say:

Local myfunctions(param:int)[10]
For Local i:int=0 to 9
   myfunctions[i](myparam)
Next i

'or I could even unroll the loop?

Local myfunctions(param:int)[50]
For Local i:int=0 to 49 step 10
   myfunctions[i](myparam)
   myfunctions[i+1](myparam)
   mufunctions[i+2](myparam)
   'etc...+3 +4 +5 +6 +7 +8 +9
next

Would that be faster? I'm just trying to eliminate as much overhead as possible.

Thanks again.


ImaginaryHuman(Posted 2004) [#6]
Would it be faster to unroll a loop like that, even though it probably means that +1, +2, +3 etc need to be stored as immediate data in machine code, rather than using a single variable that increments? At least there would be less `loop overhead`.:????


ImaginaryHuman(Posted 2004) [#7]
I'm still wishing this whole thing would work with labels so that I can use Goto somehow, removing even the overhead of function calls. Hmm. Gotta rethink this.


Robert(Posted 2004) [#8]
You know what, it almost looks as though an array of function pointers might end up being faster than this. Hmm. Something like arr[i]=func to store the function pointers and arr[i]() to call them looks like being a lot simpler and faster. I was hoping to access a bank directly and quickly for optimium speed but if it involves a lot of extra stuff it isn't going to be worth it.


The overhead in calling a function pointer is absolutely minimal compared with any graphics rendering your program might be doing or maths calculations.


ImaginaryHuman(Posted 2004) [#9]
Unless I'm doing thousands of function calls. Those little delays add up.