<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1934327362352050331</id><updated>2012-02-16T09:31:58.169-08:00</updated><category term='interpreter'/><category term='general'/><category term='axioms'/><title type='text'>Shared Nothing Arc Processes: the Virtual Machine</title><subtitle type='html'>&lt;a href="http://snapvm.blogspot.com/2008/07/shared-nothing-arc-processes.html"&gt;&lt;u&gt;SNAP&lt;/u&gt;&lt;/a&gt; is a new virtual machine designed for a massively multiprocess message-passing version of arc.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-4101652676498169681</id><published>2008-10-31T08:35:00.000-07:00</published><updated>2008-11-22T03:52:58.263-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>DROPPED</title><content type='html'>&lt;h1&gt;SNAP Dropped!&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;As of now, I am dropping support for SNAP, as well as the tangentially related project Arc-F.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However, not all is lost; the ideas behind SNAP and Arc-F will make it into a new Lisplike language, "hl" &lt;a href='http://hl-language.blogspot.com/'&gt;(blog)&lt;/a&gt;.  I will retain this blog for reference and archiving.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Basically, hl will be a merging of the runtime VM of SNAP with the slightly-different build of Arc-F (such as multimethods and packages, as well as a revamped sequence/scanner handling and base functions).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Stefano Dissegna will be helping me with hl, but I would like to also invite others who are curious to contribute.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-4101652676498169681?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/4101652676498169681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=4101652676498169681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/4101652676498169681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/4101652676498169681'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/10/dropped.html' title='DROPPED'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-274313526217105346</id><published>2008-08-30T04:01:00.000-07:00</published><updated>2008-09-01T05:46:58.183-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interpreter'/><title type='text'>Interlude: the LIFO heap</title><content type='html'>&lt;p&gt;&lt;small&gt;(i feel obligated to also give an update on the i/o subsystem first; i currently have a small basic core for the central i/o process, and am now trying to grok the c++ interface of &lt;a href='http://software.schmorp.de/pkg/libev.html'&gt;libev&lt;/a&gt;.  i implemented this bit of optimization to the machine &lt;a href='http://github.com/AmkG/snap/commit/d4ac6b63a731db2eb63db5447e22c07a2097dda6'&gt;some time ago&lt;/a&gt;)&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As I mentioned in the follow-up to the &lt;a href='http://snapvm.blogspot.com/2008/07/continuation-closures.html'&gt;post regarding continuation closures&lt;/a&gt;, one thing pointed out in the &lt;a href='http://use.perl.org/~chromatic/journal/36509?from=rss'&gt;linked Parrot article, "What C's Memory Management Gets Rightish",&lt;/a&gt; is that a stack-like allocator for call frames helps tremendously in easing the pressure in the garbage collector, since usually (barring &lt;code&gt;call/cc&lt;/code&gt;) the lifetime of call frames &lt;i&gt;is&lt;/i&gt; a stack.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, since at least one stated goal of SNAP is to have a reasonably efficient system, I decided to implement this optimization.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;small&gt;(it is of course a valid concern that i'm doing an optimization when i have no real performance data for this particular virtual machine, and in particular since the machine &lt;a href='http://snapvm.blogspot.com/2008/08/update-io.html'&gt;doesn't even have i/o yet&lt;/a&gt;, but this is from a post from someone who appears to be a developer for &lt;a href='http://www.parrotcode.org/'&gt;parrot&lt;/a&gt;, which is quite well developed; their opinion thus counts quite a bit.)&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;A LIFO Heap&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;...is of course a stack.  Like any stack it keeps track of the current "position" using a stack pointer, and like any stack, items can be pushed onto it and popped off.  Of course, the items here are variable-length items (since some closures are inevitably larger than others), but that is a trivial detail.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Note however that our stack structure is special: it has to be garbage-collectible together with the rest of the heap.  This is largely because it was developed after the main garbage collection algorithms, and it's easier to just let it be garbage-collectible so that we don't have to add special cases.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The Arc process type inherits from the &lt;code&gt;Heap&lt;/code&gt; class.  All Arc objects normally belong to a single &lt;code&gt;Heap&lt;/code&gt;, i.e. belong to a single process.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Each &lt;code&gt;Heap&lt;/code&gt; object handles one "main" memory area, represented by a &lt;code&gt;Semispace&lt;/code&gt; class.  A &lt;code&gt;Heap&lt;/code&gt; object might actually have several &lt;code&gt;Semispace&lt;/code&gt;s; this is because, when a process sends a message, it copies the data structure into a new &lt;code&gt;Semispace&lt;/code&gt; and then sends the entire &lt;code&gt;Semispace&lt;/code&gt; to the receiving process.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When data is allocated on a &lt;code&gt;Heap&lt;/code&gt;, it actually just allocates from its &lt;i&gt;main&lt;/i&gt; &lt;code&gt;Semispace&lt;/code&gt;, if there is still space available on it.  The &lt;code&gt;Semispace&lt;/code&gt; allocation is very simple: it simply increments a pointer and returns the previous value.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When the &lt;code&gt;Heap&lt;/code&gt; object decides to perform a garbage collection, it sums up the size of the main &lt;code&gt;Semispace&lt;/code&gt; and all received &lt;code&gt;Semispace&lt;/code&gt;s, then creates a new &lt;code&gt;Semispace&lt;/code&gt; to hold the data.  It then copies the live data into the new &lt;code&gt;Semispace&lt;/code&gt;, which becomes the main &lt;code&gt;Semispace&lt;/code&gt; afterwards.  The Semispace may be resized if it turns out to be much, much larger than the actual live data.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Normally, memory allocation is done via the &lt;code&gt;Heap&lt;/code&gt; objects:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;Heap&amp;amp; hp = proc;&lt;br&gt;.&lt;br&gt;.&lt;br&gt;.&lt;br&gt;Generic* gp = new(hp) Cons();&lt;br&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;new&lt;/code&gt; operator simply ends up invoking an &lt;code&gt;alloc()&lt;/code&gt; member on the &lt;code&gt;Heap&lt;/code&gt; objects.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Although a valid syntax using &lt;code&gt;Semispace&lt;/code&gt; references also exists, it is generally used only by the &lt;code&gt;Heap&lt;/code&gt; objects.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;A LIFO &lt;code&gt;Semispace&lt;/code&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;For this optimization, however, we needed to have an additional kind of &lt;code&gt;Semispace&lt;/code&gt;, called the &lt;code&gt;LifoSemispace&lt;/code&gt;. &lt;small&gt;(it could actually have been the same type as &lt;code&gt;Semispace&lt;/code&gt; but that class was designed before i put this optimization up, so there were some bits of it that were inappropriate)&lt;/small&gt; The &lt;code&gt;LifoSemispace&lt;/code&gt; does not have any inheritance relationship to the &lt;code&gt;Semispace&lt;/code&gt; type at all, although it does have a similar set of methods.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;Semispace&lt;/code&gt; object supports only deallocating the most recently allocated memory area &lt;small&gt;(this is necessary in case of a thrown exception in the constructor)&lt;/small&gt;.  However, the &lt;code&gt;LifoSemispace&lt;/code&gt; allows deallocating, in reverse order, of &lt;i&gt;all&lt;/i&gt; objects allocated on it.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;And a LIFO &lt;i&gt;aspect&lt;/i&gt; of the &lt;code&gt;Heap&lt;/code&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;A &lt;code&gt;LifoSemispace&lt;/code&gt;, of course, does not just float around: it's handled by a &lt;code&gt;Heap&lt;/code&gt; object.  We don't directly allocate on a &lt;code&gt;LifoSemispace&lt;/code&gt;, in much the same way that we don't normally directly allocate on a &lt;code&gt;Semispace&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This &lt;i&gt;does&lt;/i&gt; have the minor problem that the nice &lt;code&gt;new(hp)&lt;/code&gt; syntax is already taken.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To handle this, we introduce a new class, the &lt;code&gt;LifoHeap&lt;/code&gt;.  This class is composed of a single pointer to a &lt;code&gt;Heap&lt;/code&gt;, and is constructed from a pointer to &lt;code&gt;Heap&lt;/code&gt;.  It is thus as lightweight as a reference to a &lt;code&gt;Heap&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;Heap&lt;/code&gt; now also provides a &lt;code&gt;lifo()&lt;/code&gt; member function, which returns a &lt;code&gt;LifoHeap&lt;/code&gt; from the &lt;code&gt;this&lt;/code&gt; pointer.  In order to allocate from a &lt;code&gt;Heap&lt;/code&gt;'s LIFO allocation area, we simply use &lt;code&gt;new(hp.lifo())&lt;/code&gt;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;Heap&amp;amp; hp = proc;&lt;br&gt;.&lt;br&gt;.&lt;br&gt;.&lt;br&gt;Generic* gp = new(hp.lifo()) ClosureArray&lt;Closure, 2&gt;();&lt;br&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;h2&gt;First.... Out!&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;LifoHeap&lt;/code&gt; object also provides a &lt;code&gt;normal_dealloc(...)&lt;/code&gt; member function.  This member attempts to deallocate the specified &lt;code&gt;Generic&lt;/code&gt; object, if it happens to be &lt;b&gt;1)&lt;/b&gt; allocated on the &lt;code&gt;LifoHeap&lt;/code&gt; and &lt;b&gt;2)&lt;/b&gt; is the most recently allocated object on the &lt;code&gt;LifoHeap&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This function will silently fail if the two conditions above are not met.  Since objects on LIFO allocation are still subject to garbage collection, a failed deallocation is still OK: the memory space will simply be reclaimed automatically.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-274313526217105346?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/274313526217105346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=274313526217105346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/274313526217105346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/274313526217105346'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/08/interlude-lifo-heap.html' title='Interlude: the LIFO heap'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-7537965213651759193</id><published>2008-08-27T01:11:00.000-07:00</published><updated>2008-08-28T02:29:51.212-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>The backlog</title><content type='html'>&lt;p&gt;This is just a list of stuff I'd like to work on, as soon as I finish the I/O subsystem:&lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Proper polymorphic functions or methods&lt;/b&gt; - i.e. functions that fix &lt;a href="http://arclanguage.com/item?id=7429"&gt;the curse of chains&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Symbol-based packages&lt;/b&gt;, as suggested &lt;a href='http://arclanguage.com/item?id=7831'&gt;by cchooper&lt;/a&gt;.  Probably I'll go with &lt;a href='http://arclanguage.com/item?id=7866'&gt;what I proposed&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;Implement some more &lt;b&gt;higher-order function bytecodes&lt;/b&gt;, i.e. flesh out the &lt;a href='http://snapvm.blogspot.com/2008/07/reducto-most-complex-single-bytecode-in.html'&gt;&lt;code&gt;reducto&lt;/code&gt;&lt;/a&gt; family of bytecodes.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;Improve &lt;b&gt;arc2c&lt;/b&gt;, particularly &lt;b&gt;quasiquotes, destructuring function variables, and macros&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;Add &lt;b&gt;tables&lt;/b&gt; to the runtime, since tables are used to represent data structures in the arc2c compiler.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-7537965213651759193?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/7537965213651759193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=7537965213651759193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/7537965213651759193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/7537965213651759193'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/08/backlog.html' title='The backlog'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-5271573865940487552</id><published>2008-08-19T06:52:00.000-07:00</published><updated>2008-08-19T08:34:50.028-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Update: I/O</title><content type='html'>&lt;p&gt;It's been some time since my last post on this blog, so I feel obligated to report a bit on what I've been doing.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;We call it Input-Output&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Currently I'm working on the I/O subsystem.  I'm trying to concentrate on this now instead of adding various features to SNAP (and thinking up various axioms to help make Arc a better language for creating building blocks), and I'm forming a little backlog list while I'm building I/O.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;One problem we have here is concurrent access to an I/O port.  Of course, concurrent access to a port doesn't, quite, make sense: if you want to keep track of which one of several processes should be accessing the port &lt;i&gt;right now&lt;/i&gt;, you'd have to use some sort of serializing system (i.e. message passing).  In general having just one process keep access to the port and have it handle the synchronization will be simpler and probably easier to maintain.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However, the point is that in SNAP we will allow you to do this while making sure that the virtual machine doesn't crash as a whole, and that your process doesn't crash others just because they are effectively sharing the resource.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The other problem is that we'll be using green threads in the execution subsystem.  This means that context switching is done in an explicit manner, and in theory, it should be possible to "run" multiple processes even without using OS threads.  This means that we &lt;i&gt;have&lt;/i&gt; to use nonblocking and/or asynchronous I/O.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;No time to wait&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Typically, I/O operations will wait for the I/O to complete.  In the case of input from a user terminal or from a network socket, this means that if data is not available, we must wait.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However, waiting is not acceptable: we might have some other process that could be running and isn't going to use that port.  This means that we should be able to determine if an I/O port has data available, or can accept data, and only talk to the I/O port if so; we need to use asynchronous I/O.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Surprisingly, Microsoft Windows seems to be better at asynchronous I/O than Unix-based OS'es.  POSIX defines an asynch I/O interface but it doesn't appear to be well supported among otherwise POSIX-compliant operating systems, and we have a hodgepodge of interfaces, such as the Linux-only epoll and the Sun-only kqueue.  Some of these interfaces are not even well supported and/or particularly stable; the only thing that appears reliable is the most basic &lt;code&gt;select()&lt;/code&gt;, which has efficiency problems.  &lt;font size=small&gt;(and of course, efficiency is never a concern, unless it is)&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, the I/O system backend has to be easily swapped with other back-ends.  I'm currently implementing around &lt;a href='libev.schmorp.de/'&gt;libev&lt;/a&gt;, which was inspired by &lt;a href='www.monkey.org/~provos/libevent/'&gt;libevent&lt;/a&gt;.  libev is newer (and consequently, probably less bug-free) and faster, but is limited only to the hodgepodge of interfaces supported by Unix-likes, while libevent is older and more well developed, and includes a Windows backend.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The I/O system backend, however, is presented to the rest of the SNAP VM world by the Central I/O Process.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;The Central I/O Process&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The Central I/O Process handles all the I/O done in the system, and feeds it into the backend.  This allows the backend to be lock-free: it can only be run from one OS-level thread, specifically whichever drew the short stick and got the central I/O process.  &lt;font size=small&gt;(libev and libevent supposedly properly support multiple threads, as long as you use the "reentrant" interface functions, but I'd rather use the default interface)&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The Central I/O Process, like any good process, can also accept messages and send them.  It accepts a set of "request" messages, which includes a tag, the source process, and the port data object, and when the backend has completed the task, sends a "response" message - either an "ok" message or an error - back to the requesting process.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Crucially, the Central I/O Process keeps its hands off the port data object.  The exact format of the port data object is not known by the Central I/O Process; the port data objects are created and used only by the backend.  Thus, the port data objects are effectively opaque to the rest of the SNAP virtual machine.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;The Arc I/O Ports&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;But having a Central I/O Process is not sufficient.  The problem is that part of the backend's assumptions include the fact that at any one time, for a particular port, only one asynchronous I/O event is on-going.  This means that access to the I/O ports must be synchronized.  In SNAP and similar message-passing concurrency environments, synchronization is handled by isolating the synchronized resource into a separate process.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Thus, the I/O ports on the Arc side are not even the opaque port data objects; they are wrappers around a process ID for a process which handles the synchronization of the actual port data objects.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Yes, asynchronous I/O is hard. ^^&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-5271573865940487552?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/5271573865940487552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=5271573865940487552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/5271573865940487552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/5271573865940487552'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/08/update-io.html' title='Update: I/O'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-2943554066450639667</id><published>2008-08-03T02:18:00.000-07:00</published><updated>2008-08-05T07:50:27.077-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='axioms'/><title type='text'>The base functions</title><content type='html'>&lt;p&gt;In a few of my &lt;a href='http://arclanguage.com/item?id=7492'&gt;recent posts on arclanguage.com&lt;/a&gt;, as well as the &lt;a href='http://snapvm.blogspot.com/2008/07/reducto-most-complex-single-bytecode-in.html'&gt;reducto discussion on this blog&lt;/a&gt;, I have been &lt;b&gt;showing some functions&lt;/b&gt; that begin with the &lt;b&gt;prefix &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;&lt;/b&gt;.  However, I have been thinking of the &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; functions for some time already; their primary motivation is to make it easier to &lt;b&gt;define new object types&lt;/b&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;What started me was when I was experimenting with defining new object types in Arc, an example of which is my &lt;a href='http://arclanguage.com/item?id=7366'&gt;create your own collection&lt;/a&gt; series.  Now, one bit I thought would be nice for collections is to allow them to be composed, and yet still be assignable:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(= foo (file-table "/tmp/"))&lt;br&gt;(= foos foo:string)&lt;br&gt;(= foos.2 "2")&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Basically, the assignment to &lt;code&gt;foos&lt;/code&gt; above would be equivalent to &lt;code&gt;(= (foo (string 2)) "2")&lt;/code&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In order to allow this, I needed to redefine &lt;code&gt;compose&lt;/code&gt;.  Unfortunately, I needed to redefine the &lt;b&gt;complete&lt;/b&gt; &lt;code&gt;compose&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This is when I started thinking about the &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; functions.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Dividing the Concept&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Conceptually, &lt;code&gt;compose&lt;/code&gt; is simply a reduction of a more basic "function-composition" operation on its arguments.  We can thus divide &lt;code&gt;compose&lt;/code&gt; into a reducer operation, implemented using &lt;a href='http://snapvm.blogspot.com/2008/07/reducto-most-complex-single-bytecode-in.html'&gt;the reducto bytecode&lt;/a&gt;, and a more basic operation, which we would prepend with the prefix &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Then anyone who wishes to override &lt;code&gt;compose&lt;/code&gt; doesn't have to reimplement the &lt;i&gt;entire&lt;/i&gt; function; just the part he or she is interested in: the basic operation.  Instead of handling the the case for having one argument, or zero arguments, or N arguments, only the simple case - the two argument case - needs to be handled.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;compose&lt;/code&gt; is not the only function that would benefit from this separation; the mathematical and comparison functions would also benefit.  This simplifies the effort needed to implement various numeric systems, such as quaternions.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Adding Lists&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Not all is well in a &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;-ic world, though.  The problem is performing &lt;code&gt;+&lt;/code&gt; on lists, which performs a copying concatenation of the lists.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If we define &lt;code&gt;(+ a b c)&lt;/code&gt; as being, effectively, equivalent to &lt;code&gt;(&amp;lt;base&amp;gt;+ (&amp;lt;base&amp;gt;+ a b) c)&lt;/code&gt;, then the inner &lt;code&gt;&amp;lt;base&amp;gt;+&lt;/code&gt; will create copies of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, and then return it.  And &lt;i&gt;then&lt;/i&gt; the outer &lt;code&gt;&amp;lt;base&amp;gt;+&lt;/code&gt; will recopy the returned list, even though reusing it would have been better; we thus end up with more allocation than we wanted.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The problem is also repeated, in a less memory-pressing manner, when working with SNAP integers.  SNAP integers are boxed integers, i.e. they are part of the object hierarchy and will occupy real memory.  &lt;code&gt;+&lt;/code&gt; and other mathematical operations will have to create copies of the integer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Although there is a solution &lt;small&gt;(which I hope to fully present in a future post)&lt;/small&gt;, it involves playing some significant tricks on the type system, and will probably also need to use significant portions of a proposed multimethod dispatching scheme I've thought of.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In brief, it means defining a "temporary" type which encloses the actual type of the object.  We can then define overloads of the &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; functions which will reuse the objects in the encapsulating temporary type.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For now, however, we may have to first accept that this axiom will add overhead, but for that overhead it gains greater flexibility and ease-of-use.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-2943554066450639667?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/2943554066450639667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=2943554066450639667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/2943554066450639667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/2943554066450639667'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/08/base-functions.html' title='The base functions'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-1858602085401301072</id><published>2008-07-30T20:23:00.000-07:00</published><updated>2008-07-30T20:46:47.088-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='axioms'/><title type='text'>symeval</title><content type='html'>&lt;p&gt;A common problem in Arc is that macros - even &lt;b&gt;well-designed ones&lt;/b&gt; - can &lt;b&gt;introduce subtle bugs&lt;/b&gt;.  I thus propose the addition of a &lt;b&gt;new axiom&lt;/b&gt;, a special form called &lt;code&gt;symeval&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For example, consider a library which has a complicated global function:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(def cplx-fun (sym trap val)&lt;br&gt;&amp;nbsp; (some-complex-expression sym trap val))&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Now the library designer intends to use this as a somewhat-internal function; what he or she expects people to use is a macro that wraps the call:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(mac cplx (val . body)&lt;br&gt;&amp;nbsp; (w/uniq sym&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; `(cplx-fun ',sym (fn () ,@body) val)))&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;And of course, all is well and good... the library was so useful and powerful that people no longer felt the need to actually look inside the library and bother with how it was implemented.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Until the day, of course, where some random newbie decided to do this:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(def my-fun (x)&lt;br&gt;&amp;nbsp; (let cplx-fun (fn (tmp) (cplx 42 tmp))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (cplx answer&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (cplx-fun x))))&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Unfortunately, the &lt;i&gt;global&lt;/i&gt; &lt;code&gt;'cplx-fun&lt;/code&gt; was overridden by the &lt;i&gt;local&lt;/i&gt; version.  So now the newbie &lt;b&gt;had to bother with how the library worked&lt;/b&gt;, when it was already so good and perfect that &lt;b&gt;nobody should have had to&lt;/b&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;&lt;code&gt;symeval&lt;/code&gt;&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;I thus propose the addition of a new axiom, &lt;code&gt;'symeval&lt;/code&gt;.  &lt;code&gt;symeval&lt;/code&gt; is a special form, like &lt;code&gt;fn&lt;/code&gt; or &lt;code&gt;if&lt;/code&gt;, and thus cannot be overridden at all.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;symeval&lt;/code&gt; will &lt;b&gt;evaluate&lt;/b&gt; its argument, and check if the result is a symbol.  If it's a symbol, it evaluates the symbol in the &lt;i&gt;global&lt;/i&gt; environment.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As an optimization, the implementation can treat something of the form &lt;code&gt;(symeval 'foo)&lt;/code&gt; as being equivalent to an ordinary global variable read; the important thing is that &lt;code&gt;(symeval 'foo)&lt;/code&gt; will always read the global variable &lt;i&gt;regardless of the existence of any &lt;code&gt;foo&lt;/code&gt; variable in the same context&lt;/i&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This should be trivial to add in arc2c and hence in SNAP: we need only to replace &lt;code&gt;symeval&lt;/code&gt; forms (probably in &lt;code&gt;xe&lt;/code&gt;) with global variable references if the form is quoted, and transform it into a primitive otherwise.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Thus the macro is now:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(mac cplx (val . body)&lt;br&gt;&amp;nbsp; (w/uniq sym&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; `(symeval!cplx-fun ',sym (fn () ,@body) val)))&lt;/code&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-1858602085401301072?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/1858602085401301072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=1858602085401301072' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/1858602085401301072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/1858602085401301072'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/07/symeval.html' title='symeval'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-3643266786261305014</id><published>2008-07-29T14:41:00.000-07:00</published><updated>2008-09-01T05:49:04.880-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interpreter'/><title type='text'>Continuation Closures</title><content type='html'>&lt;p&gt;Closures in SNAP, much like closures in arc2c, are &lt;b&gt;simply flat arrays&lt;/b&gt; of references to Arc objects.  Closures in SNAP are also used to &lt;b&gt;represent functions&lt;/b&gt; on the Arc side; that is, what Arc thinks is a function, is actually an object of the class &lt;code&gt;Closure&lt;/code&gt;.  The Closure object also &lt;b&gt;contains a reference to an &lt;code&gt;Executor&lt;/code&gt;&lt;/b&gt;, which is a scary name for something that executes. &lt;small&gt;(more about &lt;code&gt;Executor&lt;/code&gt; in another post)&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Closures in SNAP are &lt;b&gt;expected to be immutable&lt;/b&gt;: once they've been constructed, their contained values are not supposed to change (there isn't anything that stops you from doing that on the C++ side, other than a nasty comment).  On the other hand, &lt;i&gt;continuation&lt;/i&gt; closures have a &lt;code&gt;reusable()&lt;/code&gt; member function which specifies whether or not &lt;b&gt;the continuation closure is reusable&lt;/b&gt;, i.e. whether or not its contents can be modified with new content.  Continuation closures are represented by the &lt;code&gt;KClosure&lt;/code&gt; class, which is derived from class &lt;code&gt;Closure&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Why &lt;code&gt;KClosure&lt;/code&gt;?&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Having a separate &lt;code&gt;KClosure&lt;/code&gt; class just for continuations is largely an optimization to avoid allocating excessive amounts of closures.  A continuation closure is usually just invoked once, at the end of a normal function.  Typically, after the continuation itself ends - when it must invoke another function - its closure can be freed.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Of course, this is a garbage-collected system, and a copying one at that.  "Freeing" memory involves not copying things, and "not copying" is what you want to do most of the time.  The best you can do is to &lt;b&gt;reuse&lt;/b&gt; a piece of memory you've already allocated.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So a continuation can freely reuse its closure, because it won't get invoked again &lt;small&gt;(barring a minor case i'll get to later)&lt;/small&gt; and we don't expect there to be any live data that still refers to the continuation.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;And since the continuation closure is still a continuation closure, we reuse the memory area by constructing any new continuation closures in the same, current continuation closure.  So a continuation which finds that it must invoke another, non-continuation function - which would expect a continuation - can reuse its own continuation closure; this allows us to skip allocating for a large number of cases.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Continuation closures have an invariant.  A reference continuation closure can only exist on the stack, or as an entry in another continuation closure.  Also, continuation closures cannot possibly form anything other than a straight singly-linked list.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So why have a &lt;code&gt;reusable()&lt;/code&gt; member function?  The problem is a little feature called &lt;code&gt;'ccc&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;'ccc&lt;/code&gt; (known in the Scheme world as &lt;code&gt;call-with-current-continuation&lt;/code&gt; or &lt;code&gt;call/cc&lt;/code&gt;) captures the continuation and returns it all trussed up.  This also means that the continuation might be invoked using the captured continuation closure more than once - and our assumption so far has been that the continuation is invoked only once.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This is solved by having &lt;code&gt;'ccc&lt;/code&gt; call the &lt;code&gt;banreuse()&lt;/code&gt; member function on the captured continuation closure, which causes &lt;code&gt;reusable()&lt;/code&gt; to always return false afterward.  This means that the continuation closure cannot be reused, and the VM will actually copy the continuation closure when reuse is requested (a sort of "copy-on-write").&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Continuation closures that are not reusable may safely violate the invariant.  Also, such continuation closures may now form any directed graph, and can even be a cyclic graph.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;small&gt;(this optimization was inspired by the parrot article &lt;a href='http://use.perl.org/~chromatic/journal/36212?from=rss'&gt;refcounting isn't all bad&lt;/a&gt; and its followup &lt;a href='http://use.perl.org/~chromatic/journal/36509?from=rss'&gt;what c's memory management gets rightish&lt;/a&gt;; instead of a full refcount, i use a single bit which means "more than one reference" - basically, that's the bit toggled by &lt;code&gt;banreuse()&lt;/code&gt; and queried by &lt;code&gt;reusable()&lt;/code&gt; - and like in the followup i use this only for continuation closures.  i suggested this &lt;a href='http://arclanguage.com/item?id=6282'&gt;in a post on the Arc forum&lt;/a&gt;)&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;lt;edit&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Follow-up: can it go even faster?&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Due to CPS conversion, code generated by the arc2c compiler (around which the SNAP virtual machine is built) tends to allocate a lot of closure objects, especially continuation closures.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As mentioned in the "what c's memory management gets rightish" link above, making use of a stack-like allocator - where continuation closure frames can be allocated and deallocated in last-in-first-out order - would severely decrease garbage collection pressure.  In a CPS implementation like SNAP, this means that, barring &lt;code&gt;'ccc&lt;/code&gt;, a continuation that has exited can have its closure deallocated almost immediately.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This could in fact be done in SNAP; any continuation that exits without reusing its closure can specify deallocation of the closure; the deallocator attempts to deallocate the continuation if's the last allocated structure, or leaves it on the stack if not.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This will of course complicate GC somewhat.  It also means that we have for each heap two separate allocation areas: one for normal allocation, and one for LIFO structures.  Since the call graph is &lt;i&gt;usually&lt;/i&gt; structured as a singly-linked list, this will allow even better reuse of closures; in fact, the current strategy of explicitly reusing can probably be replaced with the LIFO structure..&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;lt;edit&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Follow-up: LIFO implemented&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;LIFO allocation-deallocation schemes have &lt;a href='http://snapvm.blogspot.com/2008/08/interlude-lifo-heap.html'&gt;been implemented&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-3643266786261305014?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/3643266786261305014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=3643266786261305014' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/3643266786261305014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/3643266786261305014'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/07/continuation-closures.html' title='Continuation Closures'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-901512020004907799</id><published>2008-07-28T04:45:00.000-07:00</published><updated>2008-07-30T08:08:38.224-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interpreter'/><title type='text'>reducto: the most complex single bytecode in SNAP</title><content type='html'>&lt;p&gt;stefano recently &lt;a href="http://arclanguage.com/item?id=7643"&gt;brought up a potential efficiency issue&lt;/a&gt; in implementations of Arc.  Specifically, the problem is that &lt;b&gt;some variadic functions&lt;/b&gt;, such as &lt;code&gt;'+&lt;/code&gt;, are really the &lt;b&gt;reduction of a more basic function&lt;/b&gt; on its arguments, i.e.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;(def + rest&lt;br&gt;&amp;nbsp; (reduce &amp;lt;base&gt;+ rest))&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;The problem is that variadic functions normally put their arguments in a list, and in the most common case, &lt;b&gt;&lt;code&gt;'+&lt;/code&gt;&lt;/b&gt; and related functions (such as &lt;code&gt;'-&lt;/code&gt;, &lt;code&gt;'*&lt;/code&gt;, and &lt;code&gt;'/&lt;/code&gt;) will only be &lt;b&gt;called on two arguments&lt;/b&gt;.  Consing here is just a waste of memory and makes the dreaded GC loom nearer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The solution which stefano proposed is to inline the code, so that potentially &lt;code&gt;(+ a b c d)&lt;/code&gt; will become &lt;code&gt;(&amp;lt;base&gt;+ (&amp;lt;base&gt;+ (&amp;lt;base&gt;+ a b) c) d)&lt;/code&gt;.  However, inlining is a bit difficult in a dynamic language with &lt;code&gt;'eval&lt;/code&gt;; you need some way to "uninline" the code if the global functions are redefined.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;small&gt;(it also assumes that &lt;code&gt;'+&lt;/code&gt; associates left-to-right, but it's quite valid for the programmer to modify &lt;code&gt;'+&lt;/code&gt; to work right-to-left)&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;My alternative, since I am defining my own virtual machine and bytecode interpreter, is simply to make a &lt;b&gt;really, really complex bytecode&lt;/b&gt; which handles this problem and &lt;b&gt;avoids allocating&lt;/b&gt; in the most common cases.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;&lt;code&gt;reducto&lt;/code&gt;&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;reducto&lt;/code&gt; effectively implements the reduction function and avoid allocation for the common cases where only two parameters are needed.  However, it is not completely standalone; it also needs to know the function(s) to apply.  It thus expects that the function it is part of contains three entries in its closure, which are three functions or applicable objects.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The reduction is only useful if two or more arguments are given; special handling must be specified for the case where 0 or 1 arguments are given.  For example, &lt;code&gt;'-&lt;/code&gt; negates its argument if only 1 argument is given.  This is why the closure has 3 function entries - (1) a function that handles the 0-argument case, (2) a function that handles the 1-argument case, and (3) a function that is used for reduction, and handles 2-argument and higher cases.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Running &lt;code&gt;reducto&lt;/code&gt;: the simple cases&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;reducto&lt;/code&gt; chooses which function to apply based on the number of arguments it finds on the stack.  Two of the arguments are the current closure and the continuation closure; the rest of the stack entries are the arguments given by the Arc code (the "Arc arguments").  If 2 or fewer Arc arguments are on the stack, then it simply directly indexes the closure: the 0-argument function is in closure index 0, 1-argument is in closure index 1, etc.  For such simple cases, it performs the call directly, modifying only the "current closure" entry of the stack - no allocation is done.  Simple, direct, and cheap in both memory and time.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Of course, the interesting bit is for the non-trivial cases where there are 3 or more Arc arguments.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;3 arguments or more&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;For the non-trivial cases, &lt;code&gt;reducto&lt;/code&gt; must allocate a closure and store the extra arguments there; in order to reduce allocation, it uses a &lt;a href='http://snapvm.blogspot.com/2008/07/continuation-closures.html'&gt;continuation closure&lt;/a&gt;, which can be reused.  The continuation closure holds the current continuation, the function to invoke, and all the arguments except the first two, as well as an index integer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The actual size of the created closure depends on the number of arguments.  For each extra argument beyond the first two, a slot must be reserved for that argument.  In addition, the continuation closure must store the final continuation, the function to invoke, and the index; in effect, the size of the closure corresponds to 1 + number of Arc arguments.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the C++ source, the &lt;code&gt;reducto_continuation&lt;/code&gt; executor handles the actual reduction operation; it refers to the continuation closure and calls the reduction function for each argument.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The index to be specifies which argument to call with next.  Now, SNAP integers are currently unboxed; fortunately, we know that the index number will not be used by anything else, so we can simply directly modify the contents of the box without additional allocation.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Handling nonreusability&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Recall that &lt;code&gt;'ccc&lt;/code&gt; could make a continuation closure non-reusable.  In such a case, we cannot modify the index integer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Since the index integer is now nonmodifiable and the continuation closure is now immutable, we will have to create a fresh continuation closure and copy the contents.  This allows &lt;code&gt;'ccc&lt;/code&gt; to operate properly.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;small&gt;(note that now that i've thought about it, we might actually still be able to just create a closure that contains an index number and a reference to the non-reusable continuation closure, and suffer through an additional indirection, which would be a small price to pay compared to copying; we would need to define an additional executor for such a continuation, though)&lt;/small&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-901512020004907799?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/901512020004907799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=901512020004907799' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/901512020004907799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/901512020004907799'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/07/reducto-most-complex-single-bytecode-in.html' title='reducto: the most complex single bytecode in SNAP'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1934327362352050331.post-3438636110879227281</id><published>2008-07-27T03:02:00.000-07:00</published><updated>2008-08-03T03:37:39.618-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Shared Nothing Arc Processes: the introduction</title><content type='html'>&lt;p&gt;Shared Nothing Arc Processes (SNAP) is a virtual machine designed for a massively multiprocess - where communications are done by shared-nothing message passing - implementation of &lt;a href="http://www.arclanguage.com/"&gt;Arc&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Why shared-nothing message passing?&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;As an electronics engineer doing mostly digital designs, I think I can safely say that multicore, highly parallel programming is the future. ^.^ I find &lt;a href='http://www.erlang.org/'&gt;Erlang&lt;/a&gt; interesting, although I don't really like its syntax.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Of course, there's another alternative for coordinating multiple processes, &lt;a href='http://en.wikipedia.org/wiki/Software_transactional_memory'&gt;STM&lt;/a&gt;.  And maybe it can be done for Arc.  There's just one problem: I can grok shared-nothing message passing, but I can't grok STM.  So, at least for now, shared-nothing message passing it is.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Why Arc?&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Because it's very similar to Cadence &lt;a href="http://www.ece.uci.edu/eceware/cadence/sklanguser/sklanguserTOC.html"&gt;SKILL&lt;/a&gt;, the extension language of Cadence, which develops Electronic Design Automation (EDA) tools.  I'm an electronics engineer specializing (somewhat) in IC design and testing, which means that I make use of Cadence products quite a bit in the office; SKILL was the first Lisp-like I seriously programmed in.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Arc and SKILL have the following similarities:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Lisp-1&lt;/b&gt;, at least for SKILL++ mode.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;&lt;code&gt;t&lt;/code&gt; and &lt;code&gt;nil&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;List-based macros&lt;/b&gt;, like in Common Lisp and unlike hygienic macros in Scheme&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h1&gt;Why bother?&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Why do this, when there's already a good, mature implementation of shared-nothing message passing, Erlang?  Why do this when PG has &lt;i&gt;finally&lt;/i&gt; released Arc, and some dabblers are building Arc implementations &lt;i&gt;from scratch&lt;/i&gt; all over, including &lt;a href='http://github.com/sacado/arc2c/commits/master'&gt;at least one compiler that compiles to C&lt;/a&gt;, another one that &lt;a href='http://github.com/stefano/nyac/tree/master/'&gt;compiles to native x86 code&lt;/a&gt;, and an &lt;a href='http://github.com/conanite/rainbow/tree/master'&gt;implementation in Java&lt;/a&gt;?  And Lisp-likes are already being created with shared-nothing message passing, such as &lt;a href='http://weblog.thatmattbone.com/search/label/erlang-in-lisp'&gt;an on-going (as of Jul 2008) LispNYC Summer of Code project&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Well, the world needs yet another dead open source project.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Okay, it's mostly because I'm curious about how to implement an &lt;i&gt;efficient&lt;/i&gt; language system from scratch, and I'm curious about the special problems that, say, JIT faces when another thread might be compiling the same code.  Also, I happen to like Arc, but I have some issues with its axioms, and I'm also using SNAP as a sort of testbench to treat what I feel are better axioms for Arc.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Goals&lt;/h1&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Massively multiprocess&lt;/b&gt;.  If Erlang can launch hundreds of thousands of processes, SNAP should too!&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Support OS threads&lt;/b&gt;, so we can take advantage of multiple cores if the OS can do so.  By the same token SNAP should also &lt;b&gt;support &lt;i&gt;not&lt;/i&gt; using OS threads&lt;/b&gt;, meaning that operations that would block a single process should still allow other processes to continue.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Efficiency&lt;/b&gt;, because there's little point in multiprocessing if you're just being inefficient.  This includes &lt;b&gt;interpreter speed&lt;/b&gt;, as well as efficiency in &lt;b&gt;garbage collection&lt;/b&gt; and &lt;b&gt;message passing&lt;/b&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Make a &lt;b&gt;good standard for Arc&lt;/b&gt;.  Including ways of introspecting into closured functions (which no Lisp-like has ever done), as well as introspecting function code, to allow serialization of functions from the Arc-side.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1934327362352050331-3438636110879227281?l=snapvm.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://snapvm.blogspot.com/feeds/3438636110879227281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1934327362352050331&amp;postID=3438636110879227281' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/3438636110879227281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1934327362352050331/posts/default/3438636110879227281'/><link rel='alternate' type='text/html' href='http://snapvm.blogspot.com/2008/07/shared-nothing-arc-processes.html' title='Shared Nothing Arc Processes: the introduction'/><author><name>Alan Manuel</name><uri>http://www.blogger.com/profile/06159757852980295097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
