Correct returning of objects #26

Open
opened 2020-01-10 08:10:49 +00:00 by JernejL · 4 comments
JernejL commented 2020-01-10 08:10:49 +00:00 (Migrated from github.com)

Whenever an instance of class that is registered in besen is created, i put it on a class pointer list internally.

I need a class function on another class - that would return an array of all those instances.

So, gameinterface - return list of all actors:

I have experimented and found a way to return array of strings, this works for strings:

`
procedure TGameInterface.ActorList(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer; var ResultValue: TBESENValue);
var
i: integer;
ara: TBESENObjectArray;
begin

ResultValue.ValueType:= bvtBOOLEAN;
ResultValue.Bool:= false;

ara:= TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false);

for i:= 0 to BesenActorList.highest do begin

// this works well - returns an string array
ara.Push( BESENStringValue('Test String, ignore.') );
// this will crash besen
    ara.Push( besenobjectvalue(BesenActorList.Data[i]) );

end;

resultvalue:= BESENObjectValue(ara);

end;
`

If i return those objects, what happens is i get garbage collector crash in TBESENGarbageCollectorObjectList.Remove:

[Window Title]
Error

[Content]
Project tdc raised exception class 'External: SIGSEGV'.

In file 'besen\src\BESENGarbageCollector.pas' at line 518:
AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext;

[OK]

while i cannot find any example of this.. i'm not sure what the problem is with garbage collector, the crash happens when trying to access any property of the array or loop the array via for i in array in script.

The resulting array can be sent to stuff like internal print() function and that works! no crash there.

Call stack of crash:

`
#0 REMOVE(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:518
#1 GRAYIT(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:642
#2 GRAYVALUE(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENGarbageCollector.pas:675
#3 MARK(0xfeeefeee) at besen\src\BESENObject.pas:2491
#4 MARK(0xfeeefeee) at besen\src\BESENObjectArray.pas:348
#5 MARK(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:703
#6 COLLECT(0x26e4f404) at besen\src\BESENGarbageCollector.pas:830
#7 TRIGGERCOLLECT(0xfeeefeee) at besen\src\BESENGarbageCollector.pas:727
#8 CALLEX(0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}, false) at besen\src\BESENObjectDeclaredFunction.pas:175
#9 CALL(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}, 0xfeeefeee, -17891602, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENObjectDeclaredFunction.pas:132
#10 OBJECTCALLCONSTRUCT(0x2690ce94, 0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, false, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}) at besen\src\BESEN.pas:773
#11 OBJECTCALL(0xfeeefeee, 0xfeeefeee, <error reading variable: Cannot access memory at address 0xfeeefeee>, 0xfeeefeee, 652538884, <error reading variable: Cannot access memory at address 0xfeeefeee>) at besen\src\BESEN.pas:787
#12 OPTRACECALL(0x26e7df5c, 0x26dce2fc) at besen\src\BESENCodeContext.pas:3040
#13 ?? at :0

`

Whenever an instance of class that is registered in besen is created, i put it on a class pointer list internally. I need a class function on another class - that would return an array of all those instances. So, gameinterface - return list of all actors: I have experimented and found a way to return array of strings, this works for strings: ` procedure TGameInterface.ActorList(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer; var ResultValue: TBESENValue); var i: integer; ara: TBESENObjectArray; begin ResultValue.ValueType:= bvtBOOLEAN; ResultValue.Bool:= false; ara:= TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); for i:= 0 to BesenActorList.highest do begin // this works well - returns an string array ara.Push( BESENStringValue('Test String, ignore.') ); // this will crash besen ara.Push( besenobjectvalue(BesenActorList.Data[i]) ); end; resultvalue:= BESENObjectValue(ara); end; ` If i return those objects, what happens is i get garbage collector crash in TBESENGarbageCollectorObjectList.Remove: > [Window Title] > Error > > [Content] > Project tdc raised exception class 'External: SIGSEGV'. > > In file 'besen\src\BESENGarbageCollector.pas' at line 518: > AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext; > > [OK] while i cannot find any example of this.. i'm not sure what the problem is with garbage collector, the crash happens when trying to access any property of the array or loop the array via for i in array in script. The resulting array can be sent to stuff like internal print() function and that works! no crash there. Call stack of crash: ` #0 REMOVE(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:518 #1 GRAYIT(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:642 #2 GRAYVALUE(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENGarbageCollector.pas:675 #3 MARK(0xfeeefeee) at besen\src\BESENObject.pas:2491 #4 MARK(0xfeeefeee) at besen\src\BESENObjectArray.pas:348 #5 MARK(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:703 #6 COLLECT(0x26e4f404) at besen\src\BESENGarbageCollector.pas:830 #7 TRIGGERCOLLECT(0xfeeefeee) at besen\src\BESENGarbageCollector.pas:727 #8 CALLEX(0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}, false) at besen\src\BESENObjectDeclaredFunction.pas:175 #9 CALL(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}, 0xfeeefeee, -17891602, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENObjectDeclaredFunction.pas:132 #10 OBJECTCALLCONSTRUCT(0x2690ce94, 0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, false, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}) at besen\src\BESEN.pas:773 #11 OBJECTCALL(0xfeeefeee, 0xfeeefeee, <error reading variable: Cannot access memory at address 0xfeeefeee>, 0xfeeefeee, 652538884, <error reading variable: Cannot access memory at address 0xfeeefeee>) at besen\src\BESEN.pas:787 #12 OPTRACECALL(0x26e7df5c, 0x26dce2fc) at besen\src\BESENCodeContext.pas:3040 #13 ?? at :0 `
BeRo1985 commented 2020-01-10 11:12:01 +00:00 (Migrated from github.com)

You must maybe temporally protect or lock all besenobjectvalue(BesenActorList.Data[i]) instances in the garbage collector, and all instances must be BESEN objects itself.

You must maybe temporally protect or lock all besenobjectvalue(BesenActorList.Data[i]) instances in the garbage collector, and all instances must be BESEN objects itself.
JernejL commented 2020-01-10 11:56:00 +00:00 (Migrated from github.com)

Objects that i put in array are all instances of TActorInterface which is extended from TBESENNativeObject - that should be ok, right?

If i lock the instances when i construct array and return that (it is put into ResultValue) - when do i unlock those values - it will probably leak memory, if those references never get cleared?

I've done so:

TActorInterface(BesenActorList.Data[i]).GarbageCollectorLock; for each object before array is returned.

Those objects were already created elsewhere from javascript code (they are registered via RegisterNativeObject) - should they not already have a value of reference count that would protect them?

How do i correctly manage the created array - TBESENObjectArray.create, do i need to add that to garbagecollector too?

Objects that i put in array are all instances of TActorInterface which is extended from TBESENNativeObject - that should be ok, right? If i lock the instances when i construct array and return that (it is put into ResultValue) - when do i unlock those values - it will probably leak memory, if those references never get cleared? I've done so: TActorInterface(BesenActorList.Data[i]).GarbageCollectorLock; for each object before array is returned. Those objects were already created elsewhere from javascript code (they are registered via RegisterNativeObject) - should they not already have a value of reference count that would protect them? How do i correctly manage the created array - TBESENObjectArray.create, do i need to add that to garbagecollector too?
BeRo1985 commented 2020-01-10 13:09:28 +00:00 (Migrated from github.com)

try

ResultValue.ValueType:= bvtBOOLEAN;
ResultValue.Bool:= false;

ara:= TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false);
 TBESEN(Instance).GarbageCollector.Add(ara);
 ara.GarbageCollectorLock;
try
for i:= 0 to BesenActorList.highest do begin

// this works well - returns an string array
ara.Push( BESENStringValue('Test String, ignore.') );
// this will crash besen
    ara.Push( besenobjectvalue(BesenActorList.Data[i]) );

end;
finally
 ara.GarbageCollectorUnlock;
end;
resultvalue:= BESENObjectValue(ara);

and have a look for example at procedure TBESENObjectDateConstructor.Construct or at other places inside BESEN, where the garbage collector API is used,

try ```` ResultValue.ValueType:= bvtBOOLEAN; ResultValue.Bool:= false; ara:= TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); TBESEN(Instance).GarbageCollector.Add(ara); ara.GarbageCollectorLock; try for i:= 0 to BesenActorList.highest do begin // this works well - returns an string array ara.Push( BESENStringValue('Test String, ignore.') ); // this will crash besen ara.Push( besenobjectvalue(BesenActorList.Data[i]) ); end; finally ara.GarbageCollectorUnlock; end; resultvalue:= BESENObjectValue(ara); ```` and have a look for example at procedure TBESENObjectDateConstructor.Construct or at other places inside BESEN, where the garbage collector API is used,
JernejL commented 2020-01-10 15:08:49 +00:00 (Migrated from github.com)

This does make sense - i think the main misunderstandings that i have with besen seem to focus in lack of knowledge on how to operate the garbage collector.

so - if have a local function in javascript - that calls a public function which returns an array of objects - i need to only add one reference to the array or also all the objects? and once array is no longer refered to in a local function , GC will remove the objects and the array on its own?

So.. simplified - i add gives +1 reference, if it's not assigned to a global variable or something this gets -1 when local function ends, and the GC kills the object (or an array basically)?

I will try to study this further, it's starting to make some sense.

Also regarding an older comment about performance of besen - so far performance is good, but i did put besen into its own thread, so i don't think i'll have issues with this :)

This does make sense - i think the main misunderstandings that i have with besen seem to focus in lack of knowledge on how to operate the garbage collector. so - if have a local function in javascript - that calls a public function which returns an array of objects - i need to only add one reference to the array or also all the objects? and once array is no longer refered to in a local function , GC will remove the objects and the array on its own? So.. simplified - i add gives +1 reference, if it's not assigned to a global variable or something this gets -1 when local function ends, and the GC kills the object (or an array basically)? I will try to study this further, it's starting to make some sense. Also regarding an older comment about performance of besen - so far performance is good, but i did put besen into its own thread, so i don't think i'll have issues with this :)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
BeRo1985/besen#26
No description provided.