I can confirm that it works. I changed your DOL program to output
debug messages using MultiCogSerialDebug object as I don't have VGA.
It shows:
heap available 3FFA
objectLength 06A8
objectStartPtr 1605
@ steven : Finally had a chance to look at your code and it's quite impressive, and DOL quite a powerful tool. Not astoundingly easy to use yet because the PropTool doesn't have the support for dynamic objects and so on, but if the programming effort is put it I think it could yield impressive results. It's certainly good enough to launch whole programs from PropDoS etc.
When I first suggested just moving the object I never realised it was actually really that simple, just update a dummy object entry to point to the loaded object, call the dummy object which really calls the loaded object and everything else happens automatically ( Edited : Except stopping VAR being dumped in the stack space ). Thanks to Chip there for a position independent implementation of objects and Spin in general.
I've been exercising my brain trying to think of when the Spin Compiler might generate absolute addressed code or pointers which would affect DOL but haven't so far come up with any scenario.
You've got far further than I have. My absolute basic minimum implementation is attached.
@hippy: I like that. It's much neater than all my code . Maybe I'll have to make two versions. A full version with everything and a cut down version that that doesn't do calls between objects.
No update for tonight. I made a whole heap of changes for V_007 and busted something in the process. I will have to go back to V_006 to find out what it is.
@Steven and Hippy,
Would it be possible to find the values assigned to an OBJ tag?
For example:
My heap_test program has
OBJ · debug: "MultiCogSerialDebug"· 'debugport serial driver · mem:·· "heap"················ 'dynamic memory control · 'mem2: "heap"
VAR · long atnStack[noparse][[/noparse]10]······· 'stack for monitoring ATN pin · byte debugSemID········· 'lock to be used by debug · byte heapArray[noparse][[/noparse]HEAPSIZE] 'byte array to serve as heap · word block1,block2
The heap object has
VAR · word heapStart······ '//address of heap · word heapEnd········ '//points to closing 0 word
When I compile I get Program 1073 longs,·Variables 278 longs.
If I uncomment mem2 in the main program that becomes
Program 1074 longs, Variables 279 longs.
Apparently the mem2 tag consumes a long in program area.
I was thinking, if the value·for mem2 could be retrieved and passed
to another object,·that has
OBJ · mem3: "heap"
and I would replace the value for mem3 with the retrieved value of mem2,
then any reference mem3.??? would actually access mem2.???
I know this is not really related to dynamically loading·objects, but would the above
be possible? Or is there more involved?
@ Peter : Yes that's entirely possible and effectively what I do in my minimal code. For OBJ mem3: "heap" you can obtain a pointer which is effectively @mem3
I do that by using a named label in a DAT section of what here is "heap.spin". Because of the way the PropTool locates code within hub memory, that label is given the hub address of the long immediately after what I call the 'method pointer table'. By knowing how many methods there are one can simply offset back to the start of the object, ie @mem3.
From knowing @mem3, one can then find where the entry is in the 'method pointer table', and consequently, because all OBJ entries are sequential, addresses of all other sub-objects can be obtained through that table.
Getting "heap.spin" to return its object base may ( I haven't tested ) be difficult if it includes sub-objects as the magic label used to get its own address may not end up where desired, however, put that in a dummy object as per my code, and once you have the address of an object ( ie, @dummy ), you can find the address of any other object.
Once you have @dummy and @mem3, and know where the entry pointing to @dummy is in the 'method pointer table', drop @mem3 in the 'Point to @dummy' entry and any calls to the dummy object then vector off to the mem3 object.
A simple dummy object won't do I think. What I meant was to get the value for mem2 in the
main program, and write that value at the location for mem3 in another object so that when
using mem3.somefunction it really calls mem2.somefunction. Since mem2 and mem3 are the
same object type I can use the method names.
OBJ · i: "obj1" ··j: "obj2"
What is required is a function
PUB getObjectAddr(index):addr
that returns the address of the object tag.
For obj1 the index=0, for obj2 the index=1
value := long[noparse][[/noparse]getObjectAddr(0)]
obj2.passObjectHandle(value)
Hopefully another 'picture worth a thousand words'. This shows how an object is laid out in hub memory by the Prop Tool. Where any sub-object is included isn't indicated because I ahvenet checked. AFAIR, they are placed after the DAT Code and before the Executable Method Code, but I may be wrong.
.---------------.
Object Base --> |_______________|----------> To next object in application
|_______________|---. To first PUB method
|_______________|---|---. To next method
| | | |
| | | |
| |---|---|--> To object base of first sub-object
| |---|---|--> To object base of second sub-object
|_______________| | |
| | | |
: DAT Code : | |
|_______________| | |
| | <-' |
: PUB First : |
|_______________| |
| | <-----'
: Other Methods :
| |
`---------------'
Peter Verkaik said...
What I meant was to get the value for mem2 in the
main program, and write that value at the location for mem3 in another object so that when
using mem3.somefunction it really calls mem2.somefunction. Since mem2 and mem3 are the
same object type I can use the method names.
That should work, but if both objects are the same type then the PropTool will AIUI have made the two pointers point to the same hub address anyway; objects are re-entrant so there will only ever be one copy of an object's 'method pointer table' and executable code in hub.
What differentiates the two objects is where the Variable Base is set when each object is used, each gets its own unique VAR area allocated in hub. To make mem3 exactly the same as mem2 means having to adjust the Variable Base ( not sure how that would be done ) or ensure that mem2 only has its data within a DAT section.
I suppose one way to look at it in an OOP way is that variables/data in DAT is static, common for all instantiations of that object, variables in VAR are unique for each instantiation - please excuse my OOP terminology if it's wrong.
Peter Verkaik said...
Where in your picture are the object tags located, for the objects declared under OBJ
From a top-object ( main program ) the object tags for its sub-objects are the "To base of N object" pointers ( placed after PUB/PRI method pointers ).
For sub-objects including further sub-objects, same again but within their own 'method pointer table'.
I was hoping the 32bit value for an object tag would hold the reference for the
VAR area used by that specific object, so for·two objects
OBJ · p: "obj" · q: "obj"
the tag values would be different.
Yes, the object tag does hold a different reference for each object; each tag is a long, the first word is the address of the object base ( the same for each in this case ), the second word is the number of bytes to add to Variable Base which would be different.
Being a value to add is what makes it difficult to make them both point to the same Variable Base. Not a problem here when p and q are in the same object - simply replace the add value for q with that from p, but if p was in one object and q were in a sub-object the Variable Base would have been altered when the object containing q was entered, so one couldn't add the same value to get to the same Variable Base.
Theoretically the add value could be adjusted for q in the sub-object's table but I don't know if making that two's complement negative would work if it needed to be a subtract rather than add; if Variable Base is held as a long, does adding a two's complement word work ? It may. It may break for the Prop II.
Then there's the challenge of being able to determine what the add value should from within the sub-object. Calling q from the top object and from a sub-object would allow the Variable Base for each to be determined and it should be possible to determine the fixup needed but it could get quite complicated.
I'm afraid I can only comment theoretically because I've not tried any of this.
I see. Not so simple then. I wonder what the benefits are of using an offset
to the variable base rather than using the address of the var section directly in the tag value.
After all, the program·is staticly linked and the methods are referenced via object base
already.
One possibility is that on the way into an object the offset can be added and on the way out subtracted again, but that requires keeping a reference to the tag on the stack and it seems easier to just push the previous Variable Base and pop that back when done.
Thinking about that though, and it would make some sense; if the Object Base is pushed anyway the index to the tag can be pushed as a byte which frees up a byte which can be used to hold the indication of whether the call was trappable or not, should have its result discarded or not, and indicate if it was a local or inter-object call.
I never fully discovered / understood the stack framing used by the ROM Spin Interpreter when implementing SpinVM. I did it by pushing the Object Base, Variable Base, Stack Pointer and Return PC as words ( simply pop everything back to how it was on return ) and used the unused lsb's of an always long aligned word to hold the calling information. Quite messy but works.
I've also not worked out why there's a hard cap on 255 methods/sub-objects allowed in each object. The operands for calls could easily allow more, the table can allow more, so there's some unknown but rational explanation to be had elsewhere. If the area on stack for the index is fixed as a byte that could explain it.
New version of DOL. Lots of fixes and new features. It can now load more than one object and allows calls between objects. This one does all kinds of calling between objects and DOL. See the version table in DOL. I just want to fix up the aborts a bit and then I will do a version that reads from the SD card.
hippy said...
I've been exercising my brain trying to think of when the Spin Compiler might generate absolute addressed code or pointers which would affect DOL but haven't so far come up with any scenario.
I think this will happen if you use the '@@' or '@' operators in a DAT section. Haven't tried it yet though.
Peter said...
I see. Not so simple then. I wonder what the benefits are of using an offset
to the variable base rather than using the address of the var section directly in the tag value.
After all, the program is staticly linked and the methods are referenced via object base
already.
Just guessing, but I think it has to do with the compiler. The compiler can go through and compile each sub-object individually and then just put in the offsets in the method pointer table. Even if the sub-object has sub-objects it would still work and be pretty simple.
Steven,
I compared/assumed it the way the javelin handles things. The javelin uses 16bit tagvalues (when using the
'new' keyword to create an instance)
that you can pass to other objects. The tagvalue is the address where the object base address
and var base address for that specific instance are located. So no matter where you use
the tagvalue, it always points to the areas for the specific instance.
In spin·the tagvalue must hold an offset to the var base of the object in which the tagvalue is used.
That makes it not so simple. Because all is staticly linked, the absolute addresses could have been
used I am sure. Perhaps the prop II handles it better (an updated interpreter).
I found an alternative way to pass an object. Rather than copying the tagvalue, I pass
the properties of an object and call the object initialization routines from the other object. http://forums.parallax.com/showthread.php?p=699699· (3rd·post from last)
I realize that only works nice when the properties are pointers to a datastructure.
Lets see what DOL can do (I would like to use named methods)
@Peter: DOL can't use method names, but, you can define constants like this
#some number greater than 16
method1
method2
method3
etc..
and then just copy it to other objects and use these to call the methods. You will still need a data structure if you have more than one argument. If someone (please parallax, at least fix the spin compiler so that it can call a pre-processor that someone here writes) wrote a pre-processor then we wouldn't need to do this. You could just include an object definition file and the preprocessor would handle all the mucking around.
Steven,
I just thought of something. DOL uses a dummy object whose pointers are adjusted
to reflect the target object, right?
What if I have an object MyObject and I create a dummyMyObject
that has all the public and private methods (including arguments)
but with code removed (just the method names + arguments as in MyObject)
and use dummyMyObject as the dummy object. Its method table would then
be identical to the MyObject method table, wouldn't it?
Could we then use the method names directly?
Sorry, I've done that twice now. I'm not old enough to be getting Alzheimer's yet. Here it is.
Peter, it won't work with how DOL is currently set up. To call another object, the callObject method in DOL is called. This then determines which dynamically loaded oject matches the name passed to it (if any, otherwise DOL aborts). It then plays around with the pointers and calls the object. When the object is called, methodSelector takes the method name passed to it and figeres out what to do. Obviously this is going to take more time than a normal object call, but you don't generally use spin when speed is tight any way.
However, if you wanted to, you could include your dummy object, dynamically load the real object and then call DOL to get the location of the real object and then adjust the method pointer table as required. Note though that when you include a dummy object it uses up a long for every PUB, PRI and sub-object in the dummy object plus a byte for every method (needs a return op-code). If you like I can do a demo of this when I get DOL finished.
Steven,
I actually had the example in mind that I discussed with Hippy some posts back.
Since there are offsets involved, I adapted that example.
What I meant was to get the value for mem2 in the
main program, and write that value at the location for mem3 in another object so that when
using mem3.somefunction it really calls mem2.somefunction. Since mem2 and mem3 are the
same object type I can use the method names.
OBJ · i: "obj1" ··j: "obj2"
What is required is a function
PUB getObjectAddr(index):addr
that returns the address of the object tag.
and a function getVarBase that returns the varbase address
For obj1 the index=0, for obj2 the index=1
value := long[noparse][[/noparse]getObjectAddr(0)]
value.word[noparse][[/noparse]0] += getVarBase 'now the tagvalue holds absolute var address for this instance
obj2.passObjectHandle(value)
obj2 has
OBJ · k: "obj1"· 'this has index 0
PUB · value.word[noparse][[/noparse]0] -= getVarBase 'tagvalue holds offset to varbase of obj2 · long[noparse]/noparse]getObjectAddr[noparse][[/noparse]0 := value 'value·that was·passed to obj2
I assume here that the low word of the tagvalue is the offset to varbase.
Would this work? If so, is it also required that both main program and obj2 include
the routines getObjectAddr and getVarBase?
will give you the offset to the sub-object (from the base of the current object) and the offset for the VARBase (from the current VARbase) of the last sub-object respictively (In your case obj2). To get the addresses of ealier sub-objects, simply subtract 4 for each place further back the object is.
Now, if you want to use this value in another sub-object it starts getting a little tricky. What you have to do is figure out the offset from the base of the sub-object back to the sub-object that you want to call. And then do it again for the VAR base.
What do you mean by index? Do you mean the location in the method table or is it just some variable to indicate which method?
So the code you want is something like this. (haven't tested it yet so be warned)
'in the main object
OBJ
i:"obj1"
j:"obj2"
DAT
endOfObjects long 0 ' you can store any value in here. we just need the address
VAR
long firstVariable 'just the first varable
PUB start
j.passObjectHandle(getObjectAddress(1)-getObjectAddress(0),getObjectVARBase(1)-getObjectVARBase(0)
'then you can call some other method in obj2 and get it to run methods in obj1
j.run
PUB getObjectAddress(index)
' if index==1 'using the absolute addresses
' return word[noparse][[/noparse] @endOfObjects-4 ]
' elseif index==0
' return word[noparse][[/noparse] @endOfObjects-8 ]
'or if you want the absolute address and not the offset (makes finding the new offset easier)
if index==1
return word[noparse][[/noparse] @endOfObjects-4]+$10 'the $10 is where the first object starts
elseif index==0
return word[noparse][[/noparse] @endOfObjects-8]+$10
PUB getObjectVARBase(index)
' if index==1 using the absolute addresses
' return word[noparse][[/noparse] @endOfObjects-4 ]
' elseif index==0
' return word[noparse][[/noparse] @endOfObjects-8 ]
'or if you want the absolute address and not the offset
if index==1
return @firstVariable+word[noparse][[/noparse] @endOfObjects-4 ]
elseif index==0
return @firstVariable+word[noparse][[/noparse] @endOfObjects-8]
'in obj2
OBJ
d:"dummyObject" 'object that has the same methods as the one you want to call but has all the other code removed
DAT
endOfObject long 0 'same as above
PUB passObjectHandle(objectOffset,varOffset)
word[noparse][[/noparse]@endOfObject-4]:=objectOffset
word[noparse][[/noparse]@endOfObject-2]:=varOffset
'now you should be able to do something like this and it will (should [img]http://forums.parallax.com/images/smilies/smile.gif[/img] )call obj1
PUB run
d.doSomething
'whatever other methods you want
Steven,
Thanks for that template.
I put it all to work and attached some demo code.
Unfortunately it does not work.
If you care to take a look, much appreciated.
I have put in comments to make clear what should happen.
Steven,
I got it working now. Turns out to be simpler than your template suggested.
I can now use the method names and all indexes are local to files, and
determined by the order of declared objects under OBJ.
This means·even if a target object changes (eg. obj2), that does not effect the·calling (eg.·main)
Here is a new version of DOL. The next one will try to load from an SD card (I've still got to get one and make a reader for it. ). Updates for V_009 are
- fixed up the aborts some though there is still more to do
- added some calls so that loaded objects can dynamically allocate memory from the heap
Comments
Steven
debug messages using MultiCogSerialDebug object as I don't have VGA.
It shows:
heap available 3FFA
objectLength 06A8
objectStartPtr 1605
regards peter
When I first suggested just moving the object I never realised it was actually really that simple, just update a dummy object entry to point to the loaded object, call the dummy object which really calls the loaded object and everything else happens automatically ( Edited : Except stopping VAR being dumped in the stack space ). Thanks to Chip there for a position independent implementation of objects and Spin in general.
I've been exercising my brain trying to think of when the Spin Compiler might generate absolute addressed code or pointers which would affect DOL but haven't so far come up with any scenario.
You've got far further than I have. My absolute basic minimum implementation is attached.
Post Edited (hippy) : 1/10/2008 3:23:07 AM GMT
Steven
Would it be possible to find the values assigned to an OBJ tag?
For example:
My heap_test program has
OBJ
· debug: "MultiCogSerialDebug"· 'debugport serial driver
· mem:·· "heap"················ 'dynamic memory control
· 'mem2: "heap"
VAR
· long atnStack[noparse][[/noparse]10]······· 'stack for monitoring ATN pin
· byte debugSemID········· 'lock to be used by debug
· byte heapArray[noparse][[/noparse]HEAPSIZE] 'byte array to serve as heap
· word block1,block2
The heap object has
VAR
· word heapStart······ '//address of heap
· word heapEnd········ '//points to closing 0 word
When I compile I get Program 1073 longs,·Variables 278 longs.
If I uncomment mem2 in the main program that becomes
Program 1074 longs, Variables 279 longs.
Apparently the mem2 tag consumes a long in program area.
I was thinking, if the value·for mem2 could be retrieved and passed
to another object,·that has
OBJ
· mem3: "heap"
and I would replace the value for mem3 with the retrieved value of mem2,
then any reference mem3.??? would actually access mem2.???
I know this is not really related to dynamically loading·objects, but would the above
be possible? Or is there more involved?
regards peter
··
I do that by using a named label in a DAT section of what here is "heap.spin". Because of the way the PropTool locates code within hub memory, that label is given the hub address of the long immediately after what I call the 'method pointer table'. By knowing how many methods there are one can simply offset back to the start of the object, ie @mem3.
From knowing @mem3, one can then find where the entry is in the 'method pointer table', and consequently, because all OBJ entries are sequential, addresses of all other sub-objects can be obtained through that table.
Getting "heap.spin" to return its object base may ( I haven't tested ) be difficult if it includes sub-objects as the magic label used to get its own address may not end up where desired, however, put that in a dummy object as per my code, and once you have the address of an object ( ie, @dummy ), you can find the address of any other object.
Once you have @dummy and @mem3, and know where the entry pointing to @dummy is in the 'method pointer table', drop @mem3 in the 'Point to @dummy' entry and any calls to the dummy object then vector off to the mem3 object.
main program, and write that value at the location for mem3 in another object so that when
using mem3.somefunction it really calls mem2.somefunction. Since mem2 and mem3 are the
same object type I can use the method names.
OBJ
· i: "obj1"
··j: "obj2"
What is required is a function
PUB getObjectAddr(index):addr
that returns the address of the object tag.
For obj1 the index=0, for obj2 the index=1
value := long[noparse][[/noparse]getObjectAddr(0)]
obj2.passObjectHandle(value)
obj2 has
OBJ
· k: "obj1"· 'this has index 0
PUB
· long[noparse]/noparse]getObjectAddr[noparse][[/noparse]0 := value 'value·that was·passed to obj2
regards peter
·
The 'method pointer table' in more detail ...
regards peter
That should work, but if both objects are the same type then the PropTool will AIUI have made the two pointers point to the same hub address anyway; objects are re-entrant so there will only ever be one copy of an object's 'method pointer table' and executable code in hub.
What differentiates the two objects is where the Variable Base is set when each object is used, each gets its own unique VAR area allocated in hub. To make mem3 exactly the same as mem2 means having to adjust the Variable Base ( not sure how that would be done ) or ensure that mem2 only has its data within a DAT section.
I suppose one way to look at it in an OOP way is that variables/data in DAT is static, common for all instantiations of that object, variables in VAR are unique for each instantiation - please excuse my OOP terminology if it's wrong.
From a top-object ( main program ) the object tags for its sub-objects are the "To base of N object" pointers ( placed after PUB/PRI method pointers ).
For sub-objects including further sub-objects, same again but within their own 'method pointer table'.
VAR area used by that specific object, so for·two objects
OBJ
· p: "obj"
· q: "obj"
the tag values would be different.
regards peter
Being a value to add is what makes it difficult to make them both point to the same Variable Base. Not a problem here when p and q are in the same object - simply replace the add value for q with that from p, but if p was in one object and q were in a sub-object the Variable Base would have been altered when the object containing q was entered, so one couldn't add the same value to get to the same Variable Base.
Theoretically the add value could be adjusted for q in the sub-object's table but I don't know if making that two's complement negative would work if it needed to be a subtract rather than add; if Variable Base is held as a long, does adding a two's complement word work ? It may. It may break for the Prop II.
Then there's the challenge of being able to determine what the add value should from within the sub-object. Calling q from the top object and from a sub-object would allow the Variable Base for each to be determined and it should be possible to determine the fixup needed but it could get quite complicated.
I'm afraid I can only comment theoretically because I've not tried any of this.
to the variable base rather than using the address of the var section directly in the tag value.
After all, the program·is staticly linked and the methods are referenced via object base
already.
regards peter
One possibility is that on the way into an object the offset can be added and on the way out subtracted again, but that requires keeping a reference to the tag on the stack and it seems easier to just push the previous Variable Base and pop that back when done.
Thinking about that though, and it would make some sense; if the Object Base is pushed anyway the index to the tag can be pushed as a byte which frees up a byte which can be used to hold the indication of whether the call was trappable or not, should have its result discarded or not, and indicate if it was a local or inter-object call.
I never fully discovered / understood the stack framing used by the ROM Spin Interpreter when implementing SpinVM. I did it by pushing the Object Base, Variable Base, Stack Pointer and Return PC as words ( simply pop everything back to how it was on return ) and used the unused lsb's of an always long aligned word to hold the calling information. Quite messy but works.
I've also not worked out why there's a hard cap on 255 methods/sub-objects allowed in each object. The operands for calls could easily allow more, the table can allow more, so there's some unknown but rational explanation to be had elsewhere. If the area on stack for the index is fixed as a byte that could explain it.
Steven
I think this will happen if you use the '@@' or '@' operators in a DAT section. Haven't tried it yet though.
Just guessing, but I think it has to do with the compiler. The compiler can go through and compile each sub-object individually and then just put in the offsets in the method pointer table. Even if the sub-object has sub-objects it would still work and be pretty simple.
Steven
I compared/assumed it the way the javelin handles things. The javelin uses 16bit tagvalues (when using the
'new' keyword to create an instance)
that you can pass to other objects. The tagvalue is the address where the object base address
and var base address for that specific instance are located. So no matter where you use
the tagvalue, it always points to the areas for the specific instance.
In spin·the tagvalue must hold an offset to the var base of the object in which the tagvalue is used.
That makes it not so simple. Because all is staticly linked, the absolute addresses could have been
used I am sure. Perhaps the prop II handles it better (an updated interpreter).
I found an alternative way to pass an object. Rather than copying the tagvalue, I pass
the properties of an object and call the object initialization routines from the other object.
http://forums.parallax.com/showthread.php?p=699699· (3rd·post from last)
I realize that only works nice when the properties are pointers to a datastructure.
Lets see what DOL can do (I would like to use named methods)
regards peter
#some number greater than 16
method1
method2
method3
etc..
and then just copy it to other objects and use these to call the methods. You will still need a data structure if you have more than one argument. If someone (please parallax, at least fix the spin compiler so that it can call a pre-processor that someone here writes) wrote a pre-processor then we wouldn't need to do this. You could just include an object definition file and the preprocessor would handle all the mucking around.
Steven
I just thought of something. DOL uses a dummy object whose pointers are adjusted
to reflect the target object, right?
What if I have an object MyObject and I create a dummyMyObject
that has all the public and private methods (including arguments)
but with code removed (just the method names + arguments as in MyObject)
and use dummyMyObject as the dummy object. Its method table would then
be identical to the MyObject method table, wouldn't it?
Could we then use the method names directly?
BTW, did you upload the latest DOL?
regards peter
Peter, it won't work with how DOL is currently set up. To call another object, the callObject method in DOL is called. This then determines which dynamically loaded oject matches the name passed to it (if any, otherwise DOL aborts). It then plays around with the pointers and calls the object. When the object is called, methodSelector takes the method name passed to it and figeres out what to do. Obviously this is going to take more time than a normal object call, but you don't generally use spin when speed is tight any way.
However, if you wanted to, you could include your dummy object, dynamically load the real object and then call DOL to get the location of the real object and then adjust the method pointer table as required. Note though that when you include a dummy object it uses up a long for every PUB, PRI and sub-object in the dummy object plus a byte for every method (needs a return op-code). If you like I can do a demo of this when I get DOL finished.
Steven
I actually had the example in mind that I discussed with Hippy some posts back.
Since there are offsets involved, I adapted that example.
What I meant was to get the value for mem2 in the
main program, and write that value at the location for mem3 in another object so that when
using mem3.somefunction it really calls mem2.somefunction. Since mem2 and mem3 are the
same object type I can use the method names.
OBJ
· i: "obj1"
··j: "obj2"
What is required is a function
PUB getObjectAddr(index):addr
that returns the address of the object tag.
and a function getVarBase that returns the varbase address
For obj1 the index=0, for obj2 the index=1
value := long[noparse][[/noparse]getObjectAddr(0)]
value.word[noparse][[/noparse]0] += getVarBase 'now the tagvalue holds absolute var address for this instance
obj2.passObjectHandle(value)
obj2 has
OBJ
· k: "obj1"· 'this has index 0
PUB
· value.word[noparse][[/noparse]0] -= getVarBase 'tagvalue holds offset to varbase of obj2
· long[noparse]/noparse]getObjectAddr[noparse][[/noparse]0 := value 'value·that was·passed to obj2
I assume here that the low word of the tagvalue is the offset to varbase.
Would this work? If so, is it also required that both main program and obj2 include
the routines getObjectAddr and getVarBase?
regards peter
then
will give you the offset to the sub-object (from the base of the current object) and the offset for the VARBase (from the current VARbase) of the last sub-object respictively (In your case obj2). To get the addresses of ealier sub-objects, simply subtract 4 for each place further back the object is.
Now, if you want to use this value in another sub-object it starts getting a little tricky. What you have to do is figure out the offset from the base of the sub-object back to the sub-object that you want to call. And then do it again for the VAR base.
What do you mean by index? Do you mean the location in the method table or is it just some variable to indicate which method?
So the code you want is something like this. (haven't tested it yet so be warned)
Hope this helps
Steven
Thanks for that template.
I put it all to work and attached some demo code.
Unfortunately it does not work.
If you care to take a look, much appreciated.
I have put in comments to make clear what should happen.
regards peter
I got it working now. Turns out to be simpler than your template suggested.
I can now use the method names and all indexes are local to files, and
determined by the order of declared objects under OBJ.
This means·even if a target object changes (eg. obj2), that does not effect the·calling (eg.·main)
regards peter
Here is a new version of DOL. The next one will try to load from an SD card (I've still got to get one and make a reader for it. ). Updates for V_009 are
- fixed up the aborts some though there is still more to do
- added some calls so that loaded objects can dynamically allocate memory from the heap
Steven
And I even rembered to include the file this time