tag:blogger.com,1999:blog-7749593033009014712024-03-14T01:03:23.099-07:00Computer adventuressighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-774959303300901471.post-41601918439725545382009-05-02T16:35:00.000-07:002009-05-02T16:40:25.788-07:00Moving to better placeAfter trying a wordpress (as a member of Squeak Board, we now running a blog) i found that wordpress is much more convenient and having better functionality, especially for editing & organizing stuff. Good bye hotspot, wellcome <a href="http://computeradventures.wordpress.com">computeradventures.wordpress.com</a>sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com44tag:blogger.com,1999:blog-774959303300901471.post-67614921320590413072008-09-02T19:33:00.000-07:002008-09-02T19:40:03.430-07:00New name for CorruptVMWe had vote choosing more appropriate name for CorruptVM , and name Moebius wins.<br />The project registered on <a href="http://code.google.com/p/moebius-st/">http://code.google.com/p/moebius-st/</a> and i put some wiki pages there. <br />Also there is a discussion group is on <a href="http://groups.google.com.ua/group/moebius-project-discussion">http://groups.google.com.ua/group/moebius-project-discussion</a><br /><br />Feel free to join.sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com0tag:blogger.com,1999:blog-774959303300901471.post-22522999336207161962008-05-25T00:00:00.000-07:002008-05-25T00:21:26.476-07:00Got first bootstrapped object memory of CorruptVMToday, for the first time, i able to create an initial object memory of CorruptVM.<br /><br />A bootstrap procedure includes creating instances of vtables and compiling methods in simulated memory block.<br /><br />A bootstrapped memory contains 75 compiled methods and 17 classes. <br />The memory footprint is about 6K bytes.<br /><br />It will be much larger, if compiled methods would contain code.<br />But simulator, instead of putting a real machine code in method instance, puts 4 byte index, which is an index in simulator's method table where it holding lambdas of each compiled method.<br /><br />Native methods feature set is about complete. <br />This means that native method can be executed and should work as it was defined.<br /><br />ST methods compiling still lacking support of block closures & global names lookup semantics. Currently i stub block literals with nils.sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com29tag:blogger.com,1999:blog-774959303300901471.post-60641504594950824902008-04-28T23:47:00.000-07:002008-04-29T00:17:12.893-07:00Revised view of native code generatorEarlier, in my previous posts about ASM-generator i made something which can be used in practice, but still lacks of fundamental point: the VM support.<br />A new idea was born: since everything can be compiled down to native code, why we need to use C at all? I started things from the scratch and came up with new design of system where everything will be dynamically compiled and residing in object memory.<br /><br />Here is some features of new meta-circular VM:<br /><br />- all functionality, what we know as 'VM' will become a part of object memory with own classes and methods. <br /><br />- for starting an image you will need a tiny bootstrapper written in C which mainly serves as image loader and provides basic compatibility layer with few OS-specific functions required to bootstrap VM. For calling C functions from VM there will be FFI layer, which should be used by any parts of system which require external libraries or OS-specific functions. <br /><br />- there is no 'primitives' as in another ST implementations. All methods are compiled down to native code. For writing a low-level code, there is a special methods in native format. As with ASM-generator, in native methods you operating with machine registers/values , not with real objects, which allows you to implement almost anything from scratch, without writing a single line of C code.<br /><br />Watch for the updates at wiki page:<br /><a href="http://wiki.squeak.org/squeak/6041">http://wiki.squeak.org/squeak/6041</a>sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com1tag:blogger.com,1999:blog-774959303300901471.post-36756703410035070362008-02-20T06:03:00.000-08:002008-02-20T06:09:51.911-08:00Keeping this blog up to dateDuring last months i was enjoyed with hacking a Squeak VM.<br />A new project, with codename Hydra VM is a rewrite of smalltalk interpreter to support multiple instances of interpreter, running in parallel using separate native threads.<br />You can read more about it here: <a href="http://squeakvm.org/%7Esig/hydravm/devnotes.html">http://squeakvm.org/~sig/hydravm/devnotes.html</a><br /><br /><br />There are some bugs which currently make some annoyance. But in overall, a HydraVM is surprisingly stable!sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com8tag:blogger.com,1999:blog-774959303300901471.post-64318601537388657432007-08-12T18:04:00.000-07:002007-08-12T20:52:25.541-07:00Multi-threaded message passing schemeMany smalltalk implementations lack of effective native threading support. And in rising era of multi-core CPUs something must be done to fill this gap.<br /><br />The following model based on message passing threading. Any language, which based on message-passing can use such model.<br /><br />What we need to know about objects?<br />- objects is a state, stored at some memory location. To interact with objects we send them a messages. A semantics, how message sent is under total control of the VM. To make object answer messages, developer defines methods, which can access receiver's state and can use this state to evaluate return result. Methods can also send messages to other objects and use their evaluation result for own needs.<br /><br />To make safe use of native threads we need to define following restrictions:<br />- for any unique object in system only single method can access it's contents at single point of time.<br /><br />Lets examine the structure of typical method evaluation scheme in message-passing language implementation:<br />1. lookup method for given message and receiver<br />2. enter method<br />3. evaluate result<br />4. exit method, return result<br /><br />A result evaluation can be divided in steps consisting of following categories:<br />- manipulate receiver's contents<br />- send messages to other objects<br /><br />Our goal is to prevent running two or more methods which access object contents at same point of time.<br />To ensure, that no other thread can manipulate receiver's contents we must mark receiver object as busy and make it free when we done manipulating.<br />For this, we must add a field, named 'busy' for each object in system. Object considered busy when some method accessing it's state and free if no methods currently accessing it's state.<br />Make note, that when we sending message to other object from within current method, we don't need to keep receiver object marked as busy, since we stop manipulating it's contents and waiting for return from other method.<br /><br />But 'busy' property introduces too much overhead:<br />- to enter 'manipulation step' thread must check if receiver object is currently marked as busy and wait when it becomes free, then mark it as busy, perform manipulation and mark as free at the end.<br />Since such steps is rather atomic and performed with high frequency in running system, a locking/unlocking mechanism introduces too much overhead.<br /><br />To avoid this i propose to use message queuing approach:<br />- messages instead of sent directly, are enqueued.<br />- a worker thread polls queue and enters enqueued method context to evaluate result.<br />- every object in system, instead of having 'busy' property, holds an active context reference, which, if not nil, indicates that object already take part in other method evaluation.<br /><br />A typical worker thread is running on the following scheme:<br /><br />1. fetch message context from queue<br />2. activate context (start/continue evaluating a method)<br /><br /> - when sending message from active context do following:<ul><li>lookup for method of receiver</li><li>create new method context, set its parent to current<br /></li><li>check receiver's active context </li><li>if receiver's active context is nil, choose thread which will be responsible for evaluating a message, set new context owner to chosen thread, set object's context to new context(write barrier).</li><li>if receiver's active context is not nil, set new context owner to same owner of receiver's active context<br /></li><li>enqueue context to queue of its owner</li><li>deactivate current context</li></ul> - when returning from method <ul><li>store return result in parent context</li><li>if receiver's active context same as current context, set it to nil (no write barrier)</li><li>destroy current context</li><li>enqueue parent context to its owner thread queue<br /></li></ul>3. goto step 1.<br /><br />When thread queue is empty, thread is going to sleep, and wait for activation by different thread, or can be recycled.<br />For choosing new context owner thread a thread which creates new context can check if its own queue is non-empty (a more messages is pending to evaluate), and if so, pass ownership of new context to one of the sleeping threads or allocate new thread if its own queue grown too big.<br /><br />Memory management/Garbage collector.<br /><br />How GC must act in such environment?<br />A general principles is clear enough: collect garbage fast and effectively, without system wide locks.sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com129tag:blogger.com,1999:blog-774959303300901471.post-72987751702552586702007-07-18T07:54:00.000-07:002007-07-18T09:09:20.614-07:00Asm-generator continued...I decided to integrate assembler generator with standard smalltalk parser/compiler, so devs can use common tools to submit asm-code.<br /><br />To indicate that method source contains assembler source, just put <span style="font-style: italic;"><assembler></span> pragma in its source body. This activates an asm-parser, and if parser found errors, it shows them in same manner, as smalltalk parser - by inserting error message at corresponding place in edit buffer.<br /><br />The one good reason, why i decided to integrate parser with system browser is for automation:<br />- when you submitting asm code, its parsed, compiled and ready for execution by registering it with Exupery. So, in most cases, you don't need to make any extra moves - just edit and submit.<br />- if method have inline calls to other methods, they automatically parsed (if was not parsed before) to include in compiled code.<br />- when you submitting new source for method, which was inlined in other methods, this automatically causes to recompile them using new code.<br /><br />So, after successful submission, new versions of native methods automatically get used (if they already was).<br /><br />I also decided to slightly modify syntax of asm-code.<br /><br /><span style="font-weight: bold;">Changed flow control syntax. </span><br /><br />Now, instead of smalltalk-like flow control, which implies to use blocks, you have labels and jumps.<br /><br />So, instead of writing something like:<br /><br /><span style="font-style: italic;">ifZero: [ ... ]</span><br /><br />you placing a label in code:<br /><br /><span style="font-style: italic;">self label: #somelabel.</span><br /><br />then from at other point in code you placing jumps on it:<br /><br /><span style="font-style: italic;">self jump: #somelabel.</span><br /><br />or<br /><br /><span style="font-style: italic;">self jumpCarry: #somelabel.</span><br /><br />Labels and jumps must be the outermost messages (can't be passed as arguments to other messages).<br />Writing something like:<br /><span style="font-style: italic;"><br />a := b + (self label: #somelabel).</span><br /><br />is not an error in smalltalk, but error in assembler.<br /><br />Later i'll add support for <span style="font-weight: bold;">calls on label</span><br />( self call: #somelabel )<br />so, you can write methods like:<br /><br /><span style="font-style: italic;">....</span><br /><span style="font-style: italic;">self call: #somelabel</span><br /><span style="font-style: italic;">....</span><br /><span style="font-style: italic;">....</span><br /><span style="font-style: italic;">self return: result.</span><br /><span style="font-style: italic;">self label: #somelabel</span><br /><span style="font-style: italic;">result := 1.</span><br /><span style="font-style: italic;">self ret.</span><br /><br /><span style="font-weight: bold;">loading address of label</span> in register ( a := #somelabel),<br />and <span style="font-weight: bold;">indirect jumps/calls</span>: self call: a<br /><br /><span style="font-weight: bold;">global labels:</span><br /><br /><span style="font-style: italic;">method1</span><br /><br /><span style="font-style: italic;"> self globalLabel: #globalOne</span><br /><span style="font-style: italic;"> self ret.</span><br /><br />--<br /><span style="font-style: italic;">method2</span><br /><span style="font-style: italic;"> ^ self call: #globalOne</span><br /><br /><span style="font-weight: bold;">jump tables :<br /></span><br /><span style="font-style: italic;">self jumpTable: #table1 with: #(<br /> #label1<br /> #label2<br /> #label3<br />)</span><br /><span style="font-weight: bold;">....<br /></span><br />addr := (#table1 + index) loadDword.<br /><span style="font-style: italic;">self jump: addr.<br /><br />or maybe like this:<br />self jump: (#table1 at: index)<br /></span><br /><span style="font-weight: bold;">global data storage :</span><br /><br /><span style="font-style: italic;"> self dataDWord: #mydwords size: 10.</span><br /><span style="font-style: italic;"></span><br /><span style="font-style: italic;"> a:= (#mydwords + 5) loadDWord.</span><br /><br /><br />accessing VM values:<br /><br /><span style="font-style: italic;"> a:= self VMAddr: #someName</span><br /><br />or just:<br /><br /><span style="font-style: italic;"> a := #someName</span><br /><br />or<br /><br /><span style="font-style: italic;"> self call: #someVmFunction</span><br /><br />i didn't decided yet, mix VM global names with own global labels/data or not.<br />Maybe someone have some better ideas?sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com0tag:blogger.com,1999:blog-774959303300901471.post-75191868381334143352007-05-07T01:41:00.000-07:002007-05-07T02:44:43.618-07:00Everything is a Register!My explo<s>it</s><u>r</u>ation of <a href="http://www.squeaksource.com/Exupery">Exupery</a> brings some fruits - an assembler generator using smalltalk syntax.<br />I don't know how this package might be useful - you decide.<br />I'm just make it accessible for potential users.<br /><br />Generator takes a given method source code (not bytecode) and transforms it to pure asm instructions (with help of Exupery).<br />The way its done is like what <a href="http://www.squeaksource.com/VMMaker">VMMaker</a> does, which also parses a method and creates it analogue in C.<br /><br />Take a look at sample asm program:<br /><blockquote><code><br />message3<br />| a b c |<br />c := 1.<br />b := 2.<br />(b + c) ifLess: [<br />a := 5.<br />(b - 1) ifZero: [ a := 10 ]<br />].<br />^ a<br /></code></blockquote>First thing to remember: everything is a <u>register</u> not an object!<br />You allowed to assign them, return , make ariphmetic/logical ops.<br />The control flow selectors is based on processor flags (so using ifTrue/IfFalse is pointless here and will lead to DNU). All set of selectors you can find in #AsmSelectors<br /><br />The example given before produces a following immediate form:<br /><code></code><blockquote><code><br />#(#(#block 1<br /> #(#mov 1 't2')<br /> #(#mov 2 't3')<br /> #(#add 't3' 't2')<br /> #(#jge #block5))<br /> #(#block 2<br /> #(#mov 5 't1')<br /> #(#sub 't3' 1)<br /> #(#jnz #block4))<br /> #(#block 3<br /> #(#mov #(#mov 10 't1') 't5'))<br />#(#block 4<br /> #(#mov 't5' 't4'))<br /> #(#block 5<br /> #(#return 't1')))<br /></code></blockquote>It then can be processed furter with Exupery with optimization/registers allocation to get a ready to run assembler code.<br /><br />I plan to add support to far calls and inlining (which is easiest part).<br />The call (and any special instruction) started from self as receiver.<br /><br />I plan to add following:<br /><br /> <span style="font-style: italic;"> self pragma: #inline</span><br /><span style="font-style: italic;"> self pragma: #cdecl</span><br /> <span style="font-style: italic;"> self pragma: #apicall<br /><br /></span> - to indicate which prologue/epilogue generate for function. <span style="font-style: italic;">#inline</span> can be compiled as standalone function only in case if you do not have any parameters on it (unary selector).<br /><br /> <span style="font-style: italic;">self call: #selector:with:with with: .. with: .. ... </span><br /><br />- this one for local call of a function which must be present in same class, where parsed method resides. It can be inlined if you put self pragma: #inline in source<br /><br /> self inlinecall: <span style="font-style: italic;">#selector:with:with with: .. with: .. ...<br /><br /></span>- same as above, but forcing inline.<span style="font-style: italic;"><br /></span><br /> self callC: <span style="font-style: italic;">#selector:with:with with: .. with: .. ... </span><br /> self callApi: <span style="font-style: italic;">#selector:with:with with: .. with: .. ... </span><br /><br />- this one for external calls using appropriate calling convention far beyond the squeak :) You must register an Integer address for given selector in dictionary of external selectors.<br /><br />A potential use of this stuff is a callbacks. I'm not decided yet how to hook with VM (some advice with Bryce is needed) , but i think that can be solved in elegant manner.<br />Also, i have pervasive intentions to allow hot-swapping a core VM routines, so VM will recompile itself without knowing about it :)<br /><br />And moreover, in some far future i might want that <span style="font-weight: bold;">full</span> C source of VM will look like following:<br /> int main(...)<br /> {<br /> buf = loadImage();<br /> (void fn*) = buf->entryPoint;<br /><br /> return fn();<br /> }sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com0tag:blogger.com,1999:blog-774959303300901471.post-69054163828802917582007-04-26T18:29:00.000-07:002007-04-26T18:51:04.485-07:00My first blog and my first entry.This is screenshots of my current works on GLCanvas, to make OpenGL be the workhorse for squeak.<br /><br />This is an image what produces squeak by default:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixQZoZprPtQ1l_-ZmmmvsvokUf3PVv-0b7DbUIu3Kmp1Fm3fhCA14XY3AvJllKVcCtPVHd4fF713j4aeA3C-DI93aHz5-vL3m-chfRClgewRfYnNUozAgv7wOH90UKdn6atNAQwdGe5iv_/s1600-h/blitted.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixQZoZprPtQ1l_-ZmmmvsvokUf3PVv-0b7DbUIu3Kmp1Fm3fhCA14XY3AvJllKVcCtPVHd4fF713j4aeA3C-DI93aHz5-vL3m-chfRClgewRfYnNUozAgv7wOH90UKdn6atNAQwdGe5iv_/s320/blitted.png" alt="" id="BLOGGER_PHOTO_ID_5057916240554035778" border="0" /></a><br />This is same same one, but with OpenGL activated:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs6-_dvndVsmkz8PlVcaqjvoZN1B0VsAeEFMxVJBaUv5ic4fdOYHDgxUDIvg-pJfXh8LLdPL0vbXHK4Pmw7n-w6nzaD4mNX1J5bktQrGJ_YFHqRqpN6qkSQrHXpB3Aau_7IAv6bI4yjORi/s1600-h/gl.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs6-_dvndVsmkz8PlVcaqjvoZN1B0VsAeEFMxVJBaUv5ic4fdOYHDgxUDIvg-pJfXh8LLdPL0vbXHK4Pmw7n-w6nzaD4mNX1J5bktQrGJ_YFHqRqpN6qkSQrHXpB3Aau_7IAv6bI4yjORi/s320/gl.png" alt="" id="BLOGGER_PHOTO_ID_5057916794604816978" border="0" /></a>as you can see, all things looks like same except that i don't draw gradients (i'll code them later when everything else will work fine).<br />At screenshot you can see time in ms which takes to draw full world with and without OpenGL support.<br />The main bottleneck of drawing stuff is displaying text and clipping (with clipping turned off it takes 3 times faster in OpenGL).sighttp://www.blogger.com/profile/05011250942130102144noreply@blogger.com4