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