Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct returning of objects #26

Open
JernejL opened this issue Jan 10, 2020 · 4 comments
Open

Correct returning of objects #26

JernejL opened this issue Jan 10, 2020 · 4 comments

Comments

@JernejL
Copy link

JernejL commented Jan 10, 2020

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
Copy link
Owner

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
Copy link
Author

JernejL commented Jan 10, 2020

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
Copy link
Owner

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
Copy link
Author

JernejL commented Jan 10, 2020

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 up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants