Memory protective V-Table without DataSection.

Share your advanced PureBasic knowledge/code with the community.
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Memory protective V-Table without DataSection.

Post by Hroudtwolf »

Hello,

The most people here could know memory protective V-Tables in DataSections.
I want to show you another way.

Code: Select all

; PureBasic-Lounge.de
; Date: 31. October 2007
; OS: Windows, Linux, Mac
; Demo: Yes


Interface IcMyClass
   Set   (sText.s)
   Get.s ()
EndInterface

Structure cMyClass
   *VTABLE
   
   sText.s
EndStructure

Procedure.l cMyClass_Set (*This.cMyCLass , sText.s)
   *this\sText = sText
   ProcedureReturn #True
EndProcedure

Procedure.s cMyClass_Get (*This.cMyCLass)
   ProcedureReturn *this\sText
EndProcedure

Procedure CreateObject_cMyClass ()
   Protected *This.cMyClass = AllocateMemory (SizeOf (cMyClass))
   Static    *cMyClass_Vtable ; <--- Static pointer to our V-Table
   
   If Not *This
      ProcedureReturn #Null
   EndIf
   
   ; Generation a V-Table for this class, if not already exist.
   If Not *cMyClass_Vtable
      *cMyClass_Vtable = AllocateMemory (SizeOf(IcMyClass))
      If Not *cMyClass_Vtable 
         FreeMemory (*This)
         ProcedureReturn #Null
      EndIf
      ; Adding methodes
      ; Use PokeL and the interface offsets.  Its a easy way to do that.
      PokeL (*cMyClass_Vtable + OffsetOf (IcMyClass\Set ()) , @cMyClass_Set ())
      PokeL (*cMyClass_Vtable + OffsetOf (IcMyClass\Get ()) , @cMyClass_Get ())
   EndIf
   
   ; announce the address of the V-Table for our new object.   
   *This\VTABLE = *cMyClass_Vtable  
      
   ProcedureReturn *This
EndProcedure

;--- Test

*MyObj.IcMyClass = CreateObject_cMyClass ()
*MyObj\Set ("Hello World")
Debug *MyObj\Get ()


Best regards

Wolf


PS: Sorry for my funny english. :)
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi mate.

Find I need to use interfaces and found your post, which I can understand to a degree so I am going to use your approach. Thanks for this.

Some quick questions:

With
  • Static *cMyClass_Vtable
Does it have to be static, and if so why?

How do you go about releasing the object (*This\VTABLE and *This itself)?

Am I making problems for myself doing the following with protected rather than static (and with the vt memory not freed):

Code: Select all

Structure object_o
  *vt.l
  amt.l
EndStructure
Interface object_i
  set(amt.l)
  get()
EndInterface
Structure object_m
  set.l
  get.l
EndStructure


Procedure set(*this.object_o,amt)
  *this\amt = amt
EndProcedure
Procedure get(*this.object_o)
  ProcedureReturn *this\amt
EndProcedure

Procedure freeObject(*this)
; ? how to release vt?
  FreeMemory(*this)
EndProcedure
Procedure newObject()
  Protected *obj.object_o
  Protected *vt.object_m
  
  *obj = AllocateMemory(SizeOf(object_o))
  If *obj
    *vt = AllocateMemory(SizeOf(object_m))
    If *vt
      *vt\set = @set()
      *vt\get = @get()
      *obj\vt = *vt
    Else
      FreeMemory(*obj)
      *obj = 0
    EndIf
  EndIf
  ProcedureReturn *obj
EndProcedure

Debug SizeOf(object_i)
Debug SizeOf(object_m)
Debug SizeOf(object_o)

*myObj.object_i = newObject()
*myOther.object_i = newObject()
Debug *myObj
Debug *myOther
*myObj\set(10)
*myOther\set(100)

Debug *myObj\get()
Debug *myOther\get()

freeObject(*myObj)
freeObject(*myOther)
Thanks again.
Dare2 cut down to size
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

The pointer needs to be static for only one (good) reason that I can see: If it is static, subsequent calls of the procedure find it holding a value, and thus can skip the redundant rebuilding of the vtable. This way it's only built once by the first instance of the object being created.
BERESHEIT
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi mate!

How are you going? :)

Thanks.

With the object release (which is just a free-up of memory?) I am now doing this:

Code: Select all

Procedure freeObject(*this)
  Protected *obj.object_o
  *obj = *this
  FreeMemory(*obj\vt)
  FreeMemory(*this)
EndProcedure
Which I hope is ok.
Dare2 cut down to size
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Dare wrote:Hi mate!

How are you going? :)

Thanks.

With the object release (which is just a free-up of memory?) I am now doing this:

Code: Select all

Procedure freeObject(*this)
  Protected *obj.object_o
  *obj = *this
  FreeMemory(*obj\vt)
  FreeMemory(*this)
EndProcedure
Which I hope is ok.
Wouldn't this also work, and be simpler?

Code: Select all

Procedure freeObject(*this.object_o)
  FreeMemory(*this\vt)
  FreeMemory(*this)
EndProcedure
I think the simplest method is the one suggested by Hroudtwolf. If the vt table was static you wouldn't need to free it, you would only free the object's memory. It's the same as a vt table stored in a DataSection. There would be only one at any one time. If you make a copy of it, then you would need to free it and also you would be multiplying the memory needed for the identical copy that each object would have. I think Hroudtwolf's code is a good alternative to making multiple copies.

Note: if you did use a vt table in a DataSection the same alternative exists. You would just point to it, not reserve additional memory for it, just for the pointer. The example in your code copies it instead. Is that what you really wanted to do?
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Heya Demivec,

Thanks for the explanation, it was very useful.


Demivec wrote:Is that what you really wanted to do?
lol, I had no real idea of what I wanted to do. Or more accurately, what was needed to do.

However thanks to Hroudtwolf's code, which kept everything nice and simple, I could get a grasp of the concept. With the info from yourself and netty I now have a (slightly) better idea of what is going on. :)

Time will tell. :D
Dare2 cut down to size
superadnim
Enthusiast
Enthusiast
Posts: 480
Joined: Thu Jul 27, 2006 4:06 am

Post by superadnim »

I saw this method a lot in the pb lounge german forums but I still think the static method is better, at least for .. well .. static methods.

:lol: should I bash the keyboard and give up?
:?
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Post by Hroudtwolf »

Hi,

The method with DataSections inflates the size of your binaries if your classes has a lot of methods.
If you allocate the memoryarea of your vtable dynamicly,the size of your binary will not be affected.

Best regards

Wolf
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Hroudtwolf wrote:The method with DataSections inflates the size of your binaries if your classes has a lot of methods.
If you allocate the memoryarea of your vtable dynamicly,the size of your binary will not be affected.
At what point does the dynamic vtable become better than the datasection version? If I compile your example to an exe and an equivalent datasection one then the datasection one is the smaller exe.

Also, with the code you have shown, each class will have an overhead of the following code in the exe:

Code: Select all

   If Not *cMyClass_Vtable
      *cMyClass_Vtable = AllocateMemory (SizeOf(IcMyClass))
      If Not *cMyClass_Vtable
         FreeMemory (*This)
         ProcedureReturn #Null
      EndIf
      ; Adding methodes
      ; Use PokeL and the interface offsets.  Its a easy way to do that.
      PokeL (*cMyClass_Vtable + OffsetOf (IcMyClass\Set ()) , @cMyClass_Set ())
      PokeL (*cMyClass_Vtable + OffsetOf (IcMyClass\Get ()) , @cMyClass_Get ())
   EndIf
Wouldn't a simple "Data.l @method()" always be smaller?
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Post by Hroudtwolf »

I think, you should read my post exactlier ;-)
With large classes, the size of your binary will inflate.

Also, you can recycle the dynamic generated vtables like the static vtables for other classes.
So, you can minimize the size of the binaries, too.

And...
The topic of this thread was not "Dynamicly generated vtables are better".
It is about memory protective dynamicly generated vtables.
"One dynamicly generated vtable for each instances of a class".
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Hroudtwolf wrote:I think, you should read my post exactlier ;-)
With large classes, the size of your binary will inflate.
OK, I tried it again. There are now around 80 methods in the interface and the datasection executable is 3kB larger. I never would have thought that "Data.l @procedure()" would end up bigger than "PokeL(addr, @procedure())".

Thanks for the tip.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Post Reply