<div dir="ltr">Hi Denis,<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Feb 20, 2018 at 6:56 AM, Denis Kudriashov <span dir="ltr"><<a href="mailto:dionisiydk@gmail.com" target="_blank">dionisiydk@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"> <br><div dir="ltr">Hi.<div><br></div><div>It is just a question from the space :)</div><div><br></div><div>I wonder, can we be a JavaScript engine? Like replacing nodeJs with Pharo/Squeak.</div><div>I imagine that JS prototypes can be easily supported by anonymous classes. What is missing? </div></div></blockquote><div><br></div><div>Well, Vassili Bykov and I did a JavaScript implementation above VisualWorks in 2005 is.  One can do a very good job.  There are three strong ideas one can use.  The first two are Vassili's, the last is Claus Gittinger's.</div><div><br></div><div>Vassili's ideas were to </div><div>a) analyse constructors and map the accessors in constructors to inst var offsets.  If one does inst var access by property lookup (an object is a dictionary from field name to field) performance will be very poor.  If one can analyze a constructor and map each field to an inst var offset performance can be much better.</div><div><br></div><div>b) the first field of any object is the prototype slot which points to the prototype or nil.  An inst var holding nil means "unbound".  Therefore a new JavaScript object will have all its fields unbound.  To access an object's field Vassili minted special accessors, one for each offset.  They can't be written directly in Smalltalk but can be expressed using Smalltalk bytecodes.  They look like this, where instVarAt: is actually a bytecode that fetches that inst var from the receiver</div><div><br></div><div>    | current value |</div><div>    current := self.</div><div>    [current isNil ifTrue: [self error: 'field not found'].</div><div>     value := current instVarAt: N. "N is the offset of the inst var this accessor should return"</div><div>     value ~~ nil ifTrue: [^value].</div><div>     current := current instVarAt: 0] repeat</div><div><br></div><div>or in bytecode:</div><div><span class="gmail-Apple-tab-span" style="white-space:pre"><br></span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>pushReceiver<br></div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>popIntoTemp: 0<span style="white-space:pre">       </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     "set current to be the receiver"</span></div><div>L1:</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">   </span>pushTemp: N inVectorAt: 0. <span style="white-space:pre"> </span><span style="white-space:pre">     "fetch Nth field of current"</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> dup</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">    </span>pushConstant: nil <span style="white-space:pre">  </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     "if Nth field is non-nil (is bound) answer it"</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">       </span>send: ~~</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">       </span>jumpFalseTo: L2</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>returnTop</div><div>L2:</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">    </span>pop <span style="white-space:pre">        </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     "discard nil"</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>pushTemp: 0 inVectorAt: 0. <span style="white-space:pre"> </span><span style="white-space:pre">     "fetch prototype field of current"<br></span><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>dup</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">    </span>pushTemp: 0<span style="white-space:pre">  </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">"if prototype is nil, slot is not found"</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">  </span>pushConstant: nil</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">      </span>send: ==</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">       </span>jumpFalseTo: L3</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>self</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">   </span>send: errorFieldNotFound</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">       </span>pop</div><div>L3:</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">  </span>popIntoTemp: 0<span style="white-space:pre">       </span><span style="white-space:pre">     </span><span style="white-space:pre">     </span><span style="white-space:pre">     "set current to be the current's prototype"</span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">      </span>jumpTo: L1</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">     </span>returnSelf</div><div><br></div><div>    </div><div>We used a class per constructor, and were able to get performance about 4x of Netscape's VM at the time.</div><div><br></div><div>Claus' idea is to create a circular instance, an object whose class is the object itself.   The idea follows from the fact that if one has the changeClass/adoptInstance primitive one can create a prototype by creating an Array whose first three fields are laid out like a Behavior's fields, superclass/prototype, methodDictionsry, format, and whose subsequent fields are the inst vars of the object.  One then uses adoptInstance/change class primitive to change the class of the Array to itself, so that it is an instance of itself; it has its own methods in its methodDictionary, its superclass field is now the prototype.  The format field must specify a pointer object with N inst vars.  If using this scheme to implement JavaScript objects, then slot 4 (immediately after format) is probably the sot for dynamically added properties.  And of course one would implement prototype creation in a special primitive rather than using the standard adoptInstance: primitive.</div><div><br></div><div>Using tricks like these one can get reasonably high performance.  In fact, at Cadence we have a JavaScript implementation which is has evolved from Vassili's two ideas.  The implementation is in Newspeak running above the 64-bit Spur VM.</div><div><br></div><div><br></div></div><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>