<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Luke Wagner&#039;s Blog</title>
	<atom:link href="http://blog.mozilla.org/luke/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mozilla.org/luke</link>
	<description>Programming and Mozilla</description>
	<lastBuildDate>Wed, 08 May 2013 22:39:19 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>asm.js in Firefox Nightly</title>
		<link>http://blog.mozilla.org/luke/2013/03/21/asm-js-in-firefox-nightly/</link>
		<comments>http://blog.mozilla.org/luke/2013/03/21/asm-js-in-firefox-nightly/#comments</comments>
		<pubDate>Thu, 21 Mar 2013 18:00:17 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=510</guid>
		<description><![CDATA[I&#8217;m happy to announce that OdinMonkey, an asm.js optimization module for Firefox&#8217;s JavaScript engine, is now in Nightly builds and will ship with Firefox 22 in June. What is asm.js? Why are we doing it, and how are we getting &#8230; <a href="http://blog.mozilla.org/luke/2013/03/21/asm-js-in-firefox-nightly/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m happy to announce that OdinMonkey, an <a href="http://asmjs.org">asm.js</a> optimization module for Firefox&#8217;s JavaScript engine, is now in Nightly builds and will ship with Firefox 22 in June.</p>
<p>What is asm.js?  Why are we doing it, and how are we getting to within 2x of native performance?  This post won&#8217;t be able to go into too much detail since we&#8217;re hard at work preparing for Mozilla&#8217;s upcoming GDC session, which you should definitely come see (<a href="http://schedule2013.gdconf.com/session-id/824220">Wednesday 11am,  Room 3024, West Hall</a>).  After GDC, expect full coverage of these topics by <a href="https://twitter.com/kripken">Alon</a>, <a href="https://twitter.com/littlecalculist">Dave</a>, myself and surely others.  For now, allow me to point you at the <a href="http://asmjs.org/faq.html">asm.js FAQ</a>, <a href="http://kripken.github.com/mloc_emscripten_talk/#/19">Alon&#8217;s mloc.js slides</a>, a nice <a href="http://badassjs.com/post/43420901994/asm-js-a-low-level-highly-optimizable-subset-of">Badass JavaScript post</a> and a more in-depth <a href="http://www.2ality.com/2013/02/asm-js.html">post by Axel Rauschmayer</a>.</p>
<p>Want to see it in action?  Download a new <a href="http://nightly.mozilla.org">Firefox Nightly build</a> and try out <a href="http://kripken.github.com/misc-js-benchmarks/banana/benchmark.html">BananaBench</a>.  (Note: BananaBench runs with a fixed time step to make JS execution deterministic, so game speed will run fast/slow, depending on your hardware/browser.)  Or, check out a demo of the Emscripten-compiled Bullet engine <a href="http://kripken.github.com/ammo.js/examples/new/ammo.html">simulating a ton of falling boxes</a>.</p>
<p>At the moment, we have x86/x64 support on desktop Windows/Mac/Linux and support for <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840285">mobile Firefox on ARM</a> is almost done.  Since we intend to continue to iterate on the <a href="http://asmjs.org/spec/latest/">asm.js spec</a> in cooperation with other JS engines, we&#8217;ve put OdinMonkey behind the flag <code>javascript.options.asmjs</code> in about:config.  <del datetime="2013-05-08T22:34:42+00:00">This flag is currently enabled by default on Nightly and Aurora, and if nothing changes over the next 12 weeks, will be automatically disabled in Beta and Release.  By then, we hope to be happy with a stable “asm.js v.1″, we&#8217;ll enable it everywhere and ship with it enabled in our final builds.</del> [<em>Update</em>: OdinMonkey has been enabled by default for all releases starting with Firefox 22.]</p>
<p>If you want to start experimenting with asm.js right now, you can:</p>
<ul>
<li>Get <a href="https://github.com/kripken/emscripten/wiki/Tutorial">Emscripten</a> and start compiling C/C++ code.  (Don&#8217;t forget the <code>-O2 -s ASM_JS=1</code>.)</li>
<li>Check out the <a href="http://asmjs.org/spec/latest/">draft spec</a> and start writing asm.js by hand.</li>
</ul>
<p>In the future, we&#8217;d like to see a rich third option of generating asm.js using a more ergonomic front-end language (e.g., a derivative of <a href="http://lljs.org">LLJS</a>). [Update: <a href="http://jlongster.com/Compiling-LLJS-to-asm.js,-Now-Available-?hn">LLJS work is already underway!</a>]  </p>
<p>How do you know if you are generating valid asm.js and taking full advantage of OdinMonkey?  In the old days, this was a frustrating question for developers.  Maybe you were doing something wrong, maybe the code, as written, was just slow.  One cool thing about asm.js is that the <code>"use asm"</code> directive makes the programmer&#8217;s intention quite clear: they want to compile asm.js.  Thus, if there is an asm.js validation error, OdinMonkey will print a warning on the JavaScript console. (OdinMonkey emits a warning, instead of throwing an error, since asm.js is just JavaScript and thus cannot change JavaScript semantics.)  In fact, since silence is ambiguous, OdinMonkey also prints a message on <em>successful</em> compilation of asm.js.  (There is currently a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=851885">bug</a> preventing asm.js optimization and warnings in Scratchpad and the Web Console, so for now experiment in regular content.)</p>
<p>For those who are itching to do some performance experiments: go for it, we&#8217;ve been pretty happy with the results so far when asm.js is applied to <a href="https://groups.google.com/d/msg/emscripten-discuss/O1Tzgxt0Hfw/QPmrQPJH4LAJ">new codes</a>, but we&#8217;ve also seen plenty of cases where the C++ compiler is doing important backend optimizations that we haven&#8217;t taught our IonMonkey backend yet.  We expect continuous incremental improvement as we measure and implement new optimizations to close this gap.  Second: one performance fault that we already know trips up people trying to benchmark asm.js is that calling from non-asm.js into asm.js and vice versa is much slower than normal calls due to general-purpose enter/exit routines.  We plan to fix this in the next few months but, in the meantime, for benchmarking purposes, try to keep the whole computation happening inside a single asm.js module, not calling in and out.</p>
<p>In closing, I leave you with the musical inspiration for OdinMonkey:<br />
<iframe width="560" height="315" src="http://www.youtube.com/embed/Y9q41P4VrwI" frameborder="0" allowfullscreen></iframe><br />
Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2013/03/21/asm-js-in-firefox-nightly/feed/</wfw:commentRss>
		<slash:comments>37</slash:comments>
		</item>
		<item>
		<title>Optimizing JavaScript variable access</title>
		<link>http://blog.mozilla.org/luke/2012/10/02/optimizing-javascript-variable-access/</link>
		<comments>http://blog.mozilla.org/luke/2012/10/02/optimizing-javascript-variable-access/#comments</comments>
		<pubDate>Tue, 02 Oct 2012 16:23:55 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=424</guid>
		<description><![CDATA[Nicolas Pierron has provided a French translation of this post. Thanks! I recently finished a project to improve how SpiderMonkey implements variable access so I thought this would be a good time to explain how it all works now. Taking &#8230; <a href="http://blog.mozilla.org/luke/2012/10/02/optimizing-javascript-variable-access/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><i>Nicolas Pierron has provided a <a href="http://tech.mozfr.org/post/2013/02/03/Optimiser-les-acces-de-variables-JavaScript">French translation</a> of this post.  Thanks!</i></p>
<p>I recently finished a <a href="https://bugzilla.mozilla.org/showdependencygraph.cgi?id=767013">project</a> to improve how SpiderMonkey implements variable access so I thought this would be a good time to explain how it all works now.  Taking a note from mraleph&#8217;s <a href="http://blog.mrale.ph/post/24351748336/explaining-js-vm-in-js">post</a> (and <a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-25.html#%_chap_4">SICP</a>), I&#8217;ll illustrate the implementation using JavaScript as the implementation language.  That is, I&#8217;ll translate JavaScript using full-featured variable access into JavaScript that doesn&#8217;t, rather like how the <a href="http://en.wikipedia.org/wiki/Cfront">original C++ compiler</a> translated C++ into C.</p>
<p>Before starting, let me set up the problem space.  By <em>variable</em> I&#8217;m referring not just to the variables introduced by <code>var</code>, but also those introduced by <a href="http://wiki.ecmascript.org/doku.php?id=harmony:block_scoped_bindings"><code>let</code></a>, <a href="http://wiki.ecmascript.org/doku.php?id=harmony:const"><code>const</code></a>, <code>catch</code>, <code>function</code> statements, and function argument lists.  By variable <em>access</em>, I mean a read or a write.  Variable access can take many forms:</p>
<ul>
<li><em>Local</em> access (i.e., access to a variable in the same function):
<pre>function add(x,y) { return x+y }</pre>
</li>
<li><em>Non-local</em> access (i.e., access to a variable in an enclosing function):
<pre>function add(x,y) { return (function() { return x+y })() }</pre>
</li>
<li>Access from dynamically-generated code:
<pre>function add(x,y) { return eval("x+y") }</pre>
</li>
<li>Access after dynamic scope modification via non-strict direct <code>eval</code>:
<pre>function add(a,b) { eval("var x="+a+", y="+b); return x+y }</pre>
</li>
<li>Dynamic function argument access via the <code>arguments</code> object:
<pre>function add(x,y) { return arguments[0]+arguments[1] }</pre>
</li>
<li>Unexpected debugger snooping (via <a href="http://getfirebug.com">Firebug</a>, the new <a href="https://developer.mozilla.org/en-US/docs/Tools/Debugger">builtin Firefox debugger</a>, or directly from privileged JS using the new <a href="https://wiki.mozilla.org/Debugger"><code>Debugger</code></a> API):
<pre>dbg.onDebugerStatement = function(f) { return f.eval("x+y") }</pre>
</li>
</ul>
<p>To keep the post small(-ish), I&#8217;ll pretend there is only (non-strict, direct) <code>eval</code> and ignore strict and indirect <code>eval</code> as well as <code>with</code> (which we generally deoptimize as if it was an <code>eval</code>).  I&#8217;ll also ignore <code>let</code>, global access optimizations, the <a href="http://statichtml.com/2011/spidermonkey-function-hoisting.html">bizarre</a> things SpiderMonkey does for block-level function statements, and the debugger.</p>
<h2 id="dynamic-lookup">The worst case</h2>
<p>To rise above, we must first see how low we need to go in the worst case.  Consider the following function:</p>
<pre>
function strange() {
  eval("var x = 42");
  return function xPlus1() { var z = x + 1; return z }
}
</pre>
<p>Here, <code>eval</code> is <em>dynamically</em> adding <code>x</code> to the scope of <code>strange</code> where it will be read by <code>xPlus1</code>.  Since <code>eval</code> can be called with a dynamically-constructed string we must, in general, treat function scopes as dynamic maps from names to values.  (Fun fact: names added by <code>eval</code> can be removed using the <code>delete</code> keyword, so the map can both grow and shrink at runtime!)</p>
<p>To make this more concrete, we&#8217;ll implement scopes in JS using ES6 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Map">Map</a> objects.  We&#8217;ll give every function its own <code>Map</code> that will be stored in a local variable named <code>scope</code> and hold all the function&#8217;s variables.  (Yes, we&#8217;re using a variable to implement variables; but since we&#8217;ll only use a small finite number of them, we can think of them as <a href="http://en.wikipedia.org/wiki/Processor_register">registers</a>.)</p>
<pre>
function strange() {
  // the scope of 'strange' is initially empty
  var scope = new Map;

  // eval("var x = 42") effectively executes:
  scope.set('x', 42);

  return function xPlus1() {
    // vars are hoisted so scope initially contains 'z'
    var scope = new Map([['z', undefined]]);

    // var z = x + 1
    scope.set('z', scope.get('x') + 1);  // oops!

    // return z
    return scope.get('z');
  }
}
</pre>
<p>As the comment indicates, there is a bug in <code>xPlus1</code>: <code>x</code> isn&#8217;t in the <code>scope</code> of <code>xPlus1</code>, it&#8217;s in the <code>scope</code> of <code>strange</code>!  To fix this we need to do two things:</p>
<ol>
<li>Add an <code>enclosing</code> field to all scope objects indicating the enclosing function&#8217;s <code>scope</code> (or the global object if the function is top-level).</li>
<li>Replace uses of <code>scope.get</code> with a <code>lookup</code> algorithm that walks the chain of scopes.</li>
</ol>
<pre>
function strange() {
  // the scope of 'strange' is initially empty
  var scope = new Map;
  <font color=red>scope.enclosing = window;</font>

  // eval("var x = 42") effectively executes
  scope.set('x', 42);

  var tmp = function xPlus1() {
    // vars are hoisted so scope initially contains 'z'
    var scope = new Map([['z', undefined]]);
    <font color=red>scope.enclosing = xPlus1.enclosing;</font>

    // var z = x + 1
    scope.set('z', <font color=red>lookup(scope, 'x')</font> + 1);

    // return z
    return lookup(scope, 'z');
  }
  <font color=red>tmp.enclosing = scope;
  return tmp;</font>
}

<div id="lookup-function" /><font color=red>function lookup(scope, name) {
  while (scope instanceof Map &#038;&#038; !scope.has(name))
    scope = scope.enclosing;
  return scope.get(name);
}</font>
</pre>
<p>Note that, without being able to use non-local variable access (since that is what we are implementing), we must attach the <code>scope</code> of <code>strange</code> to the <code>xPlus1</code> function object.  This isn&#8217;t just some hack; it is a fundamental part of the implementation of languages with <a href="http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_and_dynamic_scoping">lexically-scoped first-class functions</a>.  More generally, we can establish the following relationship (pardon my ASCII-art):</p>
<pre>
Function-scope
  | *        ^ 0 or 1
  |          |
  | call of  | enclosing
  |          |
  V 1        | 1
Function-object
  | *
  |
  | evaluation of
  |
  V 1
Function-literal
</pre>
<p>Each function literal can be evaluated any number of times, with each evaluation producing a function object that is associated with its enclosing scope.  Each of those function objects can be called any number of times, each of those calls producing a scope.  When using the language, it is easy to see just a single concept <em>function</em>, but hopefully this illustrates that there are really three &#8220;function&#8221; concepts at play here: <em>scope</em>, <em>object</em>, and <em>literal</em>.</p>
<p>With these changes, we have successfully dealt with the ravages of <code>eval</code>, but at what cost?  Each variable access involves a call to an algorithm that iteratively performs hash-table lookups!  Fortunately, this problem isn&#8217;t that different from object-property lookup and the same type of optimizations apply: hidden classes and caches.  I won&#8217;t go into these techniques, as there are already <a href="http://blog.cdleary.com/2010/09/picing-on-javascript-for-fun-and-profit">two</a> <a href="http://blog.mrale.ph/post/24351748336/explaining-js-vm-in-js">great</a> explanations available.  (Caching has been used to speed up name access since Firefox 3.)  Even with these optimizations, however, name lookup isn&#8217;t as fast as we&#8217;d like it to be and we are still creating a <code>Map</code> object on every call.</p>
<p>In summary, we&#8217;ve handled the worst case, but we&#8217;d like to do better in code that doesn&#8217;t exercise the worst case.</p>
<h2 id='fast-local'>Fast local name access</h2>
<p>Now let&#8217;s optimize local variable access when <em>all</em> accesses are local.  With this constraint, JavaScript starts to look like C and we can use some of the same techniques as a C compiler: store all variables in a stack and access variables by their offset in the stack.</p>
<p>As a first (highly garbalicious) iteration, we create an array for each set of arguments and <code>var</code>s, thereby turning</p>
<pre>
foo(13, 42);

function foo(x,y) {
  var a = x + y;
  return bar(a);
}
</pre>
<p>into:</p>
<pre>
foo([13, 42]);

function foo(args) {
  var vars = [undefined];
  vars[0] = args[0] + args[1];
  return bar([vars[0]]);
}
</pre>
<p>The second step is to avoid creating all those temporary arrays by using one big array, shared by all active functions.  There are many ways to do this (corresponding to different <a href="http://en.wikipedia.org/wiki/Calling_conventions">calling conventions</a>); we&#8217;ll just do something simple here:</p>
<pre>
// executed some time before the first function call:
var stack = [];

stack.push(13);
stack.push(42);
foo(/* number of arguments pushed = */ 2);

function foo(numArgs) {
  // push missing arguments, pop extra arguments
  for (var i = numArgs; i < 2; i++)
    stack.push(undefined);
  for (var i = numArgs; i > 2; i--)
    stack.pop();

  // analogous to the <a href="http://en.wikipedia.org/wiki/Frame_pointer#Structure">frame pointer</a> register
  var firstLocal = stack.length;

  // push local 'a'
  stack.push(undefined);

  // var a = x + y:
  stack[firstLocal] = stack[firstLocal - 2] + stack[firstLocal - 1];

  // prepare stack for call to 'bar(a)':
  stack.push(stack[firstLocal]);
  return bar(/* number of arguments pushed = */ 1);

  // in this calling convention, the callee pops the arguments
  stack.pop(); // pop 'a'
  stack.pop(); // pop 'y'
  stack.pop(); // pop 'x'
}
</pre>
<p>With this strategy, a JIT compiler can do some pretty great optimization.  To start with, each read from or write to <code>stack</code> in the above JS can be compiled down to a single CPU load or store.  This is achieved by caching the address of <code>stack[firstLocal]</code> in a register and rolling the remaining &#8220;<code>+&nbsp;INDEX</code>&#8221; into the load instruction as an <a href="http://en.wikipedia.org/wiki/Effective_address#Base_plus_offset.2C_and_variations">offset</a>.  Even better, modern JavaScript JIT compilers do register allocation which can avoid the loads/stores altogether.  (Register allocation has been in Firefox since version 3.5.)</p>
<p>In summary, we can do pretty efficient things for local variable access, but only with some stringent restrictions.</p>
<h2>Fast non-local access</h2>
<p>While we shouldn&#8217;t expect great performance when functions call <code>eval</code> or <code>arguments</code>, the requirement made in the previous section that we only access local variables is pretty harsh and conflicts with both the <a href="http://www.joelonsoftware.com/items/2006/08/01.html">functional</a> and <a href="http://javascriptplayground.com/blog/2012/04/javascript-module-pattern">module</a> patterns of JavaScript programming.  In this section, we&#8217;ll optimize non-local access.</p>
<p>We start with the observation that, in the absence of <code>eval</code> and other weirdos, there is no need for a fully dynamic scope lookup: we can know exactly where on the scope chain to find the variable being accessed.  The first step is to view each top-level function as a tree of nested functions, giving each node (function) in the tree an array of the variables defined in its scope.  For example, given this function:</p>
<pre>
function add3(arg1, arg2, arg3) {
  function addInner(innerArg1) {
    function innermost() { return innerArg1 + arg2 + getArg3() };
    return innermost();
  }
  function getArg3() {
    return arg3;
  }
  return addInner(arg1);
}
</pre>
<p>we can distill the following tree:</p>
<pre>
function add3: [arg1, arg2, arg3, addInner, getArg3]
 |\_ function addInner: [innerArg1, innermost]
 |    \_ function innermost: []
  \_ function getArg3: []
</pre>
<p>The next step is to include uses as leaves of the tree that are linked to the innermost enclosing definition with the same name.  Rather than drawing terrible ASCII-art arrows, let&#8217;s represent a use-to-definition arrow with a two-number coordinate:</p>
<ul>
<li><em>hops</em> = the number of nodes in the tree to skip to get to the function node whose array contains the definition.</li>
<li><em>index</em> = the index of the definition in the function node&#8217;s array.</li>
</ul>
<p>Linking uses to definitions in the above tree produces:</p>
<pre>
function add3: [arg1, arg2, arg3, addInner, getArg3]
 |\_ function addInner: [innerArg1, innermost]
 |    |\_ function innermost: []
 |    |    |\_ "innerArg1"   {hops=1, index=0}
 |    |    |\_ "arg2"        {hops=2, index=1}
 |    |     \_ "getArg3"     {hops=2, index=4}
 |     \_ "innermost":       {hops=0, index=1}
 |\_ function getArg3: []
 |     \_ "arg3"             {hops=1, index=2}
 |\_ "addInner"              {hops=0, index=3}
 |\_ "getArg3"               {hops=0, index=4}
  \_ "arg1"                  {hops=0, index=0}
</pre>
<p>As a last step, we&#8217;ll erase all variables that only have local uses.  We can also remove entire scopes if they are empty; we just need to be mindful not to include these removed scopes in any <code>hops</code> count.  Applying this last transformation produces the following, final tree:</p>
<pre>
function add3: [arg2, arg3, getArg3]
 |\_ function addInner: [innerArg1]
 |     \_ function innermost: <no scope>
 |         |\_ "innerArg1"   {hops=0, index=0}
 |         |\_ "arg2"        {hops=1, index=0}
 |          \_ "getArg3"     {hops=1, index=2}
 |\_ function getArg3: <no scope>
 |     \_ "arg3"             {hops=0, index=1}
  \_ "getArg3"               {hops=0, index=2}
</pre>
<p>With this analysis, we have all the information we need to efficiently compile the program.  For the local-only variables that we removed in the last step, we can use the stack directly (as in the <a href="#fast-local">second section</a>).  For variables with non-local access, we can represent the scope chain as a linked list of scopes (as in the <a href="#dynamic-lookup">first section</a>), except this time we represent scopes as <em>arrays</em> instead of <em>maps</em>.  To compile an access, we use <code>{hops,index}</code> coordinate: <code>hops</code> tells us how many <code>.enclosing</code> links to follow, <code>index</code> tells us the index in the array.</p>
<p>Applying this scheme to the original example (and eliding the missing/extra arguments boilerplate) produces the following translated JS (with the scope access code highlighted in <font color=red>red</font>):</p>
<pre>
function add3() {
  var firstLocal = arguments.length;

  // the optimized scope of add3 is: [arg2, arg3, getArg3]
  var scope = [stack[firstLocal-2], stack[firstLocal-1], undefined];
  scope.enclosing = window;

  // initialize 'addInner':
  stack.push(function addInner() {
    var firstLocal = arguments.length;

    // the optimized scope of addInner is: [innerArg1]
    var scope = [stack[firstLocal - 1]];
    scope.enclosing = addInner.enclosing;

    // push local 'innermost'
    stack.push(function innermost() {
      // the scope of innermost is completely optimized away
      var scope = innermost.enclosing;

      // return innerArg1 {hops=0, index=0} +
      //        arg2      {hops=1, index=0} +
      //        getArg3() {hops=1, index=2}
      return <font color=red>scope[0]</font> +
             <font color=red>scope.enclosing[0]</font> +
             (<font color=red>scope.enclosing[2]</font>)();
    });
    stack[firstLocal].enclosing = scope;

    // return innermost()
    var returnValue = (stack[firstLocal])();
    stack.pop();  // pop 'innermost'
    stack.pop();  // pop 'innerArg1'
    return returnValue;
  });
  stack[firstLocal].enclosing = scope;

  // initialize 'getArg3' {hops=0, index=2}:
  scope[2] = function getArg3() {
    // the scope of getArg3 is completely optimized away
    var scope = getArg3.enclosing;

    // return arg3 {hops=0, index=1}
    return <font color=red>scope[1]</font>;
  }
  scope[2].enclosing = scope;

  // return addInner(arg1)
  stack.push(stack[firstLocal - 3]);
  var returnValue = (stack[firstLocal])();
  stack.pop();  // pop 'addInner'
  stack.pop();  // pop 'arg3'
  stack.pop();  // pop 'arg2'
  stack.pop();  // pop 'arg1'
  return returnValue;
}
</pre>
<p>JS performance experts will point out that putting a named property on an array triggers a deoptimization in some JS engines (including, until <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=586842">bug 586842</a> lands, SpiderMonkey).  Let&#8217;s pretend it doesn&#8217;t; after all, we could just reserve <code>scope[0]</code> as the <code>enclosing</code> link.</p>
<p>This strategy is good for JIT compilation in several ways:</p>
<ul>
<li>If a variable is only accessed locally, it can still live on the stack and receive full JIT optimization.</li>
<li>Each <code>.enclosing</code> expression compiles to a single load instruction.  Furthermore, when there are multiple accesses to variables in the same scope, the compiler can factor out the common scope walking.</li>
<li>Since a non-local name access in this scheme is much simpler than the name cache mentioned earlier, IonMonkey is more able to apply the optimizations it uses for local names such as <a href="http://en.wikipedia.org/wiki/Loop-invariant_code_motion">LICM</a>, <a href="http://en.wikipedia.org/wiki/Global_value_numbering">GVN</a>, and <a href="http://en.wikipedia.org/wiki/Dead_code_elimination">DCE</a>.</li>
</ul>
<p>In summary, we&#8217;ve now optimized non-local access while keeping local access fast.  There are several other optimizations related to scopes that soften the blow when <code>eval</code> or <code>arguments</code> is used, but I think this is a good stopping point.</p>
<h2>Next steps</h2>
<p>The recent scope project basically catches us up to the level of other JS VMs.  I should also note that functional languages have been doing similar optimizations <a href="ftp://publications.ai.mit.edu/ai-publications/pdf/AITR-474.pdf">forever</a>.  Looking forward, there are some <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=784839">straightforward</a> optimizations I think we could do to avoid creating scope objects as well as more <a href="http://flint.cs.yale.edu/flint/publications/escc.html">advanced</a> optimizations we can lift from the functional crowd.</p>
<h2>In SpiderMonkey</h2>
<p>If you are interested in seeing the code for all this in SpiderMonkey, you can use the following links to get started:</p>
<ul>
<li>The <code>{hops,index}</code> coordinate is called <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/vm/ScopeObject.h#l79">ScopeCoordinate</a>.</li>
<li>The various scope objects are described in this <a href="http://hg.mozilla.org/mozilla-central/file/2359243ee2b1/js/src/vm/ScopeObject.h#l111">ASCII-art tree</a>.  (Note, for mostly historical reasons, we use the same underlying representation for objects and scopes.  Due to the <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/jsscope.h#l32"><code>Shape</code></a> mechanism (which is pre-generated for scopes at compile-time), scopes are still, effectively, arrays.)</li>
<li>Optimized non-local access is performed with <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/jsopcode.tbl#l331">ALIASEDVAR</a> opcodes.  See the implementation of these ops in the <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/jsinterp.cpp#l2794">interpreter</a> and <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/ion/IonBuilder.cpp#l6272">IonMonkey jit</a>.</li>
<li>The frontend name analysis is a bit old and messy (and will hopefully be rewritten sometime in the near future).  However, the important part of the analysis is at the very end, when we emit the ALIASEDVAR ops in <a href="http://hg.mozilla.org/mozilla-central/file/df69d95f636c/js/src/frontend/BytecodeEmitter.cpp#l908"><code>EmitAliasedVarOp</code></a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2012/10/02/optimizing-javascript-variable-access/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JSRuntime is now officially single-threaded</title>
		<link>http://blog.mozilla.org/luke/2012/01/24/jsruntime-is-now-officially-single-threaded/</link>
		<comments>http://blog.mozilla.org/luke/2012/01/24/jsruntime-is-now-officially-single-threaded/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 07:07:46 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=276</guid>
		<description><![CDATA[Given this title, a reasonable reaction would be: Wait, wait, single threaded?!  But isn&#8217;t that, like, the wrong direction for the multicore present and manycore future? so let me start by clearing this up: A single SpiderMonkey runtime (that is, &#8230; <a href="http://blog.mozilla.org/luke/2012/01/24/jsruntime-is-now-officially-single-threaded/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Given this title, a reasonable reaction would be:</p>
<blockquote><p>
Wait, wait, <em>single</em> threaded?!  But isn&#8217;t that, like, the wrong direction for the multicore present and manycore future?
</p></blockquote>
<p>so let me start by clearing this up:<br />
<strong><br />
A single SpiderMonkey runtime (that is, instance of <code>JSRuntime</code>) &#8212; and all the objects, strings and contexts associated with it &#8212; may only be accessed by a single thread at any given time.  However, a SpiderMonkey embedding may create multiple runtimes in the same process (each of which may be accessed by a different thread).<br />
</strong><br />
That means it is up to the embedding to provide communication (if any) between the runtimes via <code>JSNative</code> or other SpiderMonkey hooks.  One working example is the <a href="http://mxr.mozilla.org/mozilla-central/source/dom/workers/">new implementation</a> of <a href="http://dev.w3.org/html5/workers/">web workers</a> in Firefox which uses a runtime per worker.  Niko Matsakis is experimenting with a different architecture in his new <a href="http://smallcultfollowing.com/babysteps/blog/2012/01/09/parallel-javascript/">parallel JS project</a>.</p>
<p>So that&#8217;s the quick summary.  Now, for the interested, I&#8217;ll back up and explain the situation, how we got here, and where we are going in more detail.</p>
<h3>Ghosts of SpiderMonkey past</h3>
<p>In the beginning, as Brendan explains, Java-style big-shared-mutable-heap concurrency was all the rage and so, as Java&#8217;s kid brother, SpiderMonkey also had big-shared-mutable-heap concurrency.  Now, locks weren&#8217;t ever (afaik) exposed to JS as part of SpiderMonkey, but an embedding could add them easily with a <code>JSNative</code>.  However, SpiderMonkey did support concurrent atomic operations on objects with a clever (<a href="http://www.google.com/patents/US6892200">patented</a>, even) locking scheme that avoided synchronization overhead for most operations.</p>
<p>This initial threading design stayed in place until about a year before Firefox 4.0 when the <a href="http://andreasgal.com/2010/10/13/compartments/">compartments</a> project picked up steam.  The key new concept introduced by this project was, well, the <em>compartment</em>. A runtime contains a set of compartments and each compartment contains a set of objects.  Every object is in exactly one compartment and any reference between objects in different compartments must go through a wrapper.  With compartments and wrappers, you can implement a sort of membrane that is useful for all kinds of things: GC, security boundaries, JIT compilation invariants, memory accounting, and <a href="http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies">JS proxies</a>.  Overall, I would say that compartments are one honking great idea.</p>
<p>The important thing about compartments for this story, though, is that the implementation effort really wanted single-threaded access to everything in a compartment.  To be honest, I don&#8217;t know the particular technical issue raised at the time, but it isn&#8217;t hard to see how single-threaded-ness was a necessary simplification for such a challenging plan (viz., shipping compartments with Firefox 4).  Anyway, the decision was made and compartments became single-threaded.</p>
<p>After Firefox 4 another great choice was made to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=649537">rewrite Firefox&#8217;s implementation of web workers</a> to not use XPConnect and to instead create a new runtime per worker.  The choice was made because, even though a runtime allowed multi-threaded execution, there were still some <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=617569">global</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=654265">bottlenecks</a> such as GC and allocation that were killing workers&#8217; parallelism.</p>
<h3>I&#8217;m Talking About Drawing a Line in the Sand</h3>
<p>With web workers in separate runtimes, there were no significant multi-threaded runtime uses remaining.  Furthermore, to achieve single-threaded compartments, the platform features that allowed JS to easily ship a closure off to another thread had been removed since closures fundamentally carry with them a reference to their original enclosing scope.  Even non-Mozilla SpiderMonkey embeddings had reportedly experienced problems that pushed them toward a similar shared-nothing design.  Thus, there was little reason to maintain the non-trivial complexity caused by multi-threading support.</p>
<p>There are a lot of things that &#8220;would be nice&#8221; but what pushed us over the edge is that a single-threaded runtime allows us to hoist a lot data currently stored per-compartment into the runtime.  This provides <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=720753#c0">immediate memory savings</a> and also enables another <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=650353">big change</a> we want to make that would create a lot more compartments (and thus needs compartments to be lighter-weight).</p>
<p>Thus, the decision was made to try to make SpiderMonkey single-threaded as an API requirement.  A <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=650411">bug</a> was filed in April 2011 and an <a href="http://groups.google.com/group/mozilla.dev.tech.js-engine/msg/ae5f22f39e4fd150">announcement</a> was made on dev.tech.js-engine a month after.</p>
<h3>Across this line you do not&#8230;</h3>
<p>April 2011 to&#8230; January 2012&#8230; what took so long?</p>
<p>Well, to begin with, there were quite a few minor uses of <code>JSRuntime</code> off the main thread that had to be chased down.  Also, each of these cases required understanding new parts of the codebase and, in several cases, waiting a few months for other kind-hearted, but very busy, Mozillians to fix <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=679140">things</a> for me.  The biggest problem was xpcom proxies (not to be confused with JS proxies, which are awesome).  Fortunately, Benjamin Smedberg already had a beef with <code>xpcom/proxy</code> and (just recently) <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=675221">nuked the whole directory from orbit</a>.</p>
<p>After getting try server to pass without hitting any of the 10,000 places where single-thread-ness gets verified in debug builds, we couldn&#8217;t exactly just rip out the multi-threading support.  The worry we had was that some popular add-ons would break the whole browser and we&#8217;d be faced with an uncomfortable backout situation.  Thus, we landed a simple patch that asserts single-threaded-ness in a few pinch points <em>in release builds</em> and waited for the assert to make its way to a bigger audience.  (I think this is a great example of how the rapid-release process enables developers.)</p>
<p>As of right now, the assert is in Firefox 10 Beta and slated to be released on January 31st.  There are <del datetime="2012-02-08T22:04:37+00:00">three</del> four known offending extensions:</p>
<ul>
<li>The <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=704249">IcedTea Java plugin</a> on Linux seems to hit the assert for some applets. [Update: this was reported fixed in version 1.2pre]</li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=715744">BExternal.dll</a> and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=715748">gemgecko.dll</a> are touching the main-thread only pref service off the main thread (already a bug) which ends up calling a JS observer.  [Update: Both Gemius and Babylon seem to have shipped fixes]
<li>[UPDATE] The <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=715757#c9">DivX plugin</a>.</li>
</ul>
<p>Based on these results, we are concluding that the invariant &#8220;stuck&#8221; and thus we can actually make changes that assume single-threaded-ness.  Indeed, the first <a href="https://hg.mozilla.org/integration/mozilla-inbound/rev/e517d4c43143">bomb</a> has been dropped (taking along 2200 lines of code along with it, and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=720045">this</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=720013">is</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=680562">just</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=720018">the</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=719858">beginning</a>).</p>
<h3>The single-threaded invariant in detail</h3>
<p>Each runtime now has an &#8220;owner thread&#8221; (<code>JSRuntime::ownerThread</code>).  The &#8220;owner thread&#8221; is the id of the only OS thread allowed to touch the runtime.  This owner thread is set to the current thread (<code>PR_GetCurrentThread()</code>) from <code>JS_NewRuntime</code> and may only be changed &#8212; when no JS is executing in the runtime &#8212; via <code><a href="http://mxr.mozilla.org/mozilla-central/ident?i=JS_ClearRuntimeThread">JS_ClearRuntimeThread</a></code>/<code><a href="http://mxr.mozilla.org/mozilla-central/ident?i=JS_SetRuntimeThread">JS_SetRuntimeThread</a></code>.  Virtually every JSAPI function that takes a <code>JSContext</code> parameter will assert that <code>PR_GetCurrentThread == cx->runtime->ownerThread()</code>.</p>
<p>It should be mentioned that there are still a few remaining sources of concurrency:</p>
<ul>
<li>The <a href="http://mxr.mozilla.org/mozilla-central/ident?i=GCHelperThread">background-sweeping thread</a> cleans up garbage objects which don&#8217;t have finalizers.  Its interaction with the VM is pretty well isolated to the GC.</li>
<li>Pretty much the only JSAPI function that can be called off the main thread is <a href="http://mxr.mozilla.org/mozilla-central/search?string=JS_TriggerOperationCallback">JS_TriggerOperationCallback</a>.  This is how the the <a href="http://mxr.mozilla.org/mozilla-central/ident?i=WatchdogMain">watchdog thread</a> stops runaway JS.  Fortunately, the interaction with the VM is through a single field: <code>JSRuntime::interrupt</code>.</li>
</ul>
<p>One last thing to point out is that SpiderMonkey&#8217;s architecture will likely continue evolving to meet new concurrency needs.  Indeed, concurrent runtimes may one day return in a more restricted and structured form.  But maybe not; we&#8217;ll see.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2012/01/24/jsruntime-is-now-officially-single-threaded/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Ubuntu+GNOME Shell: open-source ecosystem win</title>
		<link>http://blog.mozilla.org/luke/2011/10/18/ubuntugnome-shell-open-source-ecosystem-win/</link>
		<comments>http://blog.mozilla.org/luke/2011/10/18/ubuntugnome-shell-open-source-ecosystem-win/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 18:15:55 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=285</guid>
		<description><![CDATA[I recently upgraded to Ubuntu 11.10.  That means I finally had to bite the bullet and figure out what I wanted to do about this whole new fancy-shell business; do I reject these encroachments on my established workflow or embrace &#8230; <a href="http://blog.mozilla.org/luke/2011/10/18/ubuntugnome-shell-open-source-ecosystem-win/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I recently upgraded to Ubuntu 11.10.  That means I finally had to bite the bullet and figure out what I wanted to do about this whole new fancy-shell business; do I <a href="http://www.youtube.com/watch?v=Z-moXUALZtw">reject these encroachments on my established workflow</a> or embrace the new hotness?  Trying not to be too much of a Luddite, I decided to make the leap to the new hotness.</p>
<p>But where to leap to?  <a href="http://unity.ubuntu.com/">Unity</a> or <a href="http://www.gnome.org/gnome-3/">GNOME Shell</a>?  I expected that this would be some sort of big decision that determined what apps I could run and would take a lot of time if I wanted to try it out.  But no, getting both Unity and GNOME Shell on the same desktop was as easy as <code>sudo apt get install gnome-shell</code> from a vanilla upgrade of Ubuntu.  Toying around with each was as simple as choosing from the drop-down list in the login manager.  Everything just worked.</p>
<p>Now, maybe you&#8217;re all like &#8220;Duh, that&#8217;s what it should be; that you would be impressed by this shows how broken the system is and how your thinking is warped.  Eyhhh&#8221;.  Yeah, well I&#8217;m like <a href="http://www.youtube.com/watch?v=Xz7_3n7xyDg">whatever</a>.  Consider all the things that had to come together to make this possible.  You need the separation of window manager, desktop environment, an applications;  you need a packaging discipline that let&#8217;s all this coexist without clobbering each other; you need software broken into nice little pieces; you need Canonical making good choices, etc.</p>
<p>In the end (after a few hours of experimenting with my workflow) I prefer GNOME Shell (to Unity but also to GNOME 2).  In theory, I should switch to Fedora since it uses GNOME Shell, but I&#8217;ve been really happy with Ubuntu as a whole.  Thus, I&#8217;m sticking with a Ubuntu+GNOME Shell hybrid and I think it&#8217;s awesome that I have that choice.  Not strictly, but this seems like the type of thing that can only happen in the distributed-development model open source software.  There are still all sorts of problems to be solved for the Linux desktop, but things like this give me hope for the long-term outlook of the desktop and of the broader open-source ecosystem.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2011/10/18/ubuntugnome-shell-open-source-ecosystem-win/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Boot To Gecko misconceptions</title>
		<link>http://blog.mozilla.org/luke/2011/09/16/boot-to-gecko-misconceptions/</link>
		<comments>http://blog.mozilla.org/luke/2011/09/16/boot-to-gecko-misconceptions/#comments</comments>
		<pubDate>Sat, 17 Sep 2011 01:42:20 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=250</guid>
		<description><![CDATA[I&#8217;m all jazz hands about Boot To Gecko (B2G). I think B2G is really important to the Mozilla mission.  Perhaps stemming from the early-and-open nature of B2G, there are some misconceptions about B2G that I&#8217;ve seen in articles and forums. &#8230; <a href="http://blog.mozilla.org/luke/2011/09/16/boot-to-gecko-misconceptions/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m all jazz hands about <a href="https://wiki.mozilla.org/B2G">Boot To Gecko</a> (B2G). I think B2G is really important to the <a href="http://www.mozilla.org/about/mission.html">Mozilla mission</a>.  Perhaps stemming from the early-and-open nature of B2G, there are some misconceptions about B2G that I&#8217;ve seen in articles and forums. I am not closely involved in the project, but I do know enough to identify and correct a few of these misconceptions with the following three B2G facts:</p>
<ol>
<li><strong>B2G will not run in kernel mode</strong>.  To be clear, B2G will run on top of the Linux kernel; Gecko will run as user-mode processes.  Furthermore, a crash in Gecko will not take down the entire phone: with Electrolysis (<a href="https://wiki.mozilla.org/Electrolysis#Fennec_OOP-Tabs_Phase_I_.28Done.29">already being used in Firefox Mobile</a>), different apps/sites will run in different processes.</li>
<li><strong>B2G will (ultimately) not run on top of Android</strong>.  To bootstrap the project, work is currently being done on top of Android.  However, the goal is to incrementally remove each dependency on Android, leaving only drivers and low-level libraries.  In particular, this means B2G would not contain the <a href="http://en.wikipedia.org/wiki/Dalvik_%28software%29">Dalvik Java VM</a> which should significantly improve the <a href="http://news.cnet.com/8301-10805_3-20103309-75/microsoft-inks-android-and-chrome-patent-deals/">patent</a>-<a href="http://news.cnet.com/8301-13860_3-20003602-56.html">encumbered</a> <a href="http://en.wikipedia.org/wiki/Dalvik_%28software%29#Licensing_and_patents">Java</a> <a href="http://www.dailyfinance.com/2011/09/16/google-acquires-1023-ibm-patents-to-shore-up-andro/">situation</a> as well as reduce the number of VMs needed to browse the web from 2 to 1.</li>
<li><strong>B2G will use Gecko, but it&#8217;s not just about Gecko</strong>.  A clearer name might have been &#8220;Boot to Web platform&#8221;.  Gecko will, of course, be the engine used to prototype new <a href="http://hacks.mozilla.org/2011/08/more-details-about-the-webapi-effort/">Web APIs</a> but since these are targeted at open standards developed in the open (as opposed to <a href="http://gotocon.com/aarhus-2011/presentation/Opening%20Keynote:%20Dart,%20a%20new%20programming%20language%20for%20structured%20web%20programming">dumped in the open</a>), a possible/desirable outcome is a separate &#8220;Boot To Webkit&#8221; implementation able to run the same home screen and apps as B2G.</li>
</ol>
<p>If you are excited, feel free to <a href="https://wiki.mozilla.org/B2G#Contributing">contribute</a> to the project; it&#8217;s just starting and there are many important problems to be solved.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2011/09/16/boot-to-gecko-misconceptions/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Old Dijkstra Essays Considered</title>
		<link>http://blog.mozilla.org/luke/2011/08/12/old-dijkstra-essays-considered/</link>
		<comments>http://blog.mozilla.org/luke/2011/08/12/old-dijkstra-essays-considered/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 09:08:05 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=133</guid>
		<description><![CDATA[Sometime when I was an undergraduate, I came across a news article announcing that all the EWDs has been published online.  After figuring out what EWD meant (EWD are Dijkstra&#8217;s initials; he used &#8220;EWD&#8221; followed by a number to index &#8230; <a href="http://blog.mozilla.org/luke/2011/08/12/old-dijkstra-essays-considered/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Sometime when I was an undergraduate, I came across a news article announcing that all the EWDs has been <a href="http://www.cs.utexas.edu/users/EWD/">published online</a>.  After figuring out what EWD meant (EWD are Dijkstra&#8217;s initials; he used &#8220;EWD&#8221; followed by a number to index his essays), I started reading a few and got hooked.  For having an ivory-tower sort of reputation (stemming from opinions on <a href="http://www.amazon.com/Discipline-Programming-Edsger-W-Dijkstra/dp/013215871X">formal verification</a> and <a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD10xx/EWD1036.html">how computer science should be taught</a>), it was surprising how personable, humble and clear his writing is.  Many of the essays are handwritten and even his handwriting style is delightful (someone even turned it into a <a href="http://www.google.com/search?btnG=1&amp;pws=0&amp;q=dijkstra+font+">font</a>).</p>
<p>For fun, I recently decided to re-read some of the outstanding EWDs to see how they sounded to me now; for the last few years I&#8217;ve been hacking on the Mozilla JS engine (<a href="https://developer.mozilla.org/en/SpiderMonkey">SpiderMonkey</a>) so presumably my perspective on software development has changed.  To my surprise, instead of finding the essays milder than remembered (as happens with movies that used to be terrifying (Critters) or incredibly awesome (Dino-Riders)), I found some new things relevant to what is happening now in SpiderMonkey.  That&#8217;s what I&#8217;d like to share in this post.</p>
<p>One of, if not the most, famous EWD is &#8220;<a href="http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF">Notes on Structured Programming</a>&#8221; (NOSP).  This essay is the expansion of the famous &#8220;<a href="https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF">Go To Statement Considered Harmful</a>&#8221; CACM article that started the &#8220;X considered harmful&#8221; and, more generally, &#8220;X considered Y&#8221; <a href="en.wikipedia.org/wiki/Considered_harmful">memes</a>.  Primarily, NOSP makes a well-reasoned argument for why it is better to use structured control flow constructs (like <em>if/then/else</em> and loops) than <em>goto</em>.  Great, we all get that &#8212; so much so that <em>goto</em> is now often rejected <em>a priori</em> despite having legitimate (albeit uncommon) applications (cf. Knuth&#8217;s &#8220;<a href="http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf">Structured programming with go to statements</a>&#8220;).</p>
<p>However, NOSP&#8217;s agenda is broader than just browbeating us into not using <em>goto</em><em></em>.  Dijkstra frames the <em>goto</em> issue with some general notes on making programs simpler and in the process states two principles of program simplicity that I really like.  He doesn&#8217;t announce them as principles &#8212; they&#8217;re just sentences buried in the middle of paragraphs &#8212; but they seem like principles to me&#8230; so I&#8217;ll call them principles.  Often, judging the simplicity of a patch or piece of code feels highly subjective and more a matter of taste than anything.  However, I was delighted to see how many simplifications (considering recent SpiderMonkey patches I&#8217;ve written or seen flying by) could be viewed as following from these two principles.</p>
<p>Let&#8217;s start with the first principle, taken from the following quote:</p>
<blockquote><p><em>In vague terms we may state the desirability that the structure of the program text reflects the structure of the computation.  Or, in other terms, &#8216;What can we do to shorten the conceptual gap between the static program text (spread out in &#8220;text space&#8221;) and the corresponding computations (evolving in time)?&#8217;</em></p></blockquote>
<p>For the specific case of <em>goto</em>, Dijkstra proceeds to spell out in great detail how structured control flow admits an unequivocally shorter conceptual gap.</p>
<p>In SpiderMonkey, many recent simplifications have simply been removing old uses of <em>goto</em> (e.g., check out <a href="http://hg.mozilla.org/mozilla-central/file/6deb7f5f7a71/js/src/jsgc.cpp#l3268">js_GC</a> before a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=553671">heroic set of patches by Jason Orendorff</a>, as well as <a href="http://hg.mozilla.org/mozilla-central/file/3bbd69ab9f70/js/src/jsobj.cpp#l1246">obj_eval</a> and <a href="http://hg.mozilla.org/mozilla-central/file/3bbd69ab9f70/js/src/jsinterp.cpp#l1100">js_Invoke</a> before several incremental rewritings).  I should note that switching SpiderMonkey to C++ a few years ago has been invaluable in control flow refactoring since with C++ comes <a href="http://www.hackcraft.net/raii/">RAII</a> which has <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsproxy.cpp#l688">been</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsapi.cpp#l123">used</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsregexp.h#l303">in</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsgc.cpp#l2488">practically</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.cpp#l1065">every</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsgc.cpp#l2750">big</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsarray.cpp#l1201">function</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsinterp.cpp#l636">cleanup</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jswatchpoint.cpp#l54">since</a>.</p>
<p>But there is a lot more to this &#8220;shortening the syntax/computation gap&#8221; than control flow level refactoring.  It seems to me that trying to encode more invariants and program structure in static types falls under this category since static typing entails statements of the form &#8220;for all executions, variables of this type must have some property&#8221;.  One recent banner example is Chris Leary&#8217;s recent <a href="http://hg.mozilla.org/tracemonkey/rev/3d646df22a4b#l8.38">refactoring of JSAtomList et al</a> into something far more <a href="http://www.lucacardelli.name/Papers/TypefulProg.pdf">typeful</a>.  As <a href="http://hg.mozilla.org/mozilla-central/file/3d646df22a4b/js/src/frontend/ParseMaps.h#l200">demonstrated</a> in his patch, C++ types often ends up simulating discriminated unions found in higher-level language (or, more generally, <a href="http://en.wikipedia.org/wiki/Algebraic_data_type">ADT</a>s).  Another example of this is the <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsvalue.h#l334">type representing a JavaScript value</a>.</p>
<p>Because of the, to put it kindly, <a href="http://en.wikipedia.org/wiki/Dependent_type">dependently typed</a> nature of many central SpiderMonkey data structures, types must often be bolted on, like an exoskeleton, to an underlying representation that is being treated like a bag of bits.  Here, C++&#8217;s unsafe casts, inlining, and templates are critical for avoiding performance penalties for using abstraction.  The <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/vm/Stack.h#l73">data structure that holds the JS call stack</a> is one example.  Another example is the recently-refactored <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsgc.h#l347">set</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jscell.h#l62">of</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=641027">types</a> iteratively concocted by Gregor Wagner, Igor Bukanov, and Bill McCloskey to abstract GC data structures.</p>
<p>Another interesting non-standard application of types can be seen in the recent refactoring of strings.  Here, the C++ <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/vm/String.h#l102">class hierarchy</a> captures the logical hierarchy of string invariants.  Unlike an ordinary C++ class hierarchy, the string hierarchy contains no virtual functions and all instances of the hierarchy are necessarily the same size.  JSObject is incrementally growing a <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/vm/GlobalObject.h">similar</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/vm/StringObject.h">hierarchy</a> (which I hope continues!).  In both cases, the C++ type system is being used (and sometimes abused) to provide the desired connection between static types and dynamic properties of strings/objects.</p>
<p>Finally, in the worst case, no language or type system will help you simplify the mapping from syntax to dynamic computation; you just need to suck it up and completely change tack.  An admirable example of this last year was Andreas Gal&#8217;s <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=558754">transformation of jsiter</a>.  It is a beautiful thing when a patch, in total, removes 500 lines and SunSpider gets 4% faster.</p>
<p>The second principle contained in NOSP that I&#8217;d like to point out comes from the following quote:</p>
<blockquote><p><em>Eventually, one of our aims is to make such well-structured programs that the intellectual effort (measured in some loose sense) needed to understand them is proportional to program length (measured in some equally loose sense).  In particular, <strong>we have to guard against an exploding appeal to enumerative reasoning</strong>, [...]</em></p></blockquote>
<p>To give a bit of context, &#8220;enumerative reasoning&#8221; is defined in the essay to mean the mode of reasoning where you are forced to consider every possible case and make sure the desired property holds for each of them individually.  Dijkstra contrasts this to the more desirable &#8220;abstractive&#8221; and &#8220;inductive&#8221; reasoning and explains how building up structured control flow allows their use instead of enumerative reasoning.</p>
<p>One example of this in SpiderMonkey is typified by pretty much any work that Jeff Walden does.  In his patches (and, as the style spreads, others&#8217; too), <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsfun.cpp#l2045">each</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.cpp#l881">step</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.cpp#l1514">of</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.cpp#l2441">the</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.cpp#l5785">implementation</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.h#l1828">is</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsobj.h#l268">made</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsinterp.cpp#l4654">to</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsstr.cpp#l2441">correspond</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsfun.cpp#l1845">closely</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsfun.cpp#l1971">to</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsonparser.cpp#l190">the</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l150">individual</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l283">steps</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l377">of</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l462">the</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l543">corresponding</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l593">ECMAScript</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/json.cpp#l751">sections</a>, complete with comments labeling the steps.  This reduces enumerative reasoning by allowing one to judge the spec-conformance of an individual statement instead of an entire function.</p>
<p>Another way enumerative reasoning is reduced is by simply having less code.  This of course is Reusability, the Holy Grail of Software Engineering (apparently, a <a href="http://msdn.microsoft.com/en-us/library/aa260679%28v=vs.60%29.aspx">solved problem</a>).  One of the biggest examples of this I can think of is the security wrapper rewrite that was part of the <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=compartments">mammoth</a> <a href="http://andreasgal.com/2010/10/13/compartments/">compartmentalization</a> effort.  Allegedly, thousands of lines of mind-bending security-critical code were removed, replaced by a small set of <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/xpconnect/wrappers/FilteringWrapper.h">composable</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/xpconnect/wrappers/XrayWrapper.h">policy</a> <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/xpconnect/wrappers/CrossOriginWrapper.h">templates</a>.  And if that wasn&#8217;t enough, <a href="http://wiki.ecmascript.org/doku.php?id=harmony:proxies">harmony:proxies</a> got to ride along at a <a href="http://hg.mozilla.org/mozilla-central/file/f262c389193e/js/src/jsproxy.cpp#l462">bargain rate</a>!</p>
<p>That last class of enumerative-reasoning-reducing changes that come to mind are those that cut down on the number of VM-wide concepts &#8212; be they states, requirements, corner cases, gotchas, possibilities, etc &#8212; that must be kept in mind to effectively work on the SpiderMonkey.  Examples from recent memory include the removal of: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=558451">JSScope</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=581263">slow natives</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=637985">watchpoint</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=589015">hacks</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=648647">JSObjectMap</a>, <a href="http://hg.mozilla.org/mozilla-central/rev/183f04be1d45">GC-from-malloc</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=650411">concurrent JSRuntime access</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=519949">local rooting scopes</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=572057">newborn roots</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=577708">display optimizations</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=606029">multi-threaded objects and titles</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=compartments">multi-threaded strings</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=535656">dormant stack frames</a>, <a href="http://whereswalden.com/2010/04/06/more-changes-coming-to-spidermonkey-the-magical-__count__-property-of-objects-is-being-removed/">__count__</a>, <a href="http://whereswalden.com/2010/05/07/spidermonkey-change-du-jour-the-special-__parent__-property-has-been-removed/">__parent__</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=549143">non-identifier atoms, heap-doubles, null-is-an-object, the no-int-valued-doubles-in-values rule</a>&#8230; and those are just things that appeared on my radar; a simple <a href="https://bugzilla.mozilla.org/buglist.cgi?list_id=1072227&amp;short_desc=remove&amp;resolution=---&amp;resolution=FIXED&amp;resolution=INVALID&amp;resolution=WONTFIX&amp;resolution=DUPLICATE&amp;resolution=WORKSFORME&amp;resolution=INCOMPLETE&amp;resolution=EXPIRED&amp;resolution=MOVED&amp;classification=Components&amp;query_format=advanced&amp;bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;bug_status=RESOLVED&amp;bug_status=VERIFIED&amp;bug_status=CLOSED&amp;short_desc_type=allwordssubstr&amp;component=JavaScript%20Engine&amp;product=Core">bugzilla search for &#8220;remove&#8221;</a> shows a lot more.</p>
<p>Altogether, I think this demonstrates that these two simplification principles cover a lot of real-world patches.  It&#8217;s neat to find them nestled in a 40 year old essay written when <em>goto</em> still ruled the land.</p>
<p>On a side note, I think continual simplification is vital to maintaining a healthy, long-lived codebase.  Thus, I see the size of the &#8212; far from complete&#8211; set of simplifications listed above to be a very good sign for an already <a href="http://brendaneich.com/2011/06/new-javascript-engine-module-owner/">rather long-lived</a> codebase.</p>
<p>I&#8217;ll conclude with the summary of a section in NOSP entitled &#8220;On Our Inability To Do Much&#8221;:</p>
<blockquote><p><em>Summarizing: as a slow-witted human being I have a very small head and I had better learn to live with it and to respect my limitations and give them full credit, rather than to try to ignore them, for the latter vain effort will be punished by failure.</em></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2011/08/12/old-dijkstra-essays-considered/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>new mozilla::indonesia::Kumi()</title>
		<link>http://blog.mozilla.org/luke/2011/06/20/new-mozillaindonesiakumi/</link>
		<comments>http://blog.mozilla.org/luke/2011/06/20/new-mozillaindonesiakumi/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 16:51:26 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=89</guid>
		<description><![CDATA[Over the weekend I constructed a 3D Kumi from this 2D pattern which my two year old has been so kind as to demonstrate in a picture: If you were wondering, Kumi is a creation of the Mozilla Indonesia community.  &#8230; <a href="http://blog.mozilla.org/luke/2011/06/20/new-mozillaindonesiakumi/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Over the weekend I constructed a 3D Kumi <a href="http://blog.mozilla.org/luke/files/2011/06/kumi-3d.pdf">from this 2D pattern</a> which my two year old has been so kind as to demonstrate in a picture:</p>
<p><a href="http://blog.mozilla.org/luke/files/2011/06/scott-kumi.jpg"><img class="aligncenter size-medium wp-image-94" title="scott-kumi" src="http://blog.mozilla.org/luke/files/2011/06/scott-kumi-196x300.jpg" alt="3D Kumi" width="196" height="300" /></a></p>
<p>If you were wondering, Kumi is a creation of the Mozilla Indonesia community.  You can&#8217;t quite see it from the photo, but Kumi is wearing the traditional dress of Balinese <a href="http://en.wikipedia.org/wiki/Kecak">Kecak</a> Dancer.  The Mozilla Indonesia community has also created a <a href="http://blog.mozilla.org/luke/files/2011/06/kumi1.png">number</a> of <a href="http://blog.mozilla.org/luke/files/2011/06/kumi2.png">other</a> <a href="http://blog.mozilla.org/luke/files/2011/06/kumi3.png">variations</a> on <a href="http://blog.mozilla.org/luke/files/2011/06/kumi4.png">Kumi</a> that feature different cultural regions.  Another fun fact that you may have <a href="http://blog.mozilla.org/gen/2010/10/01/mozilla-indonesia-community-update/">already seen</a> is that Firefox market share in Indonesia is incredibly high, somewhere around 80%!  Clearly, this is a pretty hip group :-)</p>
<p>A little over a month ago, I had the chance to visit Indonesia along with my wife and some of my Mountain View based coworkers (Christian Legnitto, <a href="http://blog.mozilla.org/dmandelin/2011/05/19/firefox-4-release-parties-in-indonesia/">Dave Mandelin</a> and the Bieber-esque <a href="http://www.bailopan.net/blog/?p=900">David Anderson</a>) for the local Firefox 4 release parties.  It was an amazing experience and the country was really hospitable.  In particular, we had two incredible hosts.  One was <a href="http://www.vikingkarwur.com">Viking Karwur</a>, a freelance web-developer in Jakarta, who I think is something like a general or commander in the Mozilla Indonesia community.  He worked with a bunch of different local groups in Indonesia to plan some really successful release parties; if you look under the &#8220;Largest Firefox Communities&#8221; header on the <a href="http://www.meetup.com/Firefox/">Firefox 4 Release Party site on meetup.com</a> 7 of the cities are in Indonesia!  The other gracious host was <a href="http://yopdesign.com/">Yofie Setiawan</a>, another freelance web-developer in Jakarta.  Yofie was kind enough to take Jenn and I around the city including a market so Jenn could find some <a href="http://en.wikipedia.org/wiki/Batik">Batik</a> cloth to take back home.</p>
<p>One great thing about the trip was getting to hear what aspects of Firefox mattered to the Indonesian community.  Pretty much the number one thing I heard was Firefox memory usage, so I&#8217;m glad that Nicholas Nethercote and others have started this new <a href="https://wiki.mozilla.org/Performance/MemShrink">MemShrink</a> push (you can see a stream of updates on Nick&#8217;s <a href="http://blog.mozilla.org/nnethercote/">blog</a>).  I also think this <a href="https://wiki.mozilla.org/Electrolysis">Electrolysis</a> effort should help since closing a process should hopefully sweep away any leaked garbage associated with a page when it closes.  Also, on a practical level, I wonder how much of a free perception boost Chrome gets since its total resource usage is spread between many processes that may not all be visible to the user when they open Task Manager / Activity Monitor.</p>
<p>I also heard a lot of requests for Firefox Mobile on BlackBerry&#8230; nothing much positive I can say there&#8230; but also Firefox Mobile on iPhone.  Now, Apple Terms and Conditions seem to clearly lock us out of putting Firefox Mobile in the app store so I think its great how we&#8217;ve taken the positive/constructive route by creating <a href="http://www.mozilla.com/mobile/home/">Firefox Home</a>.  But, and I&#8217;m totally shooting in the dark here, wouldn&#8217;t it be cool if we put real development effort behind a Firefox Mobile that ran on jail-broken iPhones?  Is that an illegal activity?  Would that cause our legit Firefox Home app to get booted?  If nothing else, it seems like it would be useful for Mozilla to rattle the gates here to point out how Apple is locking out a browser that IMHO offers a superior mobile browsing experience (its the only reason I have and continue to use my <a href="http://en.wikipedia.org/wiki/Motorola_Atrix">Motorola Atrix</a>).</p>
<p>While I am shooting uniformed questions out into the InterWebz, another question came up while in Indonesia: this Kumi artwork that I linked to at the top of my post is a really neat fusion of Mozilla and local Indonesia culture.  Is there any good extension points in the Indonesian Firefox where Kumi could be featured?  The first thought that came to mind is in the &#8220;About Firefox&#8221; window, perhaps in the whitespace to the bottom-left of the giant official Firefox logo.  I know there is value in having a uniform experience across Firefoxen, but perhaps there is a sensible balance, or perhaps such extension points already exist.</p>
<p>Oh, we also got to feed monkeys!</p>
<p><a href="http://blog.mozilla.org/luke/files/2011/06/jenn-monkey.jpg"><img class="aligncenter size-medium wp-image-117" title="jenn-monkey" src="http://blog.mozilla.org/luke/files/2011/06/jenn-monkey-300x225.jpg" alt="" width="300" height="225" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2011/06/20/new-mozillaindonesiakumi/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tab-completion works with scp</title>
		<link>http://blog.mozilla.org/luke/2011/06/07/tab-completion-works-with-scp/</link>
		<comments>http://blog.mozilla.org/luke/2011/06/07/tab-completion-works-with-scp/#comments</comments>
		<pubDate>Wed, 08 Jun 2011 04:52:28 +0000</pubDate>
		<dc:creator>Luke Wagner</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.mozilla.org/luke/?p=16</guid>
		<description><![CDATA[Today I was using &#8216;scp&#8217; and I reflexively tried to tab-complete the remote path.  Right about the time I thought &#8220;oh yeah, tab-completion doesn&#8217;t work with scp, duh&#8221;, tab-completion worked.  Incredible.]]></description>
				<content:encoded><![CDATA[<p>Today I was using &#8216;scp&#8217; and I reflexively tried to tab-complete the remote path.  Right about the time I thought &#8220;oh yeah, tab-completion doesn&#8217;t work with scp, duh&#8221;, tab-completion worked.  Incredible.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.org/luke/2011/06/07/tab-completion-works-with-scp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
