<?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>David Mandelin&#039;s blog &#187; esp</title>
	<atom:link href="http://blog.mozilla.com/dmandelin/category/esp/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mozilla.com/dmandelin</link>
	<description>Just another Blog.mozilla.com weblog</description>
	<lastBuildDate>Wed, 25 Jan 2012 18:02:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Static Analysis Newslets</title>
		<link>http://blog.mozilla.com/dmandelin/2009/01/09/static-analysis-newslets-2/</link>
		<comments>http://blog.mozilla.com/dmandelin/2009/01/09/static-analysis-newslets-2/#comments</comments>
		<pubDate>Sat, 10 Jan 2009 01:12:19 +0000</pubDate>
		<dc:creator>dmandelin</dc:creator>
				<category><![CDATA[esp]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[regexp]]></category>
		<category><![CDATA[SquirrelFish]]></category>
		<category><![CDATA[static-analysis]]></category>
		<category><![CDATA[TraceMonkey]]></category>
		<category><![CDATA[wrec]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/dmandelin/?p=40</guid>
		<description><![CDATA[And, now that I&#8217;m posting again, I should offer a little news about other recent events. Jason Orendorff has successfully used Treehydra and a few GCC attribute annotations to add a read barrier to the JS frame pointer in TraceMonkey. I&#8217;m not exactly sure what that means myself, but I think the idea is this: [...]]]></description>
			<content:encoded><![CDATA[<p>And, now that I&#8217;m posting again, I should offer a little news about other recent events.</p>
<p><strong>Jason Orendorff </strong>has successfully used Treehydra and a few GCC attribute annotations to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=460865">add a read barrier</a> to the JS frame pointer in TraceMonkey. </p>
<p>I&#8217;m not exactly sure what that means myself, but I think the idea is this: Part of how TraceMonkey speeds things up is by constructing activation records for JS function calls only if and when it is necessary. But then TraceMonkey can&#8217;t safely call arbitrary native functions, because the native function might try to access those activation records, and thus crash. So TraceMonkey can&#8217;t speed up traces that call arbitrary native functions. Jason&#8217;s analysis verifies that every function that accesses the activation records is either already in a state where they are available, or first calls a function that makes them available. His analysis is pretty powerful: if a function needs the activation records only on certain paths, the analysis only requires it to have them on those paths, thus allowing it to run faster otherwise. I believe all of this is a first step toward tracing through all sorts of DOM calls, which is essential to speeding up the web as a whole.</p>
<p><strong>Graydon Hoare</strong> is just starting on an analysis application to verify that errors are handled correctly in TraceMonkey/SpiderMonkey. He&#8217;s doing the equivalent of <a href="http://www.javapractices.com/topic/TopicAction.do?Id=129">Java checked exceptions</a> in C. In Java, if you call a function like &#8216;void foo() throws FooException&#8217;, then whenever you call foo(), Java requires that you either declare that you too can throw a FooException, or you catch it in a catch block. </p>
<p>SpiderMonkey uses C-style error reporting, i.e., the return value of a function indicates whether there was an error. So the equivalent of checked exceptions is something like this:</p>
<pre>
  // The attribute tells us that a JS_FALSE return value indicates an
  // error, and that the possible error conditions are OOMError and
  // AsmError.
  JSBool foo() __attribute__(("failure:JS_FALSE:OOMError,AsmError"))

  JSBool fooCaller() {
    JSBool rv = foo();
    if (!rv) {
      return JS_FALSE;
      // Error! If foo() fails, we have to call an "error handler" like
      // handleAsmError().
    }
    ...
  }
</pre>
<p>At a high level, this is similar to Jason&#8217;s analysis, but all sorts of practical details differ, and practical details are annoying significant in static analysis. Graydon&#8217;s currently bravely trying out the largely undocumented ESP library APIs.</p>
<p>In other news, a little while back I implemented a simple <strong>regexp compiler</strong> that translates JS regular expressions to native code by way of nanojit, TraceMonkey&#8217;s cross-platform backend. I guess the WebKit team doesn&#8217;t have a blog where they would bust me for having a really incomplete implementation, so I&#8217;ll have to do it myself. My implementation so far is less complete than theirs, but it is good enough at least to give massive speedups on SunSpider&#8217;s regexp-dna.js and simple regular expressions of that kind. I&#8217;ll really bust myself by saying I haven&#8217;t implemented &#8220;dot&#8221; yet. I think V8 has a regexp compiler too, now.</p>
<p>I think the really important difference between the TraceMonkey regexp compiler and WebKit&#8217;s (WREC) is in the backend. TraceMonkey uses nanojit, a cross-platform compiler that turns linear (or mostly-linear) LIR code sequences into optimized native code. WREC, the last time I looked at it, uses an x86 assembler library. Thus, WREC can very directly implement a human-designed x86 code generation and register allocation pattern, making good x86 code. Also, the assembly process is a lot quicker than nanojit&#8217;s compilation process. But unlike nanojit, it doesn&#8217;t have the opportunity to automatically optimize the code, and is x86-only. In practice, this means WREC wins on getting to the breakeven point faster (compiling takes time, which you win back as you run the regexp against more and more text characters), and running a hair faster on regexp-dna, while TraceMonkey wins on being cross-platform.</p>
<p>I guess as the author I&#8217;m not really qualified to say so, but I do think my little regexp compiler is pretty simple and clean, so if anyone out there is interested in getting into some compiler hackery, it might be a fun place to start. And there&#8217;s lots left to be done.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/dmandelin/2009/01/09/static-analysis-newslets-2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>ESP: MSR&#8217;s little helper</title>
		<link>http://blog.mozilla.com/dmandelin/2008/04/18/esp-msrs-little-helper/</link>
		<comments>http://blog.mozilla.com/dmandelin/2008/04/18/esp-msrs-little-helper/#comments</comments>
		<pubDate>Fri, 18 Apr 2008 22:45:12 +0000</pubDate>
		<dc:creator>dmandelin</dc:creator>
				<category><![CDATA[esp]]></category>
		<category><![CDATA[outparams]]></category>
		<category><![CDATA[treehydra]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/dmandelin/2008/04/18/esp-msrs-little-helper/</guid>
		<description><![CDATA[The Javascript/Treehydra version of the outparam usage checker is finally nearing completion: all that&#8217;s left is packaging it as a patch that can go into mozilla-central (plus the inevitable future debugging). In my last post, I mentioned that the checker is based on ESP, an program analysis technique invented at Microsoft Research. A few people [...]]]></description>
			<content:encoded><![CDATA[<p>The Javascript/<a href="http://wiki.mozilla.org/Treehydra">Treehydra</a> version of the <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420933">outparam usage checker</a> is finally nearing completion: all that&#8217;s left is packaging it as a patch that can go into mozilla-central (plus the inevitable future debugging). In my last post, I mentioned that the checker is based on <a href="http://www.google.com/search?q=ESP%3A+path-sensitive+program+verification+in+polynomial+time&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-US:official&amp;client=firefox-a">ESP</a>, an program analysis technique invented at Microsoft Research. A few people have asked for a post about ESP (the paper is good, but very dense if you don&#8217;t have a PL research background), so here it is.</p>
<p><strong>Why ESP? </strong><br />
First I should explain why I bothered implementing a new outparam checker design given that I had a working version based on theorem proving. The problem was that that the theorem-proving version worked by analyzing &#8220;every&#8221; path in each method. Or it would have worked if it could analyze every path. But a method with N <code>if</code> statements can have 2^N paths, and N gets big enough that Mozilla has a method with 8 million paths. Worse, methods with loops have an infinite number of paths. In practice, path-based analyses have to give up after about 1000 paths, leaving the rest unanalyzed.</p>
<p>In short, path-based analysis is very precise, but lacks coverage of all the code paths. Conversely, the abstract interpretation approach I showed in my previous post does cover all code paths, but it mixes them up so much that it ends up being too imprecise to work at all.</p>
<p>When I saw this problem, I remembered ESP right away, because the whole point of ESP is to get the precision of path-based analysis with the speed and coverage of abstract interpretation. But after reviewing the paper, I couldn&#8217;t really see how to make ESP solve the problems I described before, so I went the theorem proving route. But once I got stuck on the path explosion problem, I went back to it, and eventually it hit me. Now it seems kind of obvious. So, it seems like I should be able to explain ESP and its application to outparams in a way that makes it sound simple, but that turned out to be hard. Hopefully it&#8217;s at least comprehensible.</p>
<p><strong>Abstract Interpetation Redux.</strong><br />
Previously, I tried out abstract interpretation with pen and paper and found that it didn&#8217;t even come close to working for outparams. (Reminder: abstract interpretation means running the code in a special interpreter that (a) tracks finite(-ish) <em>abstract states</em> instead of the standard program state, (b) goes both ways at branches and (c) merges state when control rejoins. This has the effect of running the method on every possible input value and every path in finite time. The price is that the output is abstract states instead of full detail.) Here are the results again (the table on the right shows the abstract state after abstractly interpreting each statement):</p>
<pre>
 1   nsresult SomeMethod(nsIX **out) {      out       rv   tmp   if.temp
 2     nsresult rv = doSomething();      not-written   ?
 3     tmp = rv;                         not-written   ?    ?
 4     if.temp = NS_SUCCEEDED(tmp)       not-written   ?    ?      ?
 5     if (if.temp) {                    not-written   ?    ?    true
 6       out = mValue;                       written   ?    ?    true
 7       return NS_OK;                       written   ?    ?    true
 8     } else {                          not-written   ?    ?    false
 9       return rv;                      not-written   ?    ?    false
10     }
11   }</pre>
<p>These analysis results are too imprecise to check the return on line 9: <code>rv</code> is unknown, so the analysis has to assume that the return value could be success, which is an error because <code>out</code> has not been written at this point. Note that the abstract interpretation <em>never</em> had any information about <code>rv</code>. Clearly, total ingorance about <code>rv</code> just won&#8217;t work, and any algorithm that works <em>must</em> track the relationship between <code>out</code> and <code>rv</code> that is created by line 2.</p>
<p><strong>A Smarter Abstract State Space.</strong><br />
Abstract interpetation can track that relationship, but it needs to use a more complicated abstract state than the one I implicitly used above. The abstract state in my table above is a mapping of variables to abstract values. (Compare with the real program state, which is a mapping of variable to C++ values.) That&#8217;s the simplest and most common abstract state, but there&#8217;s really nothing special about it. An abstract state can be any representation of a set of program states: the game is to choose an abstract state space that is &#8220;fine&#8221; enough to represent the information we need, but no finer, so the abstract states stay small and simple.</p>
<p>We need a state space that can represent facts like &#8220;<code>if.temp</code> is true iff <code>tmp</code> is a success code&#8221;. I can write that more explictly as, &#8220;<code>if.temp</code> is true and <code>tmp</code> is a success code, <em>or</em> <code>if.temp</code> is false and <code>tmp</code> is a failure code.&#8221; And that looks just like the &#8220;or&#8221; of two mappings of variables to abstract values. So, it looks like we can use an abstract state that&#8217;s just like our original state, except allowing <strong>multiple &#8220;table rows&#8221;</strong>. If we code the abstract interpreter to use multiple rows when it can, the results of abstract interpretation will come out like this (showing the states between the statements so it&#8217;s easier to separate the rows):</p>
<pre>
 1   nsresult SomeMethod(nsIX **out) {      out         rv    tmp   if.temp
                                         not-written
 2     nsresult rv = doSomething();
                                         not-written   succ
                                         not-written   fail
 3     tmp = rv;
                                         not-written   succ  succ
                                         not-written   fail  fail
 4     if.temp = NS_SUCCEEDED(tmp)
                                         not-written   succ  succ    true
                                         not-written   fail  fail    false
 5     if (if.temp) {
                                         not-written   succ  succ    true
 6       out = mValue;
                                             written   succ  succ    true
 7       return NS_OK;
 8     } else {
                                         not-written   fail  fail    false
 9       return rv;
10     }
11   }</pre>
<p>These results are detailed enough to check outparams perfectly!</p>
<p>A few things to note: In abstractly interpreting line 2, we don&#8217;t know the results exactly, but instead of generating a lot of &#8220;unknown&#8221; abstract values, we generate multiple rows, establishing the correlation among results. Now on lines 3 and 4, we have a multiple-row state, so we abstractly interpret the statements on each row independently. Finally, line 5 is a conditional guard, so at that point, we filter out all the rows that don&#8217;t match the guard (because the program wouldn&#8217;t execute this path in those states). Each of these features is another detail that has to be noticed and coded up in the analysis, but they all fit naturally into the framework of interpreting statements on abstract states.</p>
<p><strong>Path Sensitivity.</strong><br />
This version of the analysis is actually path-sensitive, because if different paths generate different states, those states will be kept as separate rows. Here&#8217;s an example:</p>
<pre>
nsresult OtherMethod(nsIX **out1, nsIX **out2) {
                                        out1          out2         rv    if.temp
                                    not-written   not-written
  nsresult rv = doSomething();
                                    not-written   not-written   success
                                    not-written   not-written   failure
  if.temp = NS_SUCCEEDED(rv);
                                    not-written   not-written   success   true
                                    not-written   not-written   failure   false
  if (if.temp) {
                                    not-written   not-written   success   true
    out1 = mFoo;
                                A:      written   not-written   success   true
  } else {
                                B:  not-written   not-written   failure   false
  }
                                C:  // Join point -- state is union of A and B.
                                        written   not-written   success   true
                                    not-written   not-written   failure   false
  doMoreStuff();
                                        written   not-written   success   true
                                    not-written   not-written   failure   false
  if (if.temp) {
                                        written   not-written   success   true
    out2 = mBar;
                                        written       written   success   true
  } else {
                                    not-written   not-written   failure   false
  }
                                     // Join point
                                        written       written   success   true
                                    not-written   not-written   failure   false
  return rv;
}</pre>
<p>It&#8217;s kind of hard to read, but the key point is that there are two <code>ifs</code> with the same guard, and to analyze the method correctly, we need to know that of the 4 possible paths, only 2 can actually be taken. State C is the important one: after finishing the first <code>if</code>, at the join point we merge the states by simply collecting all the rows. Each path has a different row, and the rows stay separate, so on the second <code>if</code>, the analysis executes the then branch only in the states generated by the first then branch.</p>
<p>This is actually the kind of thing the ESP authors were most concerned with in their paper. It&#8217;s pretty neat but the problems I had look very different, which is why it took me so long to see the connection.</p>
<p>A nice thing about this kind of path sensitivity is that if the state is the same along two branches, the rows will &#8220;rejoin&#8221; at the join point, essentially forgetting that there was a branch (because it didn&#8217;t really matter anyway). It also works with loops.</p>
<p>The problem is that although we don&#8217;t exactly get path explosion anymore, we can get &#8220;row explosion&#8221;: if there are M variables, and each has 2 possible abstract values, we can get 2^M rows in the state. And M can easily get big enough in Mozilla to run out of memory.</p>
<p><strong>ESP.</strong><br />
This is where ESP comes into play. The insight of ESP is that there are some variables you care about a lot (which the ESP authors call <em>property variables</em>), and others you care about only as far as they relate to the property variables (which the ESP authors call <em>execution variables</em>). (For example, in outparams, the property variables are the outparams and any variables that whose values can reach a return statement.) So, if there are only a few property variables, then if we had a way to track only the property values path-sensitively, we can be precise on the things we care about without row explosion.</p>
<p>ESP does this very simply: it just takes our multiple-row states and adds a  <strong>primary key</strong>, namely the set of property variables. Thus, property value combinations and relations are always tracked precisely. Execution variables are tracked as one mapping per property value combination, just as in the basic abstract interpretation. Because of primary key uniqueness, if there are K property variables, there can be no more than 2^K rows in a state, so if K is smaller than 10 or so, the states are small enough to analyze in reasonable time.</p>
<p>An ESP analysis looks a lot like our path-sensitive abstract intepretation, except that after each operation, it &#8220;collects&#8221; rows together to maintain the primary key uniqueness property. For example, if P is a property variable and E is an execution variable, and we need to merge this state:</p>
<pre>
    P = true,    E = false
    P = false,   E = false</pre>
<p>with this state:</p>
<pre>
    P = true,    E = true</pre>
<p>we take the union of rows as before to get this:</p>
<pre>
    P = true,    E = false
    P = false,   E = false
    P = true,    E = true</pre>
<p>but then we merge together rows with the same primary key, yielding:</p>
<pre>
    P = true,    E = anything
    P = false,   E = false</pre>
<p>The significance of ESP is for outparams is that all Mozilla methods have only a few outparams and return value variables, so the analysis runs fast no matter how many other &#8220;unimportant&#8221; variables are in the method.</p>
<p><strong>A small tweak.</strong><br />
Actually, that&#8217;s not quite true. GCC generates a temporary variable for each return statement, so if there are 30 return statements, there are 30 temporary variables, and the state can grow to 2^30 rows. That does happen, and it does make the analysis run out of memory.<br />
Fortunately, I was able to fix this with a just a small tweak to ESP. The temporary variables are only &#8220;live&#8221; between the point where they are created and where they are copied to another return variable, and their values don&#8217;t matter at all outside that live range. At any given point in the method, only a few temporaries are live. So I can keep the number of property values small by &#8220;demoting&#8221; return values to execution values once they are dead. And demotion is trivial to implement: just set the abstract value to any one value, because we&#8217;ll never read it anyway.</p>
<p>The whole outparam analysis came out to about 2500 lines of Javascript, but a lot of that was adapter code to simplify the Treehydra API, plus subsidiary analyses to find return value variables and their live ranges. The ESP framework was 450 lines, and the outparam abstract interpreter was another 800 lines. It runs in reasonable time too, without any effort optimizing it yet. I haven&#8217;t measured it exactly, but I think it&#8217;s less than 20 minutes on 1970 C++ files of Mozilla on a 4-processor machine. I guess you wouldn&#8217;t want to run it on every build, but if you&#8217;re only changing a few .cpp files, it shouldn&#8217;t be too bad.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/dmandelin/2008/04/18/esp-msrs-little-helper/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

