<br><br><div class="gmail_quote">On Sat, Nov 22, 2008 at 9:34 AM, Igor Stasenko <span dir="ltr">&lt;<a href="mailto:siguctua@gmail.com">siguctua@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="Ih2E3d">2008/11/22 Andreas Raab &lt;<a href="mailto:andreas.raab@gmx.de">andreas.raab@gmx.de</a>&gt;:<br>
</div><div class="Ih2E3d">&gt; Igor Stasenko wrote:<br>
&gt;&gt;<br>
&gt;&gt; By more security, i meant a little feature, that since getting atom<br>
&gt;&gt; value is inexpensive operation, you can<br>
&gt;&gt; load value identified by atom and check for non-null value each time<br>
&gt;&gt; before calling function.<br>
&gt;<br>
&gt; Oh, I think you mean it can be safer to use (with which I would agree) not<br>
&gt; necessarily more secure.<br>
&gt;<br>
&gt;&gt; Old scheme, needs to check for non-null as well, but in addition you<br>
&gt;&gt; need to be careful to clean out this pointer when you get notification<br>
&gt;&gt; that module, from where you taken this pointer is unloaded.<br>
&gt;<br>
&gt; Yes. Although, you won&#39;t get around doing something about unloading either -<br>
&gt; we spent today learning about the intricacies of unloading OpenAL32.dll and<br>
&gt; it turned out to be absolutely crucial to be able to unload our own plugins.<br>
&gt; A flat shared namespace might have caused some serious issues here.<br>
&gt;<br>
</div>Almost anything &quot;might have cause some serious issues&quot;, if you don&#39;t<br>
use it wisely (Class become: nil).<br>
Its not an argument not to use it.<br>
<div class="Ih2E3d"><br>
&gt;&gt; I&#39;m not sure what you mean by per-plugin namespace.<br>
&gt;&gt; And how much difference in namespaces between this:<br>
&gt;&gt; &nbsp;bitblt = ioLoadFunctionFrom(&quot;ioBitBlt&quot;, &quot;BitBltPlugin&quot;)<br>
&gt;&gt; and this:<br>
&gt;&gt; &nbsp; atom = makeAtom(&quot;BitBltPlugin.ioBitBlt&quot;);<br>
&gt;&gt; &nbsp; bitBlt = getAtomValue(atom);<br>
&gt;&gt;<br>
&gt;&gt; The difference that first binds symbol at compile/link time, while<br>
&gt;&gt; second - at run time.<br>
&gt;<br>
&gt; It would be quite possible to bind this at runtime, too. But what I mean by<br>
&gt; per-plugin namespace is that the *export* isn&#39;t done into a flat namespace<br>
&gt; but rather into a structured one.<br>
&gt;<br>
&gt; And yes, one could conceivably use a naming scheme that is equivalent in<br>
&gt; practice but unless that&#39;s automated (the current scheme is fully automated)<br>
&gt; it seems error-prone and one of these things were people are simply too lazy<br>
&gt; in practice to utilize it correctly (if that were different I would expect<br>
&gt; people to use class and selector prefixes consistently which they don&#39;t).<br>
&gt;<br>
</div>It could be automated or used manually. Its open for any intrusion :)<br>
<div><div></div><div class="Wj3C7c"><br>
&gt;&gt; As for modularity, let me illustrate what i meant.<br>
&gt;&gt; There are many primitives in VM, which look like:<br>
&gt;&gt;<br>
&gt;&gt; primitiveFoo: x with: y<br>
&gt;&gt;<br>
&gt;&gt; ^ self cCode: &#39;ioFoo(x,y)&#39;.<br>
&gt;&gt;<br>
&gt;&gt; Obviously, when you generate this code using VMMaker, it wont compile<br>
&gt;&gt; unless you having ioFoo() function implemented somewhere.<br>
&gt;&gt; And you have a little choice where to put this implementation - in one<br>
&gt;&gt; of internal plugins or in platform-specific part of VM.<br>
&gt;&gt;<br>
&gt;&gt; Now, lets consider, if i refactor this code to use atoms (i skipping<br>
&gt;&gt; details like declarations etc) :<br>
&gt;&gt;<br>
&gt;&gt; primitiveFoo: x with: y<br>
&gt;&gt;<br>
&gt;&gt; ioFoo := getAtomValue: AtomIoFoo.<br>
&gt;&gt; ioFoo notNil ifTrue: [ ^ self cCode: &#39;ioFoo(x,y)&#39; ].<br>
&gt;&gt; ^ self primitiveFail.<br>
&gt;&gt;<br>
&gt;&gt; 1. the code will compile regardless i declared a function or not.<br>
&gt;&gt; 2. i&#39;m free in choice where to put the implementation of this<br>
&gt;&gt; function, or even build VM initially w/o this function.<br>
&gt;&gt; 3. across different platforms, one can use same VMMaker to generate<br>
&gt;&gt; sources , and it will always compile &amp; link.<br>
&gt;&gt;<br>
&gt;&gt; doesn&#39;t it look like more modular?<br>
&gt;<br>
&gt; No. It looks utterly pointless to me. You introduce a plugin that does<br>
&gt; nothing but looking up and call an atom; what good is that plugin? If you<br>
&gt; generalize that just a little you have the FFI where you might declare<br>
&gt; ioFoo() directly and call it. Which of course could be done via atom table<br>
&gt; too, but I still fail to see how that would be more modular.<br>
&gt;<br>
<br>
</div></div>Not a plugin. I mentioned VM code in interp.c. I see little need in<br>
having such constructs in plugin.<br>
In VM core, however, there is always a bit of uncertainty - VM forced<br>
to provide primitive by default (because its a standart one), but on<br>
different platforms, depending on their capabilities or your intent,<br>
you may omit putting functionality of some primitives into VM.<br>
This is where such scheme is can be quite useful - instead of stubbing<br>
function in sources, or exploring what function has to return to make<br>
primitive fail , just remove it from build.<br>
<div class="Ih2E3d"><br>
&gt;&gt; Now, take a look at a sqWin32Stubs.c - how it would look if we would<br>
&gt;&gt; use shared namespace? It would look as zero length file.<br>
&gt;&gt; Because all we have to do in platform code is just initialize pointers:<br>
&gt;&gt;<br>
&gt;&gt; pointers = {<br>
&gt;&gt; &nbsp;&quot;ioFoo&quot; , ioFoo<br>
&gt;&gt; #ifdef NO_SOME_STUFF<br>
&gt;&gt; &nbsp;&quot;ioBar&quot; , ioBar<br>
&gt;&gt; #endif<br>
&gt;&gt; &nbsp;...<br>
&gt;&gt; };<br>
&gt;<br>
&gt; And if you stick this in sqWin32Stubs.c (or its equivalent) you end up with<br>
&gt; a non-empty stubs file. In other words, you are replacing one set of stubs<br>
&gt; with another one. Not much of an improvement.<br>
&gt;<br>
<br>
</div>Its not the same thing. Currently you have to define a function - with<br>
implementation or with empty body to make compiler content.<br>
In example i showed - you can do simpler - just omit binding a<br>
function to a symbol.<br>
Suppose we having a well structured organization of VM platform<br>
sources, &nbsp;then it might look like:<br>
<br>
#ifdef SUPPORT_FILES<br>
#include &quot;file_functions.inc&quot;<br>
/// or put all functions here w/o using #include<br>
#endif<br>
<br>
instead of something like:<br>
<br>
#ifdef SUPPORT_FILES<br>
#include &quot;file_functions.inc&quot;<br>
/// or put all functions here w/o using #include<br>
#else<br>
#include &quot;file_functions_stubs.inc&quot;<br>
#endif<br>
<div class="Ih2E3d"><br>
&gt;&gt; I&#39;m currently trying to make a HostWindowsPlugin and want to put all<br>
&gt;&gt; windowing and i/o stuff in it from VM platform sources.<br>
&gt;<br>
&gt; Why do another one? Is there something that the current host window plugin<br>
&gt; doesn&#39;t address?<br>
<br>
</div>Well, there&#39;s many things.<br>
Don&#39;t want to OT here, just simple example: when image fires up, i<br>
want to show a splash screen, and then, when user clicks on it, or<br>
some time passed , hide it and show the &quot;main&quot; window. ALL is<br>
controlled from image, of course , e.g. one might want to show splash<br>
screen and when user clicks on it - just quit the squeak :)<br>
<div class="Ih2E3d"><br>
&gt;<br>
&gt;&gt; It would be much a cut&#39;n&#39;paste experience to me, if all callouts in VM<br>
&gt;&gt; would use atoms - because then i don&#39;t need to touch headers &amp; sources<br>
&gt;&gt; and many different places to make compiler content. Because there<br>
&gt;&gt; would be no need in exporting function in C-like manner.<br>
&gt;<br>
&gt; Ah. But that&#39;s a fallacy. That you don&#39;t need to &quot;touch&quot; these places<br>
&gt; doesn&#39;t mean you don&#39;t need to know about them. In fact, having to touch<br>
&gt; them, having the compiler complain about them is a great way to learn and<br>
&gt; know and understand all the areas you need to touch - if the VM would<br>
&gt; randomly crash on you because you have replaced one but not another function<br>
&gt; you&#39;d be in for a hellish experience. Yes, the C compiler can be notorious<br>
&gt; but it can also be a pretty good teacher.<br>
&gt;<br>
<br>
</div>The same self-fallacy is to be confident, that if your code compiles<br>
ok it doesn&#39;t crash in some random place :)<br>
<div><div></div><div class="Wj3C7c"><br>
&gt;&gt; And lastly, remember InterpreterProxy thing? Each time you want to<br>
&gt;&gt; introduce new functionality , you have to extend the structure and<br>
&gt;&gt; increase version number. But what is it? Its just a list of pointers!<br>
&gt;<br>
&gt; No, it&#39;s not. It&#39;s an interface (a contract) between the VM and the plugin.<br>
&gt;<br>
&gt;&gt; Isn&#39;t it would be simpler for plugin to just lookup a function by its<br>
&gt;&gt; name - and use it if such function exists. Its pretty much same as<br>
&gt;&gt; dynamic linking, just s/dlsym/getAtomValue/ and don&#39;t let your code be<br>
&gt;&gt; constrained by compiler/linker anymore :)<br>
&gt;<br>
&gt; I *very much* doubt that it would be simpler for each plugin to look up the<br>
&gt; function every time they use it and test for its existence every time it is<br>
&gt; used. Consider this primitive:<br>
&gt;<br>
&gt; primitiveStringClone<br>
&gt; &nbsp;interpreterProxy methodArgument = 1<br>
&gt; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;arg := interpreterProxy stackValue: 0.<br>
&gt; &nbsp;(interpreterProxy isBytes: arg)<br>
&gt; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;clone := interpreterProxy clone: arg.<br>
&gt; &nbsp;interpreterProxy pop: 2.<br>
&gt; &nbsp;interpreterProxy push: clone.<br>
&gt;<br>
&gt; Now let&#39;s rewrite this in pseudo-code to see what it would look like without<br>
&gt; an interface:<br>
&gt;<br>
&gt; primitiveStringClone<br>
&gt; &nbsp;((interpreterProxy has: #methodArgumentCount)<br>
&gt; &nbsp; &nbsp;and:[interpreterProxy methodArgument = 1])<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;(interpreterProxy has: #stackValue)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;arg := interpreterProxy stackValue: 0.<br>
&gt; &nbsp;(interpreterProxy has: #isBytes)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;(interpreterProxy isBytes: arg)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;(interpreterProxy has: #clone)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;clone := interpreterProxy clone: arg.<br>
&gt; &nbsp;(interpreterProxy has: #pop)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;interpreterProxy pop: 2.<br>
&gt; &nbsp;(interpreterProxy has: #push)<br>
&gt; &nbsp; &nbsp; &nbsp;ifFalse:[^interpreterProxy primitiveFail].<br>
&gt; &nbsp;interpreterProxy push: clone.<br>
&gt;<br>
&gt;<br>
&gt; Simpler? You&#39;ve got to be kidding me ;-)<br>
&gt;<br>
<br>
</div></div>This counter-example missing a point :)<br>
Take a look at Hydra code, where InterpreterProxy has left with only 3<br>
functions, and will stay to have 3 functions forever without need in<br>
extending protocol , because rest functions is obtained dynamicaly<br>
using name lookup.<br>
A plugin simply refuse to start without having all requested VM<br>
functions be non-null. But the trick is, that VM not forced anymore to<br>
support obsolete stuff of ever-growing InterpreterProxy protocol.</blockquote><div><br></div><div>I like this very much. &nbsp;Not totally, just very much :)</div><div><br></div><div>What&#39;s good here is that the plugin can access functions directly in the VM and not go through the slow interpreterProxy. &nbsp;Because C supports syntax for calls through function pointers that looks just like normal functions calls wouldn&#39;t look very different to normal calls. &nbsp;The function pointers simply need to be decared.</div>
<div><br></div><div>But what I don&#39;t like is having interpreterProxy persist at all. Why not get rid of it except for initialization and pass it in through setInterpreter? &nbsp;What do you need interpreterProxy to persist for?</div>
<div><br></div><div>So Slang generates a standard prolog for all the functions used in a plugin at the beginning of the file (nice documentation; lists exactly the functions the plugin uses). &nbsp;setInterpreter (better called initializePlugin?) takes an argument that provides a function to lookup function pointers by name. &nbsp;Slang generates the code to initialize these fnction pointers. &nbsp;Uses of the function pointers look just like normal calls.</div>
<div><br></div><div>Then internal plugins can be linked directly against the VM. &nbsp;e.g.</div><div><br></div><div><br></div><div>#if EXTERNAL_PLUGIN</div><div>static void (*popthenPush(sqInt,sqInt);</div><div>static void (*primitiveFailed)(void);</div>
<div>#endif</div><div>...</div><div>void somePrimitive()</div><div>{</div><div>&nbsp;&nbsp; &nbsp;....</div><div>&nbsp;&nbsp; &nbsp;if (!ok) {</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;primitiveFailed();</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return;</div><div>&nbsp;&nbsp; &nbsp;}</div><div>&nbsp;&nbsp; &nbsp;popthenPush(result);</div>
<div>}</div><div>...</div><div><div>#if EXTERNAL_PLUGIN</div></div><div>static sqInt</div><div>setInterpreter(InterpreterProxy *interpreterProxy)</div><div>{</div><div>&nbsp;&nbsp; &nbsp;if (interpreterProxy.oopSize() != 4)</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return InitErrorWrongOopSize;</div>
<div>&nbsp;&nbsp; &nbsp;if (!interpreterProxy.getFunction(&quot;popthenPush&quot;, &amp;popthenPush)</div><div>&nbsp;&nbsp; &nbsp; ||&nbsp;!interpreterProxy.getFunction(&quot;primitiveFailed&quot;, &amp;&nbsp;primitiveFailed))</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return InitErrorMissingFunction;</div>
<div>&nbsp;&nbsp; &nbsp;return 0;</div><div>}</div><div>#endif /*&nbsp;EXTERNAL_PLUGIN */</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br>
<div><div></div><div class="Wj3C7c"><br>
&gt; Cheers,<br>
&gt; &nbsp;- Andreas<br>
&gt;<br>
<br>
<br>
--<br>
Best regards,<br>
Igor Stasenko AKA sig.<br>
<br>
</div></div></blockquote></div><br>