[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
|