Mozilla

JavaScript Articles

Sort by:

View:

  1. Firefox – tons of tools for web developers!

    One of the goals of Firefox have always been to make the lives of web developers as easy and productive as possible, by providing tools and a very extensible web browser to enable people to create amazing things. The idea here is to list a lot of the tools and options available to you as web developers using Firefox.

    Continued…

  2. JavaScript speedups in Firefox 3.6

    This post was written by David Mandelin who works on Mozilla’s JavaScript team.

    Firefox 3.5 introduced TraceMonkey, our new JavaScript engine that traces loops and JIT compiles them to native (x86/ARM) code. Many JavaScript programs ran 3-4x faster in TraceMonkey compared to Firefox 3. (See our previous article for technical details.)

    For JavaScript performance in Firefox 3.6, we focused on the areas that we thought needed further improvement the most:

    • Some JavaScript code was not trace-compiled in Firefox 3.5. Tracing was disabled by default for Firefox UI JavaScript and add-on JavaScript, so those programs did not benefit from tracing. Also, many advanced JavaScript features were not trace-compiled. For Firefox 3.6, we wanted to trace more programs and more JS features.
    • Animations coded with JavaScript were often choppy because of garbage collection pauses. We wanted to improve GC performance to make pauses shorter and animations smoother.

    In this article, I’ll explain the most important JS performance improvements that come with Firefox 3.6. I’ll focus on listing what kinds of JS code get faster, including sample programs that show the improvements Fx3.6 makes over Fx3.5.

    JIT for Browser UI JavaScript

    Firefox runs JavaScript code in one of two contexts:content and chrome (no relation to Google Chrome). JavaScript that is part of web content runs in a content context. JavaScript that is part of the browser UI or browser add-ons runs in a chrome context and has extra privileges. For example, chrome JS can alter the main browser UI, but content JS is not allowed to.

    The TraceMonkey JIT can be enabled or disabled separately for content and chrome JS using about:config. Because bugs affecting chrome JS are a greater risk for security and reliability, in Firefox 3.5 we chose to disable the JIT for chrome JS by default. After extensive testing, we’ve decide to enable the JIT for chrome JS by default, something we did not have time to fully investigate for Fx3.5. Turning on the JIT for chrome should make the JS behind the Firefox UI and add-ons run faster. This difference is probably not very noticeable for general browser usage, because the UI was designed and coded to perform well with the older JS engines. The difference should be more noticeable for add-ons that do heavy JS computation.

    Option Fx3.5 Default Fx3.6 Default
    javascript.options.jit.chrome false true
    javascript.options.jit.content true true
    about:config options for the JIT

    Garbage Collector Performance

    JavaScript is a garbage-collected language, so periodically the JavaScript engine must reclaim unused memory. Our garbage collector (GC) pauses all JavaScript programs while it works. This is fine as long as the pauses are “short”. But if the pauses are even a little too long, they can make animations jerky. Animations need to run at 30-60 frames per second to look smooth, which means it should take no longer than 17-33 ms to render one frame. Thus, GC pauses longer than 40 ms cause jerkiness, while pauses under 10 ms should be almost unnoticeable. In Firefox 3.5, pause times were noticeably long, and JavaScript animations are increasingly common on the web, so reducing pause times was a major goal for JavaScript in Firefox 3.6.

    Demo: GC Pauses and Animation

    Demo.
    The spinning dial animation shown here illustrates pause times. Besides animating the dial, this demo creates one million 100-character strings per second, so it requires frequent GC. The frame delay meter gives the average time between frames in milliseconds. The estimated GC delay meter gives the average estimated GC delay, based on the assumption that if a frame has a delay of 1.7 times the average delay or more, then exactly one GC ran during that frame. (This procedure may not be valid for other browsers, so it is not valid for comparing different browsers. Note also that the GC time also depends on other live JavaScript sessions, so for a direct comparison of two browsers, have the same tabs open in each.) On my machine, I get an estimated GC delay of about 80 ms in Fx3.5, but only 30 ms in Fx3.6.

    But it’s a lot easier to see the difference by opening the demo in Fx3.5, watching it a bit, and then trying it in Fx3.6.
    In Fx3.5, I see frequent pauses and the animation looks noticeably jerky. In Fx3.6, it looks pretty smooth, and it’s hard for me even to tell exactly when the GC is running.

    How Fx3.6 does it better. We’ve made many improvements to the garbage collector and memory allocator. I want to give a little more technical details on the big two changes that really cut our pause times.

    First, we noticed that a large fraction of the pause time was spent calling free to reclaim the unused memory. We can’t do much to make freeing memory faster, but we realized we could do it on a separate thread. In Fx3.6, the main JS thread simply adds unused memory chunks to a queue, and another thread frees them during idle time or on a separate processor. This means machines with 2 or more cores will benefit more from this change. But even when one core, freeing might be delayed to an idle time when it will not affect scripts.

    Second, we knew that in Fx3.5 running GC clears out all the native code compiled by the JIT as well as some other caches that speed up JS. The reason is that the tracing JIT and GC did not know about each other, so if the GC ran, it might reclaim objects being used by a compiled trace. The result was that immediately after a GC, JS ran a bit slower as the caches and compiled traces were built back up. This would be experienced as either an extended GC pause or a brief hiccup of slow animation right after the GC pause. In Fx3.6, we taught the GC and the JIT to work together, and now the GC does not clear caches or wipe out native code, so it resumes running normally right after GC.

    Tracing More JavaScript Constructs

    In my article on TraceMonkey for the Fx3.5 release, I noted that certain code constructs, such as the arguments object, were not traced and did not get performance improvements from the JIT. A major goal for JS in Fx3.6 was to trace more stuff, so more programs can run faster. We do trace more stuff now, in particular:

    • DOM Properties. DOM objects are special and harder for the trace compiler to work with. For Fx3.5, we implemented tracing of DOM methods, but not DOM properties. Now we trace DOM properties (and other “native” C++ getters and setters) as well. We still do not trace scripted getters and setters.
    • Closures. Fx3.5 traced only a few operations involving closures (by which I mean functions that refer to variables defined in lexically enclosing functions). Fx3.6 can trace more programs that use closures. The main operation that is still not traced yet is creating an anonymous function that modifies closure variables. But calling such a function and actually writing to the closure variables are traced.
    • arguments. We now trace most common uses of the arguments keyword. “Exotic” uses, such as setting elements of arguments, are not traced.
    • switch. We have improved performance when tracing switch statements that use densely packed numeric case labels. These are particularly important for emulators and VMs.

    These improvements are particularly important for jQuery and Dromaeo, which heavily use arguments, closures, and the DOM. I suspect many other complex JavaScript applications will also benefit. For example, we recently heard from the author that this R-tree library performs much better in Fx3.6.

    Here is a pair of demos of new things we trace. The first sets a DOM property in a loop. The second calls a sum function implemented with arguments I get a speedup of about 2x for both of them in Fx3.6 vs. Fx3.5.

    Demo: Fx3.6 Tracing DOM properties and arguments


    DOM Property Set:

    Sum using arguments:

    String and RegExp Improvements

    Fx3.6 includes several improvements to string and regular expression performance. For example, the regexp JIT compiler now supports a larger class of regular expressions, including the ever-popular \w+. We also made some of our basic operations faster, like indexOf, match, and search. Finally, we made concatenating sequences of several strings inside a function (a common operation in building up HTML or other kinds of textual output) much faster.

    Technical aside on how we made string concatenation faster: The C++ function that concatenates two strings S1 and S2 does this: Allocate a buffer big enough to hold the result, then copy the characters of S1 and S2 into the buffer. To concatenate more than two strings, as in JS s + "foo" + t, Fx3.5 simply concatenates two at a time from left to right.

    Using the Fx3.5 algorithm, to concatenate N strings each of length K, we need to do N-1 memory allocations, and all but one of them are for temporary strings. Worse, the first two input strings are copied N-1 times, the next one is copied N-2 times, and so on. The total number of characters copied is K(N-1)(N+2)/2, which is O(N^2).

    Clearly, we can do a lot better. The minimum work we can do is to copy each input string exactly once to the output string, for a total of KN characters copied. Fx3.6 achieves this by detecting sequences of concatenation in JS programs and combining the entire sequence into one operation that uses the optimal algorithm.

    Here are a few string benchmarks you can try that are faster in Fx3.6:

    Demo: Fx3.6 String Operations


    /\w+/:

    indexOf('foo'):

    match('foo'):

    Build HTML:

    Final Thoughts and Next Steps

    We also made a lot of little improvements that don't fit into the big categories above. Most importantly, Adobe, Mozilla, Intel, Sun, and other contributors continue to improve nanojit, the compiler back-end used by TraceMonkey. We have improved its use of memory, made trace recording and compiling faster, and also improved the speed of the generated native code. A better nanojit gives a boost to all JS that runs in the JIT.

    There are two big items that didn't make the cut for Fx3.6, but will be in the next version of Firefox and are already available in nightly builds:

    • JITting recursion. Recursive code, like explicit looping code, is likely to be hot code, so it should be JITted. Nightly builds JIT directly recursive functions. Mutual recursion (g calls f calls g) is not traced yet.
    • AMD x64 nanojit backend. Nanojit now has a backend that generates AMD x64 code, which gives the possibility of better performance on that plaform.

    And if you try a nightly build, you'll find that many of these demos are already even faster than in Fx3.6!

  3. an overview of TraceMonkey

    This post was written by David Mandelin who works on Mozilla’s JavaScript team.

    Firefox 3.5 has a new JavaScript engine, TraceMonkey, that runs many JavaScript programs 3-4x faster than Firefox 3, speeding up existing web apps and enabling new ones. This article gives a peek under the hood at the major parts of TraceMonkey and how they speed up JS. This will also explain what kinds of programs get the best speedup from TraceMonkey and what kinds of things you can do to get your program to run faster.

    Why it’s hard to run JS fast: dynamic typing

    High-level dynamic languages such as JavaScript and Python make programming more productive, but they have always been slow compared to statically typed languages like Java or C. A typical rule of thumb was that a JS program might be 10x slower than an equivalent Java program.

    There are two main reasons JS and other dynamic scripting languages usually run slower than Java or C. The first reason is that in dynamic languages it is generally not possible to determine the types of values ahead of time. Because of this, the language must store all values in a generic format and process values using generic operations.

    In Java, by contrast, the programmer declares types for variables and methods, so the compiler can determine the types of values ahead of time. The compiler can then generate code that uses specialized formats and operations that run much faster than generic operations. I will call these type-specialized operations.

    The second main reason that dynamic languages run slower is that scripting languages are usually implemented with interpreters, while statically typed languages are compiled to native code. Interpreters are easier to create, but they incur extra runtime overhead for tracking their internal state. Languages like Java compile to machine language, which requires almost no state tracking overhead.

    Let’s make this concrete with a picture. Here are the slowdowns in picture form for a simple numeric add operation: a + b, where a and b are integers. For now, ignore the rightmost bar and focus on the comparison of the Firefox 3 JavaScript interpreter vs. a Java JIT. Each column shows the steps that have to be done to complete the add operation in each programming language. Time goes downward, and the height of each box is proportional to the time it takes to finish the steps in the box.

    time diagram of add operation

    In the middle, Java simply runs one machine language add instruction, which runs in time T (one processor cycle). Because the Java compiler knows that the operands are standard machine integers, it can use a standard integer add machine language instruction. That’s it.

    On the left, SpiderMonkey (the JS interpreter in FF3) takes about 40 times as long. The brown boxes are interpreter overhead: the interpreter must read the add operation and jump to the interpreter’s code for a generic add. The orange boxes represent extra work that has to be done because the interpreter doesn’t know the operand types. The interpreter has to unpack the generic representations of a and i, figure out their types, select the specific addition operation, convert the values to the right types, and at the end, convert the result back to a generic format.

    The diagram shows that using an interpreter instead of a compiler is slowing things down a little bit, but not having type information is slowing things down a lot. If we want JS to run more than a little faster than in FF3, by Amdahl’s law, we need to do something about types.

    Getting types by tracing

    Our goal in TraceMonkey is to compile type-specialized code. To do that, TraceMonkey needs to know the types of variables. But JavaScript doesn’t have type declarations, and we also said that it’s practically impossible for a JS engine to figure out the types ahead of time. So if we want to just compile everything ahead of time, we’re stuck.

    So let’s turn the problem around. If we let the program run for a bit in an interpreter, the engine can directly observe the types of values. Then, the engine can use those types to compile fast type-specialized code. Finally, the engine can start running the type-specialized code, and it will run much faster.

    There are a few key details about this idea. First, when the program runs, even if there are many if statements and other branches, the program always goes only one way. So the engine doesn’t get to observe types for a whole method — the engine observes types through the paths, which we call traces, that the program actually takes. Thus, while standard compilers compile methods, TraceMonkey compiles traces. One side benefit of trace-at-a-time compilation is that function calls that happen on a trace are inlined, making traced function calls very fast.

    Second, compiling type-specialized code takes time. If a piece of code is going to run only one or a few times, which is common with web code, it can easily take more time to compile and run the code than it would take to simply run the code in an interpreter. So it only pays to compile hot code (code that is executed many times). In TraceMonkey, we arrange this by tracing only loops. TraceMonkey initially runs everything in the interpreter, and starts recording traces through a loop once it gets hot (runs more than a few times).

    Tracing only hot loops has an important consequence: code that runs only a few times won’t speed up in TraceMonkey. Note that this usually doesn’t matter in practice, because code that runs only a few times usually runs too fast to be noticeable. Another consequence is that paths through a loop that are not taken at all never need to be compiled, saving compile time.

    Finally, above we said that TraceMonkey figures out the types of values by observing execution, but as we all know, past performance does not guarantee future results: the types might be different the next time the code is run, or the 500th next time. And if we try to run code that was compiled for numbers when the values are actually strings, very bad things will happen. So TraceMonkey must insert type checks into the compiled code. If a check doesn’t pass, TraceMonkey must leave the current trace and compile a new trace for the new types. This means that code with many branches or type changes tends to run a little slower in TraceMonkey, because it takes time to compile the extra traces and jump from one to another.

    TraceMonkey in action

    Now, we’ll show tracing in action by example on this sample program, which adds the first N whole numbers to a starting value:

     function addTo(a, n) {
       for (var i = 0; i < n; ++i)
         a = a + i;
       return a;
     }
     
     var t0 = new Date();
     var n = addTo(0, 10000000);
     print(n);
     print(new Date() - t0);

    TraceMonkey always starts running the program in the interpreter. Every time the program starts a loop iteration, TraceMonkey briefly enters monitoring mode to increment a counter for that loop. In FF3.5, when the counter reaches 2, the loop is considered hot and it’s time to trace.

    Now TraceMonkey continues running in the interpreter but starts recording a trace as the code runs. The trace is simply the code that runs up to the end of the loop, along with the types used. The types are determined by looking at the actual values. In our example, the loop executes this sequence of JavaScript statements, which becomes our trace:

        a = a + i;    // a is an integer number (0 before, 1 after)
        ++i;          // i is an integer number (1 before, 2 after)
        if (!(i < n)) // n is an integer number (10000000)
          break;

    That’s what the trace looks like in a JavaScript-like notation. But TraceMonkey needs more information in order to compile the trace. The real trace looks more like this:

      trace_1_start:
        ++i;            // i is an integer number (0 before, 1 after)
        temp = a + i;   // a is an integer number (1 before, 2 after)
        if (lastOperationOverflowed())
          exit_trace(OVERFLOWED);
        a = temp;
        if (!(i < n))   // n is an integer number (10000000)
          exit_trace(BRANCHED);
        goto trace_1_start;

    This trace represents a loop, and it should be compiled as a loop, so we express that directly using a goto. Also, integer addition can overflow, which requires special handling (for example, redoing with floating-point addition), which in turn requires exiting the trace. So the trace must include an overflow check. Finally, the trace exits in the same way if the loop condition is false. The exit codes tell TraceMonkey why the trace was exited, so that TraceMonkey can decide what to do next (such as whether to redo the add or exit the loop). Note that traces are recorded in a special internal format that is never exposed to the programmer — the notation used above is just for expository purposes.

    After recording, the trace is ready to be compiled to type-specialized machine code. This compilation is performed by a tiny JIT compiler (named, appropriately enough, nanojit) and the results are stored in memory, ready to be executed by the CPU.

    The next time the interpreter passes the loop header, TraceMonkey will start executing the compiled trace. The program now runs very fast.

    On iteration 65537, the integer addition will overflow. (2147450880 + 65537 = 2147516417, which is greater than 2^31-1 = 2147483647, the largest signed 32-bit integer.) At this point, the trace exits with an OVERFLOWED code. Seeing this, TraceMonkey will return to interpreter mode and redo the addition. Because the interpreter does everything generically, the addition overflow is handled and everything works as normal. TraceMonkey will also start monitoring this exit point, and if the overflow exit point ever becomes hot, a new trace will be started from that point.

    But in this particular program, what happens instead is that the program passes the loop header again. TraceMonkey knows it has a trace for this point, but TraceMonkey also knows it can’t use that trace because that trace was for integer values, but a is now in a floating-point format. So TraceMonkey records a new trace:

      trace_2_start:
        ++i;            // i is an integer number
        a = a + i;      // a is a floating-point number
        if (!(i < n))   // n is an integer number (10000000)
          exit_trace(BRANCHED);
        goto trace_2_start;

    TraceMonkey then compiles the new trace, and on the next loop iteration, starts executing it. In this way, TraceMonkey keeps the JavaScript running as machine code, even when types change. Eventually the trace will exit with a BRANCHED code. At this point, TraceMonkey will return to the interpreter, which takes over and finishes running the program.

    Here are the run times for this program on my laptop (2.2GHz MacBook Pro):

    System Run Time (ms)
    SpiderMonkey (FF3) 990
    TraceMonkey (FF3.5) 45
    Java (using int) 25
    Java (using double) 74
    C (using int) 5
    C (using double) 15

    This program gets a huge 22x speedup from tracing and runs about as fast as Java! Functions that do simple arithmetic inside loops usually get big speedups from tracing. Many of the bit operation and math SunSpider benchmarks, such bitops-3bit-bits-in-byte, ctrypto-sha1, and math-spectral-norm get 6x-22x speedups.

    Functions that use more complex operations, such as object manipulation, get a smaller speedup, usually 2-5x. This follows mathematically from Amdahl’s law and the fact that complex operations take longer. Looking back at the time diagram, consider a more complex operation that takes time 30T for the green part. The orange and brown parts will still be about 30T together, so eliminating them gives a 2x speedup. The SunSpider benchmark string-fasta is an example of this kind of program: most of the time is taken by string operations that have a relatively long time for the green box.

    Here is a version of our example program you can try in the browser:

    Numerical result:

    Run time:

    Average run time:

    Understanding and fixing performance problems

    Our goal is to make TraceMonkey reliably fast enough that you can write your code in the way that best expresses your ideas, without worrying about performance. If TraceMonkey isn’t speeding up your program, we hope you’ll report it as a bug so we can improve the engine. That said, of course, you may need your program to run faster in today’s FF3.5. In this section, we’ll explain some tools and techniques for fixing performance of a program that doesn’t get a good (2x or more) speedup with the tracing JIT enabled. (You can disable the jit by going to about:config and setting the pref javascript.options.jit.content to false.)

    The first step is understanding the cause of the problem. The most common cause is a trace abort, which simply means that TraceMonkey was unable to finish recording a trace, and gave up. The usual result is that the loop containing the abort will run in the interpreter, so you won’t get a speedup on that loop. Sometimes, one path through the loop is traced, but there is an abort on another path, which will cause TraceMonkey to switch back and forth between interpreting and running native code. This can leave you with a reduced speedup, no speedup, or even a slowdown: switching modes takes time, so rapid switching can lead to poor performance.

    With a debug build of the browser or a JS shell (which I build myself – we don’t publish these builds) you can tell TraceMonkey to print information about aborts by setting the TMFLAGS environment variable. I usually do it like this:

    TMFLAGS=minimal,abort
    dist/MinefieldDebug.app/Contents/MacOS/firefox
    

    The minimal option prints out all the points where recording starts and where recording successfully finishes. This gives a basic idea of what the tracer is trying to do. The abort option prints out all the points where recording was aborted due to an unsupported construct. (Setting TMFLAGS=help will print the list of other TMFLAGS options and then exit.)

    (Note also that TMFLAGS is the new way to print the debug information. If you are using a debug build of the FF3.5 release, the environment variable setting is TRACEMONKEY=abort.)

    Here’s an example program that doesn’t get much of a speedup in TraceMonkey.

    function runExample2() {
      var t0 = new Date;
     
      var sum = 0;
      for (var i = 0; i < 100000; ++i) {
        sum += i;
      }
     
      var prod = 1;
      for (var i = 1; i < 100000; ++i) {
        eval("prod *= i");
      }
      var dt = new Date - t0;
      document.getElementById(example2_time').innerHTML = dt + ' ms';
    }

    Run time:

    If we set TMFLAGS=minimal,abort, we’ll get this:

    Recording starting from ab.js:5@23
    recording completed at  ab.js:5@23 via closeLoop
     
    Recording starting from ab.js:5@23
    recording completed at  ab.js:5@23 via closeLoop
     
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.
     
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.
     
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.

    The first two pairs of lines show that the first loop, starting at line 5, traced fine. The following lines showed that TraceMonkey started tracing the loop on line 10, but failed each time because of an eval.

    An important note about this debug output is that you will typically see some messages referring to inner trees growing, stabilizing, and so on. These really aren’t problems: they usually just indicate a delay in finishing tracing a loop because of the way TraceMonkey links inner and outer loops. And in fact, if you look further down the output after such aborts, you will usually see that the loops eventually do trace.

    Otherwise, aborts are mainly caused by JavaScript constructs that are not yet supported by tracing. The trace recording process is easier to implement for a basic operation like + than it is for an advanced feature like arguments. We didn’t have time to do robust, secure tracing of every last JavaScript feature in time for the FF3.5 release, so some of the more advanced ones, like arguments, aren’t traced in FF3.5.0. Other advanced features that are not traced include getters and setters, with, and eval. There is partial support for closures, depending on exactly how they are used. Refactoring to avoid these constructs can help performance.

    Two particularly important JavaScript features that are not traced are:

    • Recursion. TraceMonkey doesn’t see repetition that occurs through recursion as a loop, so it doesn’t try to trace it. Refactoring to use explicit for or while loops will generally give better performance.
    • Getting or setting a DOM property. (DOM method calls are fine.) Avoiding these constructs is generally impossible, but refactoring the code to move DOM property access out of hot loops and performance-critical segments should help.

    We are actively working on tracing all the features named above. For example, support for tracing arguments is already available in nightly builds.

    Here is the slow example program refactored to avoid eval. Of course, I could have simply done the multiplication inline. Instead, I used a function created by eval because that’s a more general way of refactoring an eval. Note that the eval still can’t be traced, but it only runs once so it doesn’t matter.

    function runExample3() {
      var t0 = new Date;
     
      var sum = 0;
      for (var i = 0; i < 100000; ++i) {
        sum += i;
      }
     
      var prod = 1;
      var mul = eval("(function(i) { return prod * i; })");
     
      for (var i = 1; i < 100000; ++i) {
        prod = mul(i);
      }
      var dt = new Date - t0;
      document.getElementById('example3_time').innerHTML = dt + ' ms';
    }

    Run time:

    There are a few more esoteric situations that can also hurt tracing performance. One of them is trace explosion, which happens when a loop has many paths through it. Consider a loop with 10 if statements in a row: the loop has 1024 paths, potentially causing 1024 traces to be recorded. That would use up too much memory, so TraceMonkey caps each loop at 32 traces. If the loop has fewer than 32 hot traces, it will perform well. But if each path occurs with equal frequency, then only 3% of the paths are traced, and performance will suffer.

    This kind of problem is best analyzed with TraceVis, which creates visualizations of TraceMonkey performance. Currently, the build system only supports enabling TraceVis for shell builds, but the basic system can also run in the browser, and there is ongoing work to enable TraceVis in a convenient form in the browser.

    The blog post on TraceVis is currently the most detailed explanation of what the diagrams mean and how to use them to diagnose performance problems. The post also contains a detailed analysis of a diagram that is helpful in understanding how TraceMonkey works in general.

    Comparative JITerature

    Here I will give a few comparisons to other JavaScript JIT designs. I’ll focus more on hypothetical designs than competing engines, because I don’t know details about them — I’ve read the release information and skimmed a few bits of code. Another big caveat is that real-world performance depends at least as much on engineering details as it does on engine architecture.

    One design option could be a called a per-method non-specializing JIT. By this, I mean a JIT compiler that compiles a method at a time and generates generic code, just like what the interpreter does. Thus, the brown boxes from our diagrams are cut out. This kind of JIT doesn’t need to take time to record and compile traces, but it also does not type-specialize, so the orange boxes remain. Such an engine can still be made pretty fast by carefully designing and optimizing the orange box code. But the orange box can’t be completely eliminated in this design, so the maximum performance on numeric programs won’t be as good as a type-specializing engine.

    As far as I can tell, as of this writing Nitro and V8 are both lightweight non-specializing JITs. (I’m told that V8 does try to guess a few types by looking at the source code (such as guessing that a is an integer in a >> 2) in order to do a bit of type specialization.) It seem that TraceMonkey is generally faster on numeric benchmarks, as predicted above. But TraceMonkey suffers a bit on benchmarks that use more objects, because our object operations and memory management haven’t been optimized as heavily.

    A further development of the basic JIT is the per-method type-specializing JIT. This kind of a JIT tries to type-specialize a method based on the argument types the method is called with. Like TraceMonkey, this requires some runtime observation: the basic design checks the argument types each time a method is called, and if those types have not been seen before, compiles a new version of the method. Also like TraceMonkey, this design can heavily specialize code and remove both the brown and orange boxes.

    I’m not aware that anyone has deployed a per-method type-specializing JIT for JavaScript, but I wouldn’t be surprised if people are working on it.

    The main disadvantage of a per-method type-specializing JIT compared to a tracing JIT is that the basic per-method JIT only directly observes the input types to a method. It must try to infer types for variables inside the method algorithmically, which is difficult for JavaScript, especially if the method reads object properties. Thus, I would expect that a per-method type-specializing JIT would have to use generic operations for some parts of the method. The main advantage of the per-method design is that the method needs to be compiled exactly once per set of input types, so it’s not vulnerable to trace explosion. In turn, I think a per-method JIT would tend to be faster on methods that have many paths, and a tracing JIT would tend to be faster on highly type-specializable methods, especially if the method also reads a lot of values from properties.

    Conclusion

    By now, hopefully you have a good idea of what makes JavaScript engines fast, how TraceMonkey works, and how to analyze and fix some performance issues that may occur running JavaScript under TraceMonkey. Please report bugs if you run into any significant performance problems. Bug reports are also a good place for us to give additional tuning advice. Finally, we’re trying to improve constantly, so check out nightly TraceMonkey builds if you’re into the bleeding edge.

  4. new device API for Firefox 3.6: orientation

    One new feature that we’re including as part of Firefox 3.6 is support for web pages to access machine orientation information if it’s available. As you can see from the demo above you can use it to figure out if the machine is moving and what direction it’s facing.

    Using the API is very simple. All you have to do is add a simple event listener:

    window.addEventListener("MozOrientation", function(e) {
                            /* 3 values: e.x, e.y, e.z */
                            }, true);

    Originally built as something that we would include for our upcoming mobile browser release, we’ve made it available on desktop systems as well. Many modern Macbooks and Thinkpads contain devices and drivers that expose this information. We’ve added support for Linux, Macs and some Thinkpads where drivers and devices are available. (Note, on some Macbooks detect the orientation information backwards – we’re working on that.)

    You can find more information on two posts by Doug Turner and an update on documentation for orientation from Eric Shepherd.

    Paul Rouget has this and some other demos up in one of his posts.

  5. what does tracemonkey feel like?

    One of our goals with Firefox 3.5 is to help upgrade the web. Over the lifecycle of this release we’ve invested heavily in developer features. One of the features that we’ve invested in is TraceMonkey – a tracing interpreter that turns commonly-run JavaScript code into machine code so that it can run at near-native speeds. We consider it to be both an end user feature because it makes existing web applications faster as well as a developer feature because of the new kinds of applications it enables.

    We’re always challenged to try and come up with ways to describe what that means in a way that’s not a dry benchmark. How can we explain what it feels like?

    We’ve made a video to help describe both what it means by the numbers, but also shows what it feels like. If you want to try the demo we suggest you try it in both Firefox 3 and Firefox 3.5. It’s something you can really feel.

    Sadfaces. Your browser doesn’t support native video. Maybe you can try the .ogv version or the .mp4 version and hope for the best?

  6. Creating the future of mobile with Firefox OS – resources, docs and more!

    Just under a month ago I wrote a personal post about my thoughts on Firefox OS and why I think there is something ‘magical’ about what it stands for and the possibilities it brings to the table. This post is a follow-up that aims to cover much of the same ground but with extra detail and more of a technical focus.

    What is Firefox OS?

    In short, Firefox OS is about taking the technologies behind the Web, like JavaScript, and using them to produce an entire mobile operating system. It’s effectively a mobile OS powered by JavaScript!

    Firefox OS screenshots

    This is achieved with a custom version of Gecko, the rendering engine in Firefox, that introduces a variety of new JavaScript APIs needed to create a phone-like experience; things like WebSMS to send text messages, and WebTelephony to make phone calls.

    You might be wondering what’s running Gecko, as a phone can’t naturally boot directly into Gecko. To do that, the phone boots into a very lightweight Linux kernel that, in turn, boots the Gecko process. The process is a little more involved than that and much more detail can be found in the B2G Architecture documentation, including how Gecko accesses the radio hardware and other phone-specific functionality.

    The Firefox OS project also aims to combine many of the other projects at Mozilla into a single vision, what we refer to as the Web as the platform. These projects include the Open Web Apps initiative and Persona, our solution to identity and logins on the Web (formally known as BrowserID). It’s the combination of these various technologies that completes Firefox OS.

    If you want to find out more technical information about the OS then definitely check out the Firefox OS pages on MDN.

    Why Firefox OS?

    A couple of common questions that come up are, “Why Firefox OS?” and more specifically, “Why build a mobile OS using JavaScript?” These are incredibly important questions so let’s take a moment to delve into them in a little detail.

    Why build a mobile OS using JavaScript?

    Answering this question can quite simply be boiled down to one sentence; because it’s possible. It’s not the one and only answer but it succinctly handles most of the arguments against JavaScript being used in this way.

    A longer answer is that a JavaScript-powered OS unlocks a whole range of possibilities that aren’t normally or easily available to developers and users with existing operating systems.

    The most obvious of the possibilities is the ability to build applications using the technologies that we already use to build websites; namely JavaScript, CSS, and HTML. While not a truly unique feature of Firefox OS — projects like PhoneGap have done this for years on ‘native’ platforms — it allows developers everywhere to create mobile applications without having to learn native languages and APIs.

    Another draw of JavaScript is that it’s both extremely well documented and free to develop with. Anyone could sit down for a weekend and put together an application without having to pay for a single thing. Obviously that’s not true in the majority of cases, as people tend to buy their own hosting or tooling, but theoretically there is nothing to stop you building with these technologies for free.

    What’s arguably most interesting about JavaScript being used in this way is that it inherently enables physical devices to communicate using the same APIs that we already use on websites. In effect, instead of accessing the Web through a mobile browser the entire phone is now capable of accessing and communicating with any Web API. For example, there is nothing to stop you building an application for Firefox OS that uses WebRTC (once added) to create Skype-like P2P video communication between phones, desktop computers, or anything else that supports WebRTC.

    This really only scrapes the surface of “Why JavaScript?” but it certainly gives you a feel of how this is both interesting and important, beyond the tired debate of ‘native’ vs. Web. If you’re still not convinced, just think for a moment about how you can now customise an entire mobile OS using nothing by JavaScript. You’d be hard pushed to deny that it’s pretty darn interesting!

    OK, but why Firefox OS?

    Effectively, Firefox OS has been built to put our money where our mouth is (so to speak) and prove that JavaScript is capable of doing what we say it can do. However, there is much more to the project than just proving the the technology is fast enough.

    The first reason ‘Why Firefox OS’ is that the mobile ecosystem is overrun with proprietary platforms, most of which prevent you from easily moving between various platforms. What Firefox OS aims to achieve is a truly ‘open’ platform that doesn’t lock you in and inherently makes it as easy and possible to move between devices as and when you choose.

    Mozilla is effectively replicating its success with Firefox, in which it stormed the browser market and showed users that there is an alternative, one that lets them be in control of how they use the Web. In this case, it’s less about browsers and more about mobile platforms and application portability.

    Another reason is that Firefox OS is an attempt to push the Web forward into the world of physical devices. One direct benefit of this is the addition of brand new Web standards and APIs that allow for things like hardware access using JavaScript.

    Plenty of challenges

    It’s fair to say that the Firefox OS journey will contain a number of technical challenges along the way, however that’s part of the fun and the reasons why we’re working on it.

    One of those challenges is how to manage an apps ecosystem that is open and distributed. This is something that we are tackling with the Open Web Apps initiative and the Mozilla Marketplace. It’s a challenge that we are dealing with as things progress and as we learn more about how things work best, as is the nature with new ways of thinking.

    Another of the challenges is making sure that the phone runs as fast as possible, creating the best experience possible. This also relates to questions raised within the developer community around the performance capabilities of JavaScript, particularly when it is used to do things that are perceived to be complex, or when it is compared against ‘native’ technologies. This is a challenge that we are taking very seriously and one which we feel we can overcome. In fact, it’s a challenge that I believe we have already overcome.

    One prime example of how capable JavaScript has become is seeing beautiful JavaScript games running in Firefox OS at near-enough 60 frames per-second, on a low-end, cheap phone.

    Beyond the mobile phone

    While the phone aspect of Firefox OS is immediately interesting, you should consider the wider implications of a JavaScript OS and what possibilities it unlocks. For example, what other devices could benefit from being powered by JavaScript? And, what would a network of JavaScript-powered devices allow us to do — things like Ubiquitous Computing, perhaps?

    These aren’t things that we are exploring directly at Mozilla, but they are things that are now inherently possible as a result of the work that we’re doing. There is nothing to stop you taking the Firefox OS source code from GitHub and porting it to a device that we’ve never even considered.

    We’re already starting to see this happen with examples like a Firefox OS port for the Raspberry Pi, as well as another for the Pandaboard.

    What about a game console powered by Firefox OS? A TV, or set-top box? What about a fridge? Individually, these are all interesting projects, but together they offer something we don’t really have at the moment, a network of different devices powered by the same, open technologies and able to access and communicate across the Web with the same APIs.

    We are a long way away from that kind of world but it is projects like Firefox OS that may pave the way for it to happen. You could even be a part of it!

    Getting started with Firefox OS

    The hope is that by now you’re sufficiently interested in Firefox OS to begin exploring, experimenting and playing with it. The good news is that there are a whole host of ways that you can do that.

    Documentation

    One of the first places to start is the MDN documentation surrounding Firefox OS and its related technologies. This is where you’ll find everything you need to know about the developer-facing aspects of the platform.

    If you’re more interested with the inner-workings of the platform then you’ll want to cast an eye over the B2G wiki, which outlines much of the internals in plenty of detail.

    Source code

    If you’re keen to get to grips with the source code of Firefox OS then you’ll want to head over to GitHub and check it out. The two main repositories that you want are ‘b2g’ (the underlying Gecko engine) and ‘gaia’ (everything you can see, the OS).

    Getting involved

    There are a few ways to get involved with the project. You could check out some of the issues and get involved in fixing them, or perhaps just hang out in the mailing list for B2G, or the one for Gaia, and take part in the discussions there.

    If you just want to ask a few immediate questions then try out the #b2g and #gaia rooms on irc.mozilla.org. We’re all pretty friendly!

    Development options

    If you just want to dig in and make some applications, or perhaps customise the OS, then you’ll need to know about the various development options available to you. They are covered in some detail on MDN but here is a brief overview.

    The simplest method to get started is running Gaia (the visual side of Firefox OS) within Firefox Nightly. This doesn’t give you a true representation of a phone environment but it will allow you to install applications and use all of the developer tools within the browser that you’re already used to.

    Slightly more involved than Nightly is using the desktop B2G client. This is effectively a chromeless build of Firefox that looks phone-like has some added APIs that aren’t normally available in standard Firefox. This doesn’t replicate phone hardware but it’s the next best thing before starting to develop on an actual device.

    Setting up the desktop B2G client isn’t too hard, but it could be made easier. In the meantime, projects like r2d2b2g aim to make the process super simple. Definitely worth checking out.

    The last method, and arguably the most important one, is developing on an actual Firefox OS device. This is the only method that will give you a true representation of how your application will perform. It is also the only method that will give you access to the all the new APIs that come with Firefox OS.

    Right now, you’ll need to build and install Firefox OS on one of the supported devices. In the future you will be able to skip this step and get access to devices that already run Firefox OS. We don’t have any dates for that just yet.

    Go forth and be part of something big

    My hope is that by now you should now have enough inspiration and information to go forth and begin building for this new platform, powered by the technologies you already use. We hope you do and we’d love to see what you come up with.

    It’s not every day that you get the opportunity to be a part of something that could quite literally change the way we do things.

  7. cross-site xmlhttprequest with CORS

    XMLHttpRequest is used within many Ajax libraries, but till the release of browsers such as Firefox 3.5 and Safari 4 has only been usable within the framework of the same-origin policy for JavaScript. This meant that a web application using XMLHttpRequest could only make HTTP requests to the domain it was loaded from, and not to other domains. Developers expressed the desire to safely evolve capabilities such as XMLHttpRequest to make cross-site requests, for better, safer mash-ups within web applications. The Cross-Origin Resource Sharing (CORS) specification consists of a simple header exchange between client-and-server, and is used by IE8′s proprietary XDomainRequest object as well as by XMLHttpRequest in browsers such as Firefox 3.5 and Safari 4 to make cross-site requests. These browsers make it possible to make asynchronous HTTP calls within script to other domains, provided the resources being retrieved are returned with the appropriate CORS headers.

    A Quick Overview of CORS

    Firefox 3.5 and Safari 4 implement the CORS specification, using XMLHttpRequest as an “API container” that sends and receives the appropriate headers on behalf of the web developer, thus allowing cross-site requests. IE8 implements part of the CORS specification, using XDomainRequest as a similar “API container” for CORS, enabling simple cross-site GET and POST requests. Notably, these browsers send the ORIGIN header, which provides the scheme (http:// or https://) and the domain of the page that is making the cross-site request. Server developers have to ensure that they send the right headers back, notably the Access-Control-Allow-Origin header for the ORIGIN in question (or ” * ” for all domains, if the resource is public) .

    The CORS standard works by adding new HTTP headers that allow servers to serve resources to permitted origin domains. Browsers support these headers and enforce the restrictions they establish. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.

    Capability Detection

    XMLHttpRequest can make cross-site requests in Firefox 3.5 and in Safari 4; cross-site requests in previous versions of these browsers will fail. It is always possible to try to initiate the cross-site request first, and if it fails, to conclude that the browser in question cannot handle cross-site requests from XMLHttpRequest (based on handling failure conditions or exceptions, e.g. not getting a 200 status code back). In Firefox 3.5 and Safari 4, a cross-site XMLHttpRequest will not successfully obtain the resource if the server doesn’t provide the appropriate CORS headers (notably the Access-Control-Allow-Origin header) back with the resource, although the request will go through. And in older browsers, an attempt to make a cross-site XMLHttpRequest will simply fail (a request won’t be sent at all).

    Both Safari 4 and Firefox 3.5 provide the withCredentials property on XMLHttpRequest in keeping with the emerging XMLHttpRequest Level 2 specification, and this can be used to detect an XMLHttpRequest object that implements CORS (and thus allows cross-site requests). This allows for a convenient “object detection” mechanism:

    if (XMLHttpRequest)
    {
        var request = new XMLHttpRequest();
        if (request.withCredentials !== undefined)
        {
          // make cross-site requests
        }
    }

    Alternatively, you can also use the “in” operator:

    if("withCredentials" in request)
    {
      // make cross-site requests
    }

    Thus, the withCredentials property can be used in the context of capability detection. We’ll discuss the use of “withCredentials” as a means to send Cookies and HTTP-Auth data to sites later on in this article.

    “Simple” Requests using GET or POST

    IE8, Safari 4, and Firefox 3.5 allow simple GET and POST cross-site requests. “Simple” requests don’t set custom headers, and the request body only uses plain text (namely, the text/plain Content-Type).

    Let us assume the following code snippet is served from a page on site http://foo.example and is making a call to http://bar.other:

     
    var url = "http://bar.other/publicNotaries/"
    if(XMLHttpRequest)
    {
      var request = new XMLHttpRequest();
      if("withCredentials" in request)
      {
       // Firefox 3.5 and Safari 4
       request.open('GET', url, true);
       request.onreadystatechange = handler;
       request.send();
      }
      else if (XDomainRequest)
      {
       // IE8
       var xdr = new XDomainRequest();
       xdr.open("get", url);
       xdr.send();
     
       // handle XDR responses -- not shown here :-)
      }
     
     // This version of XHR does not support CORS  
     // Handle accordingly
    }

    Firefox 3.5, IE8, and Safari 4 take care of sending and receiving the right headers. Here is the Simple Request example. It is also instructive to look at the headers sent back by the server. Notably, amongst the other request headers, the browser would send the following in order to enable the simple request above:

    GET /publicNotaries/ HTTP/1.1
    Referer: http://foo.example/notary-mashup/
    Origin: http://foo.example

    Note the use of the “Origin” HTTP header that is part of the CORS specification.

    And, amongst the other response headers, the server at http://bar.other would include:

    Access-Control-Allow-Origin: http://foo.example
    Content-Type: application/xml
    ......

    A more complete treatment of CORS and XMLHttpRequest can be found here, on the Mozilla Developer Wiki.

    “Preflighted” Request

    The CORS specification mandates that requests that use methods other than POST or GET, or that use custom headers, or request bodies other than text/plain, are preflighted. A preflighted request first sends the OPTIONS header to the resource on the other domain, to check and see if the actual request is safe to send. This capability is currently not supported by IE8′s XDomainRequest object, but is supported by Firefox 3.5 and Safari 4 with XMLHttpRequest. The web developer does not need to worry about the mechanics of preflighting, since the implementation handles that.

    The code snippet below shows code from a web page on http://foo.example calling a resource on http://bar.other. For simplicity, we leave out the section on object and capability detection, since we’ve covered that already:

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/post-here/';
    var body = '
    Arun';
    function callOtherDomain(){
    if(invocation)
    {
        invocation.open('POST', url, true);
        invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
        invocation.setRequestHeader('Content-Type', 'application/xml');
        invocation.onreadystatechange = handler;
        invocation.send(body);
    }

    You can see this example in action here. Looking at the header exchange between client and server is really instructive. A more detailed treatment of this can be found on the Mozilla Developer Wiki.

    In this case, before Firefox 3.5 sends the request, it first uses the OPTIONS header:

    OPTIONS /resources/post-here/ HTTP/1.1
    Origin: http://foo.example
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-PINGOTHER

    Then, amongst the other response headers, the server responds with:

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: http://arunranga.com
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER
    Access-Control-Max-Age: 1728000

    At which point, the actual response is sent:

    POST /resources/post-here/ HTTP/1.1
    ...
    Content-Type: application/xml; charset=UTF-8
    X-PINGOTHER: pingpong
    ...

    Credentialed Requests

    By default, “credentials” such as Cookies and HTTP Auth information are not sent in cross-site requests using XMLHttpRequest. In order to send them, you have to set the withCredentials property of the XMLHttpRequest object. This is a new property introduced in Firefox 3.5 and Safari 4. IE8′s XDomainRequest object does not have this capability.

    Again, let us assume some JavaScript on a page on http://foo.example wishes to call a resource on http://bar.other and send Cookies with the request, such that the response is cognizant of Cookies the user may have acquired.

    var request = new XMLHttpRequest();
    var url = 'http://bar.other/resources/credentialed-content/';
    function callOtherDomain(){
      if(request)
      {
       request.open('GET', url, true);
       request.withCredentials = "true";
       request.onreadystatechange = handler;
       request.send();
      }

    Note that withCredentials is false (and NOT set) by default. The header exchange is similar to the case of of a simple GET request, with the exception that now an HTTP Cookie header is sent with the request header. You can see this sample in action here.

    A Note on Security

    In general, data requested from a remote site should be treated as untrusted. Executing JavaScript code retrieved from a third-party site without first determining its validity is NOT recommended. Server administrators should be careful about leaking private data, and should judiciously determine that resources can be called in a cross-site manner.

    References

  8. XHR progress and rich file upload feedback

    This demo is by Olli Pettay (smaug) with help from Austin King.

    A common limitation on the web today has been a rich file upload widget for web applications. Many sites use Flash or a desktop helper applications to improve the experience of uploading files.

    Firefox 3.5 bridges one of these gaps allowing a better progress indicator to be built. Many developers don’t realize that they can use Firefox’s File object (nsIDOMFile) and XMLHttpRequest together to accomplish file uploads. This demo will feature an upload widget that gives the kind of rich progress feedback that users have come to expect, as well as fast and easy multiple simultaneous file uploads.

    Progress Indicators

    It’s always a good idea to expose feedback that your application is hard at work for them, and when the current action is expected to finish. The two main types of progress feedback are:

    • indeterminate progress – some activity just happened
    • deterministic progress I’m 40% done, I’m 42% done… etc

    Deterministicsaidwhat? The Demo

    We’ve created a simple file upload / download page that demonstrates the progress bar:

    The demo is host at mozilla.pettay.fi and requires Firefox 3.5 beta4 or later. It demonstrates how to do multiple simultaneous file uploads without posting a form or leaving the current page. For each file upload / download we display the current speed, % complete, and bytes transmitted. We’ll go over a few key snippets of the code which are used in the screenshot above. Please click through the the demo and view source for the full code example.

    The page contains two HTML inputs, one type="file" and one type="button". The form is never actually submitted, instead we add an onclick handler to the button:

    <input type="file" id="file">
    <input type="button"
              onclick="startXHR();"
              value="Upload file using XHR">

    In the startXHR function, we create an XMLHttpRequest and add an event handler to the XHR request to listen for the new ‘progress’ event. With this ProgressEvent’s lengthComputable property, we will know if we are dealing with an indeterminate or deterministic progress. The object also gives us loaded and total bytes.

    var xhr = new XMLHttpRequest();
     
    xhr.onprogress = function(evt) {        
    if (evt.lengthComputable) {
        evt.target.curLoad = evt.loaded;
        evt.target.log.parentNode.parentNode.previousSibling.textContent =
            Number(evt.loaded/k).toFixed() + "/"+ Number(evt.total/k).toFixed() + "kB";
    }
    if (evt.lengthComputable) {
        var loaded = (evt.loaded / evt.total);
        if (loaded < 1) {
            var newW = loaded * width;
            if (newW < 10) newW = 10;
                evt.target.log.style.width = newW + "px";
            }
        }
    };

    Now we need some data to send. We grab the contents of the file directly from the input by id:

    var files = document.getElementById("file").files;
    if (files) {
       var file = files.item(0);
       xhr.sendAsBinary(file.getAsBinary());

    And the last step is to start the request:

    xhr.open("POST", "cgi-bin/posthandler.pl");
    xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
    xhr.sendAsBinary(file.getAsBinary());

    These methods would also work with xhr.upload.onprogress.

    Notice the use of the sendAsBinary method on the XMLHttpRequest object and getAsBinary on the File object. Starting with Firefox 3 you’ve been able to get at the contents of a file on the client side without form submission. This is quite useful for moving beyond the limitation of tranditional file input and form submissions. It is also part of an up and coming W3C standard for FileUpload.

    A related method that the nsIDOMFile provides is the getAsText method which returns a DOMString suitable for slicing, dicing, and displaying.

    Here is an example usage, not used by the demo:

    file.getAsText("utf8");

    So that’s the gist of the code. Check out the demo and view it’s source.

    Feedback In User Interfaces

    Exposing system feedback to users improves perceived performance. We
    can’t always determine how long something will take, so at a minimum we
    can show indeterminate progress.

    During file uploads and file downloads (assuming the server gives us Content-Length) we do indeed know the total number of bytes. Firefox 3.5’s Progress Events support adds a progress event so that we can show actual upload/download progress.

    Traditionally XMLHttpRequests were difficult to get deterministic progress back from. In theory, you could give it callbacks and watch for status code updates and textual message updates, but in practice they turn out to be not very useful. In the past, if a deterministic progress meter was important, you’d have to make a second XHR request to poll for progress.

    Enter Progress Events

    The W3C has a working draft for Progress Events 1.0 which we include in Firefox 3.5. Firefox has added a key new DOM ProgressEvent progress event, as well as the loadstart event. The other existing events included: error, abort and load.

    These same events are also available for uploads and downloads. The progress event gives us the following properties:

    • lengthComputable – true or false, is the size of the request known?
    • loaded – number of bytes received so far
    • total – number of bytes expected for entire request

    The Contract

    When you’re looking at the properties of those progress events, certain rules apply that you can depend on. They are:

    • The total property will be 0 when lengthComputable is false.
    • The loadstart event is always signaled only once.
    • The progress event is fired off zero or more times after loadstart.

    And that’s it. Go forth and improve file uploads with Firefox 3.5 goodness.

  9. How fast is PDF.js?

    Hi, my name is Thorben and I work at Opera Software in Oslo, not at Mozilla. So, how did I end up writing for Mozilla Hacks? Maybe you know that there is no default PDF viewer in the Opera Browser, something we would like to change. But how to include one? Buy it from Adobe or Foxit? Start our own?

    Introducing PDF.js

    While investigating our options we quickly stumbled upon PDF.js. The project aims to create a full-featured PDF viewer in the browser using JavaScript and Canvas. Yeah, it sounds a bit crazy, but it makes sense: browsers need to be good at processing text, images, fonts, and vector graphics — exactly the things a PDF viewer has to be good at. The draw commands in PDFs are a subset of Postscript, and they are not so different from what Canvas offers. Also security is virtually no issue: using PDF.js is as secure as opening any other website.

    Working on PDF.js

    So Christian Krebs, Mathieu Henri and myself began looking at PDF.js in more detail and were impressed: it’s well designed, seems fast and big parts of the code are just wow!

    But we also discovered some problems, mainly with performance on very large or graphics-heavy PDFs. We decided that the best way to get to know PDF.js better and to push the project further, was to help the project and address the major issues we found. This gave us a pretty good understanding of the project and its high potential. We were also very impressed by how much the performance of PDF.js improved while we worked on it. This is an active and well managed project.

    Benchmarking PDF.js

    Of course, our tests gave us the wrong impression about performance. We tried to find super large, awkward and hard-to-render PDFs, but that is not what most people want to view. Most PDFs you actually want to view in PDF.js are fine. But how to test that?

    Well, you could check the most popular PDFs on the Internet – as these are the ones you probably want to view – and benchmark them. A snapshot of 5 to 10k PDFs should be enough … but how do you get them?

    I figured that search engines would be my friend. If you tell them to search for PDFs only, they give you the most relevant PDFs for that keyword, which in turn are probably the most popular ones. And if you use the most searched keywords you end up with a good approximation.

    Benchmarking that many PDFs is a big task. So I got myself a small cluster of old computers and built a nice server application that supplied them with tasks. The current repository has almost 7000 PDFs and benchmarking one version of PDF.js takes around eight hours.

    The results

    Let’s skip to the interesting part with the pretty pictures. This graph

    histogram

    gives us almost all the interesting results at one look. You see a histogram of the time it took to process all the pages in the PDFs in relation to the average time it takes to process the average page of the Tracemonkey Paper (the default PDF you see when opening PDF.js). The User Experience when viewing the Tracemonkey Paper is good and from my tests even 3 to 4 times slower is still okay. That means from all benchmarked pages over 96% (exclude pdfs that crashed) will translate to a good user experience. That is really good news! Or to use a very simple pie chart (in % of pages):

    overview

    You probably already noticed the small catch: around 0.8% of the PDFs crashed PDF.js when we tested them. We had a closer look at most of them and at least a third are actually so heavily damaged that probably no PDF viewer could ever display them.

    And this leads us to another good point: we have to keep in mind that these results just stand here without comparison. There are some PDFs on the Internet that are so complex that there is no hope that even native PDF viewers could display them nice and fast. The slowest tested PDF is an incredibly detailed vector map of the public transport system of Lisbon. Try to open it in Adobe Reader, it’s not fun!

    Conclusion

    From these results we concluded that PDF.js is a very valid candidate to be used as the default PDF viewer in the Opera Browser. There is still a lot of work to do to integrate PDF.js nicely into it, but we are working right now on integrating it behind an experimental flag (BTW: There is an extension that adds PDF.js with the default Mozilla viewer. The “nice” integration I am talking about would be deeper and include a brand new viewer). Thanks Mozilla! We are looking forward to working on PDF.js together with you guys!

    PS: Both the code of the computational system and the results are publicly available. Have a look and tell us if you find them useful!

    PPS: If anybody works at a big search engine company and could give me a list with the actual 10k most used PDFs, that would be awesome :)

    Appendix: What’s next?

    The corpus and the computational framework I described, could be used to do all kinds of interesting things. In the next step, we hope to classify PDFs by used fonts formats, image formats and the like. So you can quickly get PDFs to test a new feature with. We also want to look at which drawing instructions are used with which frequency in the Postscript so we can better optimise for the very common ones, like we did with HTML in browsers. Let’s see what we can actually do ;)

  10. saving data with localStorage

    This post was written by Jeff Balogh. Jeff works on Mozilla’s web development team.

    New in Firefox 3.5, localStorage is a part of the Web Storage specification. localStorage provides a simple Javascript API for persisting key-value pairs in the browser. It shouldn’t be confused with the SQL database storage proposal, which is a separate (and more contentious) part of the Web Storage spec. Key-value pairs could conceivably be stored in cookies, but you wouldn’t want to do that. Cookies are sent to the server with every request, presenting performance issues with large data sets and the potential for security problems, and you have to write your own interface for treating cookies like a database.

    Here’s a small demo that stores the content of a textarea in localStorage. You can change the text, open a new tab, and find your updated content. Or you can restart the browser and your text will still be there.


    The easiest way to use localStorage is to treat it like a regular object:

    >>> localStorage.foo = 'bar'
    >>> localStorage.foo
    "bar"
    >>> localStorage.length
    1
    >>> localStorage[0]
    "foo"
    >>> localStorage['foo']
    "bar"
    >>> delete localStorage['foo']
    >>> localStorage.length
    0
    >>> localStorage.not_set
    null

    There’s also a more wordy API for people who like that sort of thing:

    >>> localStorage.clear()
    >>> localStorage.setItem('foo', 'bar')
    >>> localStorage.getItem('foo')
    "bar"
    >>> localStorage.key(0)
    "foo"
    >>> localStorage.removeItem('foo')
    >>> localStorage.length
    0

    If you want to have a localStorage database mapped to the current session, you can use sessionStorage. It has the same interface as localStorage, but the lifetime of sessionStorage is limited to the current browser window. You can follow links around the site in the same window and sessionStorage will be maintained (going to different sites is fine too), but once that window is closed the database will be deleted. localStorage is for long-term storage, as the w3c spec instructs browsers to consider the data “potentially user-critical”.

    I was a tad disappointed when I found out that localStorage only supports storing strings, since I was hoping for something more structured. But with native JSON support it’s easy to create an object store on top of localStorage:

    Storage.prototype.setObject = function(key, value) {
        this.setItem(key, JSON.stringify(value));
    }
     
    Storage.prototype.getObject = function(key) {
        return JSON.parse(this.getItem(key));
    }

    localStorage databases are scoped to an HTML5 origin, basically the tuple (scheme, host, port). This means that the database is shared across all pages on the same domain, even concurrently by multiple browser tabs. However, a page connecting over http:// cannot see a database that was created during an https:// session.

    localStorage and sessionStorage are supported by Firefox 3.5, Safari 4.0, and IE8. You can find more compatibility details on quirksmode.org, including more detail on the storage event.