Embedding API: method invocation.
Shockwave
vinfobag at gmail.com
Sun Feb 6 13:32:36 UTC 2011
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);
// 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.
1) Is what I have above the way one is supposed to invoke methods. If not,
what can be improved about it?
2) How does one fetch a return value of a PIR method call from the C/C++
side?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Main.pir
Type: application/octet-stream
Size: 688 bytes
Desc: not available
URL: <http://lists.parrot.org/pipermail/parrot-dev/attachments/20110206/807e94b5/attachment.obj>
More information about the parrot-dev
mailing list