On Sun, Feb 6, 2011 at 8:32 AM, Shockwave <[email protected]> wrote:
> Hello, All.
>
> I have a couple of questions regarding method invocation with the new
> embedding API.
>
> I'm not sure of the correct way of calling a class method. I've found a
> unit-test that made use of the API function Parrot_api_pmc_invoke(). I've
> successfully used that function to call a method of a class, but I may not
> be using it the way it's intended.
>
> I currently have a C++ function like the one shown below, which is called at
> the beginning of the embedding application. This function executes the :main
> method of the bytecode file, which initializes some stuff, including
> registering a class named 'Main'. This function also calls a method of the
> Main class named 'construct'. Finally, the function grabs a reference to an
> 'update' method of the Main class, which will be used to repeatedly call
> that method from another C++ function (Show below this one).
> --------------------- SNIP:Begin -----------------------------------
> bool
> VMachine::start()
> {
> Parrot_PMC args;
> const char** argValues = NULL;
> if (!Parrot_api_pmc_wrap_string_array(mInterp, 0, argValues, &args))
> {
> Log::e("Could not wrap main args array.");
> return false;
> }
>
> // Run the main method.
> if (!Parrot_api_run_bytecode(mInterp, mBytecode, args)) {
> Log::e("Could not run bytecode.");
> return false;
> }
>
> Parrot_String str;
>
> Parrot_PMC mainClass;
> Parrot_PMC classKey;
> Parrot_api_string_import_ascii(mInterp, "Main", &str);
> Parrot_api_pmc_box_string(mInterp, str, &classKey);
>
> // Get a reference to the 'Main' class.
> if (!Parrot_api_pmc_get_class(mInterp, classKey, &mainClass)) {
> Log::e("Could not get the main class key.");
> return false;
> }
>
> // Create an instance of the 'Main' class.
> if (!Parrot_api_pmc_new_from_class(mInterp, mainClass, NULL,
> &mMainObject)) {
> Log::e("Could not instantiate a main class object.");
> return false;
> }
>
> Parrot_PMC contextClassName = NULL;
> Parrot_PMC contextClassHandle = NULL;
> Parrot_PMC sig = NULL;
> Parrot_PMC method = NULL;
>
> // Load the 'CallContext' class,
> Parrot_api_string_import_ascii(mInterp, "CallContext", &str);
> Parrot_api_pmc_box_string(mInterp, str, &contextClassName);
> Parrot_api_pmc_get_class(mInterp, contextClassName,
> &contextClassHandle);
>
> // Create a couple of call contexts.
> Parrot_api_pmc_new_from_class(mInterp, contextClassHandle, NULL,
> &sig);
> Parrot_api_pmc_new_from_class(mInterp, contextClassHandle, NULL,
> &mUpdateSig);
Where are these signatures defined? They are *key* to understanding
what will be done by the invocation.
>
> // Call the construct() method //
>
> Parrot_api_string_import_ascii(mInterp, "construct", &str);
> Parrot_api_pmc_find_method(mInterp, mMainObject, str, &method);
> Parrot_api_pmc_set_keyed_int(mInterp, sig, 0, mMainObject);
>
> if (!Parrot_api_pmc_invoke(mInterp, method, sig)) {
> Log::e("Could not invoke 'construct' method.");
> checkErrors();
> return false;
> }
>
> // Grab a handle to the update method //
>
> Parrot_api_string_import_ascii(mInterp, "update", &str);
> Parrot_api_pmc_find_method(mInterp, mMainObject, str,
> &mUpdateMethod);
>
> // Ideally, I would like to uncomment this out, so that the signature would
> only be set once, and reused every time in the VMachine::update() function
> shown below.
> // Parrot_api_pmc_set_keyed_int(mInterp, mUpdateSig, 0, mMainObject);
>
> return true;
> }
> --------------------- SNIP:End -----------------------------------
>
> The 'update' method of the Main class is called by the embedding app like
> so:
>
>
> --------------------- SNIP:Begin -----------------------------------
> /**
> * Called continuesly to update the Virtual Machine.
> */
> bool
> VMachine::update()
> {
> // Is it possible to remove this first function called?
> // If I move this function to the start() function above (in order
> to set it just once), then
> // ...invoke() function doesn't work.
> Parrot_api_pmc_set_keyed_int(mInterp, mUpdateSig, 0, mMainObject);
>
> if (!Parrot_api_pmc_invoke(mInterp, mUpdateMethod, mUpdateSig)) {
> Log::e("Could not invoke 'update' method.");
> checkErrors();
> return false;
> }
> return true;
> }
> --------------------- SNIP:End -----------------------------------
>
> After running the application, within 1 to 2 seconds, I'll get a parrot
> method recursion error. The exact message is:
>> maximum recursion depth exceeded
>> current instr.: 'runik;VOS.Library.IO;File;write%m_6' pc 4007
> (Runtime/Conversion.pir:194) called from Sub 'runik;Main;Main;update%m' pc
> 3761 (Runtime/Conversion.pir:70) called from Sub 'runik;Main;update' pc 4214
> (Runtime/Array.pir:37)
>
> The double arrows are mine. Also, the filenames shown are wrong (Runtime/*)
>
> To reiterate:
> a) The parrot 'construct' method runs fine, but the C/C++ code doing
> it may not be optimal.
> b) The parrot 'update' method runs, but gives a recursion exceeded
> error. That parrot update method has no recursion within it on the PIR side.
That we cannot tell from the information you have given. You clearly
have more of the Main class defined somewhere or you'd get a method
not defined error on 'update%m', which is not defined in the PIR you
have provided. I also question why you would want to create another
instance of Main (assuming that is what '%CreateInstance' does) and
why doing so in the constructor (assuming 'construct' is a
constructor) does not lead to infinite recursion.
> 1) Is what I have above the way one is supposed to invoke methods. If not,
> what can be improved about it?
Your method is correct, assuming you've used the right signature
(which you have redacted).
> 2) How does one fetch a return value of a PIR method call from the C/C++
> side?
Again, this is all in the signatures.
_______________________________________________
http://lists.parrot.org/mailman/listinfo/parrot-dev