[squeak-dev] Re: [Vm-dev] Better VM <-> plugin API

Igor Stasenko siguctua at gmail.com
Wed Nov 26 03:02:53 UTC 2008


.. continuing
In the light of current topic about shared namespace. Things could be
more uniform:

let suppose VM having following functions:

int makeAtom(char * atomName) -- which returns an atom id, and interns
an unique name (in same way as symbols interned in squeak) , and sets
it default value to null (if it wasn't internet before).
Any subsequent calls to this function with same argument will return same id.

Two accessor functions:
void * getAtomValue(int atomId);
void * setAtomValue(int atomId, void * newValue); /* returns old value */

And, surely we need a special thread-local storage

makeThreadLocalAtom(char * atomName, initFn, destroyFn)

this function behaves similar to makeAtom() except that
getAtomValue/setAtomValue will use thread-local storage to access atom
value.
InitFn/destroyFn is a functions in a form:

void Fn(Interpreter * intr, int atomId);

Not sure about init/destroy functions. Maybe they not needed, but
instead a VM should notify all plugins about creating new interpreter
or destroying existing one, so plugins should care for themselves
about initializing/finalizing/allocating/deallocating their state.
This just a choice between, where to put a handling logic - into VM,
or into each plugin.

Now, how things would look like if we apply unification thoughout VM:

1. VM could use atoms to define own public function pointers:

setAtom(makeAtom("KERNEL.fetchClassOf:") , & fetchClassOf);

then external plugin don't needs interpreterProxy. All it have to do is:

fetchClassOfFnPtr = getAtomValue(makeAtom("KERNEL.fetchClassOf:"));

and to make a call it simply could use:
fetchClassOfFnPtr (foo, bar);

2. Plugin state (Hydra specific):

int stateId = makeThreadLocalAtom("BitBltPlugin.TLS", initFn, destroyFn);

and to access it:
 struct PluginState* pstate = (struct PluginState* ) getAtomValue(stateId);

and, of course we can use similar macros for it
DECLARE_STATE() / pstate(name)

so, things remain pretty same for code generation - only different macros.

3. Primitives.

Plugins at loading stage should:

- register atom "modulaName" and set its value to non-nil.
e.g.
setAtomValue(makeAtom("BitBltPlugin"), 1);
or.. we could put a version there.. not really relevant.

Trough this atom, we letting know VM that plugin is loaded , so it
shouldn't try to find/load module again.
It tries to load a module only if atom value is null.

Then, as you may suggest, primitive pointers registered by plugin into
a namespace by defining an atom names in a form:
"<moduleName>.<primitiveName>", and setting their values.

If VM encounters an unknown primitive (primitiveIndex is 0, but method
has a named primitive)
it does following:
first, checks if there is non-null atom value with given module name

   moduleLoaded = getAtomValue(makeAtom(moduleName));
   if (!moduleLoaded) ioLoadModule(...blabla)

then instead of storing a direct function pointer for given primitive,
into primitiveCache,
it puts an atom id for "<moduleName>.<primitiveName>" name.

so, that  primitiveCache[primitiveIndex] = atomId
and to get function pointer it should read it with getAtomValue().

In this way, a plugin may override primitive pointer values at run
time (by setting atom value to null or to different function),
while for VM its a simple task: before call, fetch atom value by id,
call the primitive or report failure if value is null.

Its really helpful for debugging/monitoring purposes. As i described earlier,
one plugin may override a primitive pointers of another plugin, for
collecting a different statistical information or for logging activity
etc etc.
Of course such usage introducing some risks, but as our folks says:
the one who not risking, not drinking a champagne :)

-- 
Best regards,
Igor Stasenko AKA sig.



More information about the Squeak-dev mailing list