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

Constructor that take ptr as argument never called #340

Open
AlixANNERAUD opened this issue May 19, 2023 · 17 comments
Open

Constructor that take ptr as argument never called #340

AlixANNERAUD opened this issue May 19, 2023 · 17 comments

Comments

@AlixANNERAUD
Copy link
Contributor

AlixANNERAUD commented May 19, 2023

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.

@s-hadinger
Copy link
Contributor

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.

@AlixANNERAUD
Copy link
Contributor Author

That would be great ! Thank you for your quick answer.

@AlixANNERAUD
Copy link
Contributor Author

Update ?

@s-hadinger
Copy link
Contributor

Sorry not yet. I tried a quick fix but it failed

@s-hadinger
Copy link
Contributor

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.

@s-hadinger
Copy link
Contributor

Can you elaborate more about what you need? Can you make sure you don't send a comptr as first argument?

@AlixANNERAUD
Copy link
Contributor Author

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.

@s-hadinger
Copy link
Contributor

My point is that it would work if you pass a dummy first argument, and the comptr as a second argument.

@AlixANNERAUD
Copy link
Contributor Author

Ok, well, thank you, I will try to do it like that.

@s-hadinger
Copy link
Contributor

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.

@AlixANNERAUD
Copy link
Contributor Author

Comobj ? Do you have the link to its documentation ?

@s-hadinger
Copy link
Contributor

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");
[...]

@s-hadinger
Copy link
Contributor

Comobj ? Do you have the link to its documentation ?

Unfortunately documentation of comobj is missing. I inferred it from the source.

@AlixANNERAUD
Copy link
Contributor Author

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.

@s-hadinger
Copy link
Contributor

Ok, got it. Then comptr is the right way.

@AlixANNERAUD
Copy link
Contributor Author

AlixANNERAUD commented May 22, 2023

Thank you, however, this will be very useful to me because I have other cases where it can be useful.

@AlixANNERAUD
Copy link
Contributor Author

AlixANNERAUD commented May 23, 2023

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.

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