berry
berry copied to clipboard
Constructor that take ptr as argument never called
Here is the following berry code :
Foo = Get_Ptr()
print(Foo) # print : <ptr: 0x3fca0a64> for example
Bar = Module.Test(Foo) #Class constructor taking pointer as argument
Bar = Module.Test(15)
The constructor is declared as CTYPE_FUNC with berry mapping as follows :
class Test_Class()
{
// Stuf here
};
void* Test_Init(bvm* VM, void* PTR)
{
Log_Format("Test_Init with ptr : %p", PTR);
return be_malloc(VM, sizeof(Test_Class));
}
BE_FUNC_CTYPE_DECLARE(Test_Init, "+_p", "@.")
// Berry mapping @const_object_info_begin declaration of the class and module
Once the code is ran, Bar = Test(Foo)
is never called, but Bar = Test(15)
is (of course invalid).
I don't understand why, since there's no type checking on the last argument. It's maybe related to berry mapping ?
I didn't get any exception thrown by the VM.
Oh, I realize this is a leftover from early LVGL mapping. This is not documented, but currently when you pass a comptr
to a constructor, it is directly assigned to the variable and the function is not called.
I think I should change this to not call the function only if the pointer to the function is NULL. Let me check.
That would be great ! Thank you for your quick answer.
Update ?
Sorry not yet. I tried a quick fix but it failed
I'm sorry but I didn't find any good way to solve it.
In LVGL, I typically need to call a native constructor in "C" with the following construct:
int be_ntv_lv_obj_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_obj_create, "+_p", "(lv.lv_obj)"); }
However there are some cases when I just need to clone an existing object and not call the constructor. This is way there is a special behavior: when you call a constructor with a comptr
argument, it just stores the reference and does not call the constructor.
I can't think of any alternative way to call the Berry constructor and not trigger the C constructor.
Can you elaborate more about what you need? Can you make sure you don't send a comptr as first argument?
Well, since in my case the comptr
point to an object allocated outside Berry, it cannot be passed as a class instance to berry because the GC will clean it. Unless there is another way to practice, I don't see how else. However I totally understand the mechanism, and yes indeed, it makes sense.
My point is that it would work if you pass a dummy first argument, and the comptr as a second argument.
Ok, well, thank you, I will try to do it like that.
If you allocate memory outside of Berry but still want to benefit from the GC, you can use comobj
. comobj
are managed by GC and you register a function that will be called when memory is deallocated.
Comobj ? Do you have the link to its documentation ?
The way I do in Tasmota:
/* generic destroy method for comobj, just call be_os_free() on the pointer */
int be_commonobj_destroy_generic(bvm* vm)
{
int argc = be_top(vm);
if (argc > 0) {
void * obj = be_tocomptr(vm, 1);
if (obj != NULL) { be_os_free(obj); }
}
be_return_nil(vm);
}
And then I can allocate an object. Example from Tasmota crypto:
[...]
// Initialize an AES CTR structure with the secret key
br_aes_small_ctr_keys * ctr_ctx = (br_aes_small_ctr_keys *) be_os_malloc(sizeof(br_aes_small_ctr_keys));
if (!ctr_ctx) { be_throw(vm, BE_MALLOC_FAIL); }
[...]
be_newcomobj(vm, ctr_ctx, &be_commonobj_destroy_generic);
be_setmember(vm, 1, ".p1");
[...]
Comobj ? Do you have the link to its documentation ?
Unfortunately documentation of comobj
is missing. I inferred it from the source.
Thank you, however, I don't think this is suitable for my use. I especially don't want my object, allocated outside of berry, to be deallocated as it is also used outside of the VM.
Ok, got it. Then comptr
is the right way.
Thank you, however, this will be very useful to me because I have other cases where it can be useful.
I tried to pass an instance of an object as the first argument parameter, and I get the same behaviour. Same thing when adding a dummy boolean argument.