Activate your free membership today | Log-in

Friday, July 31st, 2009

PyramiDOM: Spectrum DOM Analyzer

Andrea Giammarchi has created PyramiDOM a “Spectrum DOM Analyzer”. When I first saw it, and read “Spectrum” I thought I was looking at an old 48k video game, but in fact it is showing you info on the DOM:

The generated spectrum will contain every single nodeType 1 present in the document and will show via tooltip info about that node (nodeName, id if present, className if present). Moreover, it highlights somehow that node temporary changing the background (yellow one). The most wicked effect was in jQuery website itself, since it is dark, and since it is linear enough (you scroll and the spectrum is almost there where you scroll).

On the other hand, the most interesting spectrum was in Gmail, where you can spot a proper pyramid of nested divs. Each nodeName will have the same color, but for practical reasons each time this color will be different (random).

You can grab this PyramiDOM link to play.

Posted by Dion Almaer at 6:38 am
4 Comments

+++--
3.6 rating from 23 votes

WPS: PostScript and PDF interpreter for HTML 5 canvas

Category: Canvas, Showcase

It would be a pretty cool hack to implement a PostScript/PDF interpreter in JavaScript wouldn't it? That is exactly what has been done with WPS.

The code takes PS and really groks it so:

JAVASCRIPT:
  1.  
  2. /n 10 def
  3. /w 25 def
  4.  
  5. 0 0 n w mul dup .gbox
  6.  
  7. 4 dict begin
  8.   0 1 n 1 sub {
  9.     /i exch def
  10.     /ii 1 1 n div i mul sub def
  11.     0 1 n 1 sub {
  12.       /j exch def
  13.       /jj 1 1 n div j mul sub def
  14.       ii jj 0 setrgbcolor
  15.       w j mul w i mul w w rectfill
  16.     } for
  17.   } for
  18. end
  19.  

becomes:

And all in ~400 lines of code! Check out the examples..... just awesome!

Posted by Dion Almaer at 12:09 am
6 Comments

++++-
4.9 rating from 19 votes

Thursday, July 30th, 2009

Best way to load your JavaScript

Category: JavaScript, Performance

Nicholas Zakas thinks he has the best way to load JavaScript.

Steve Souders has a bunch of best practices, and it seems that there is definitely nuance that makes advice very much tailored to your circumstance.

Nicholas though, has an opinion:

I’ve come to the conclusion that there’s just one best practice for loading JavaScript without blocking:

  1. Create two JavaScript files. The first contains just the code necessary to load JavaScript dynamically, the second contains everything else that’s necessary for the initial level of interactivity on the page.
  2. Include the first JavaScript file with a <script> tag at the bottom of the page, just inside the </body>.
  3. Create a second <script> tag that calls the function to load the second JavaScript file and contains any additional initialization code.

A helper to make this happen could look like:

JAVASCRIPT:
  1.  
  2. function loadScript(url, callback){
  3.  
  4.     var script = document.createElement("script")
  5.     script.type = "text/javascript";
  6.  
  7.     if (script.readyState){  //IE
  8.         script.onreadystatechange = function(){
  9.             if (script.readyState == "loaded" ||
  10.                     script.readyState == "complete"){
  11.                 script.onreadystatechange = null;
  12.                 callback();
  13.             }
  14.         };
  15.     } else {  //Others
  16.         script.onload = function(){
  17.             callback();
  18.         };
  19.     }
  20.  
  21.     script.src = url;
  22.     document.getElementsByTagName("head")[0].appendChild(script);
  23. }
  24.  

In related news, the LABjs folk have updated their API from this:

JAVASCRIPT:
  1.  
  2. $LAB
  3. .script("jquery.js")
  4. .block(function(){
  5.       $LAB
  6.       .script("jquery.ui.js")
  7.       .script("myplugin.jquery.js")
  8.       .block(function(){
  9.             $LAB.script("initpage.js");
  10.       });
  11. });
  12.  

to the simpler:

JAVASCRIPT:
  1.  
  2. $LAB
  3. .script("jquery.js")
  4. .block()
  5. .script("jquery.ui.js")
  6. .script("myplugin.jquery.js")
  7. .block()
  8. .script("initpage.js");
  9.  

I seem to remember that Steve had some opinions on this API too :)

Posted by Dion Almaer at 9:41 am
16 Comments

+++--
3.2 rating from 32 votes

The Doctor subscribes HTML 5 Audio cross browser support

Category: Sound

The doctor is in, and this time the specialist is Mark Boas who walks us through HTML5 Audio in various browsers and how to get audio working on the various implementations that are in the wild today.

This early in the game especially, all implementations are not equal. For one there is the codec support:

But also there are the various levels of API support (and even the fact that Opera current supports Audio() but not the audio tag for example).

Mark worked on the jPlayer jQuery plugin which lead him down this path, and in conclusion it comes down too:

  1. Check for HTML 5 audio support and if not present fall back on Flash.
  2. Check the level of HTML 5 audio support and adapt your code accordingly for each browser.
  3. Check what file types are supported and link to appropriate formats of the files.

You can go to a audio checker in various browsers to see them poked and prodded.

Mark shares code such as:

JAVASCRIPT:
  1.  
  2. // Using JavaScript You can check for audio tag support like this:
  3. var audioTagSupport = !!(document.createElement('audio').canPlayType);
  4.  
  5. // Checking for the audio object looks more like this:
  6. try {
  7.     // The 'src' parameter is mandatory in Opera 10, so have used an empty string "",
  8.     // otherwise an exception is thrown.
  9.  
  10.     myAudioObj = new Audio("");
  11.  
  12.     audioObjSupport = !!(myAudioObj.canPlayType);
  13.     basicAudioSupport = !!(!audioObjSupport ? myAudioObj.play : false);
  14. } catch (e) {
  15.     audioObjSupport = false;
  16.     basicAudioSupport = false;
  17. }
  18.  
  19. // Need to check the canPlayType first or an exception will be thrown for those browsers that don't support it
  20. if (myAudio.canPlayType) {
  21.    // Currently canPlayType(type) returns: "no", "maybe" or "probably"
  22.     canPlayOgg = ("no" != myAudio.canPlayType("audio/ogg")) && ("" != myAudio.canPlayType("audio/ogg"));
  23.     canPlayMp3 = ("no" != myAudio.canPlayType("audio/mpeg")) && ("" != myAudio.canPlayType("audio/mpeg"));
  24. }
  25.  

Posted by Dion Almaer at 6:12 am
14 Comments

++++-
4 rating from 6 votes

Wednesday, July 29th, 2009

Chroma Hash: Interesting visualization of your password

Category: CSS, jQuery

Matt Thompson has created a fun little jQuery plugin called Chroma-Hash that "dynamically visualizes secure text-field values using ambient color bars":

Password entry can be frustrating, especially with long or difficult passwords. On a webpage, secure fields obscure your input with •'s, so others can't read it. Unfortunately, neither can you—you can't tell if you got your password right until you click "Log In".

Chroma-Hash displays a series of colored bars at the end of field inputs so you can instantly see if your password is right. Chroma-Hash takes an MD5 hash of your input and uses that to compute the colors in the visualization. The MD5 hash is non-reversible, so no one could know what your password just from the colors. Your password will display the same sequence each time, so you can learn to expect "blue, red, pink", for instance; if you instead see "green, purple, yellow", you'll know you typed it wrong.

Here is a snippet of the magic:

JAVASCRIPT:
  1.  
  2.               $(this).css({position:   'absolute',
  3.                            left:       position.left + width - 2,
  4.                            top:        position.top,
  5.                            height:     height + "px",
  6.                            width:      8 + "px",
  7.                            margin:     5 + "px",
  8.                            marginLeft: -8 * (i + 1) + "px"
  9.                           }
  10.                     );
  11.               });
  12.          
  13.               var id     = $(this).attr('id');
  14.               var md5    = hex_md5($(this).val());
  15.               var colors = md5.match(/([\dABCDEF]{6})/ig);
  16.               $(".chroma-hash").stop();
  17.  
  18.               chromaHashesForElement(this).each(function(i) {
  19.                 $(this).animate({backgroundColor:"#" + colors[i]});
  20.               });
  21.  

Posted by Dion Almaer at 5:35 pm
8 Comments

+++--
3.5 rating from 34 votes

Text rotation for all

Category: CSS, Tip

Jonathan Snook has posted a nice nugget on text rotation with CSS that takes a nice bit of markup like this:

HTML:
  1.  
  2. <div class="example-date">
  3.   <span class="day">31</span>
  4.   <span class="month">July</span>
  5.   <span class="year">2009</span>
  6. </div>
  7.  

and converts it to:

all via the CSS:

CSS:
  1.  
  2. -webkit-transform: rotate(-90deg);
  3. -moz-transform: rotate(-90deg);
  4. filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
  5.  

Yup, even IE.

Posted by Dion Almaer at 10:20 am
30 Comments

++++-
4.5 rating from 37 votes

Be an early bird - $300 off expires Friday

Hi everybody,

A quick reminder that $300 off The Ajax Experience conference expires this Friday, July 31. The Ajax Experience is September 14 - 16 in Boston, MA.
www.AjaxExperience.com

Be an early bird. Save $300 now!

We hope to see you there!
The Ajaxian.com team

Posted by tberardi at 8:24 am
Comment here

++---
2.8 rating from 8 votes

Tuesday, July 28th, 2009

Developer evangelism handbook released

Category: Examples, Presentation, Workshop

As developers, it can be hard to get your voice heard in a company. Whilst our products depend on developers building them the right way, other people seem to call the shots about where they are going.

This becomes disastrous when a company tries to reach developers with their product. Normal marketing and PR stunts normally fail to get us excited. To work around this issue, clever companies allow developers to move into a role of developer evangelists.

A developer evangelist is a spokesperson, mediator and translator between a company and both its technical staff and outside developers.

This is my job at the moment, and I was asked by people I trained if there is a handbook about the skills needed to do this job, so I wrote one.

Check out the The Developer Evangelist handbook

The handbook explains several things:

  • What developer evangelism is
  • What makes a good developer evangelist
  • How to write for the web
  • How to use social media and the web to promote content
  • How to deliver great presentations
  • How to deal with criticism of your company and what to do with the competition
  • How to write easy to understand and useful code examples
  • The handbook is Creative Commons and free to use. I am working on getting a printed version out, too.

    Posted by Chris Heilmann at 3:59 pm
    2 Comments

    ++++-
    4.4 rating from 18 votes

    Dynamic script generation and memory leaks

    Category: JSON, Performance

    An interesting piece by Neil Fraser shows that using JSON-P with generated script nodes can be quite a memory leak. Normally you'd add information returned from an API in JSON-P with a generated script node:

    JAVASCRIPT:
    1. script = document.createElement('script');
    2.   script.src = 'http://example.com/cgi-bin/jsonp?q=What+is+the+meaning+of+life%3F';
    3.   script.id = 'JSONP';
    4.   script.type = 'text/javascript';
    5.   script.charset = 'utf-8';
    6.   // Add the script to the head, upon which it will load and execute.
    7.   var head = document.getElementsByTagName('head')[0];
    8.   head.appendChild(script)

    The issue there is that you clog up the head of the document with lots of script nodes, which is why most libraries (like the YUI get() utility) will add an ID to the script element and remove the node after successfully retrieving the JSON data:

    JAVASCRIPT:
    1. var script = document.getElementById('JSONP');
    2. script.parentNode.removeChild(script);

    The issue with this is that browsers do remove the node but fail to do a clean garbage collection of the JavaScript at the same time. This means to cleanly remove the script and its content, you need to also delete the properties of the script by hand:

    JAVASCRIPT:
    1. // Remove any old script tags.
    2.   var script;
    3.   while (script = document.getElementById('JSONP')) {
    4.     script.parentNode.removeChild(script);
    5.     // Browsers won't garbage collect this object.
    6.     // So castrate it to avoid a major memory leak.
    7.     for (var prop in script) {
    8.       delete script[prop];
    9.     }
    10.   }

    Read the whole post here

    Posted by Chris Heilmann at 3:50 pm
    15 Comments

    ++++-
    4 rating from 22 votes

    CSS Gradients for All!

    Category: CSS

    Weston Ruter has created a very cool library that enables CSS gradients on non-WebKit browsers (at least, a subset). Incredibly cool:

    CSS Gradients via Canvas provides a subset of WebKit's CSS Gradients proposal for browsers that implement the HTML5 canvas element.

    To use, just include css-gradients-via-canvas.js (12KB) anywhere on the page (see examples below). Unlike WebKit, this implementation does not currently allow gradients to be used for border images, list bullets, or generated content. The script employs document.querySelectorAll()—it has no external dependencies if this function is implemented; otherwise, it looks for the presence of jQuery, Prototype, or Sizzle to provide selector-querying functionality.

    The implementation works in Firefox 2/3+ and Opera 9.64 (at least). Safari and Chrome have native support for CSS Gradients since they use WebKit, as already mentiond.

    This implementation does not work in Internet Explorer since IE does not support Canvas, although IE8 does support the data: URI scheme, which is a prerequisite (see support detection method). When/if Gears's Canvas API fully implements the HTML5 canvas specification, then this implementation should be tweakable to work in IE8. In the mean time, rudimentary gradients may be achieved in IE by means of its non-standard gradient filter.

    CSS Gradients via Canvas works by parsing all stylesheets upon page load (DOMContentLoaded), and searches for all instances of CSS gradients being used as background images. The source code for the external stylesheets is loaded via XMLHttpRequest—ensure that they are cached by serving them with a far-future Expires header to avoid extra HTTP traffic.

    The CSS selector associated with the gradient background image property is used to query all elements on the page; for each of the selected elements, a canvas is created of the same size as the element's dimensions, and the specified gradients are drawn onto that canvas. Thereafter, the gradient image is retrieved via canvas.toDataURL() and this data is supplied as the background-image for the element.

    An aside. I only just noticed the Gears Canvas API. It doesn't quite do what you think..... I always wanted to implement Canvas in Gears. It is also strange that Gears is so under the radar at Google these days. One blog post per year?. I guess all of the work is going into Chrome / WebKit itself.

    Posted by Dion Almaer at 6:00 am
    14 Comments

    ++---
    2.7 rating from 22 votes

    Monday, July 27th, 2009

    The Ajax Experience Agenda At-a-Glance Now Available!

    Category: Ajaxian.com Announcements, Conferences, The Ajax Experience

    Over the past few weeks we've finalized over 40 key sessions across 7 tracks for The Ajax Experience conference, including Frameworks, User Experience, Standards and Cross-Browser Issues, High Performance and Scalability, Security, Architecture, JavaScript, and Cutting-Edge Ajax. The agenda-at-glance is ready for your review now. There's something for everyone!  Check it out

    The Ajax Experience is September 14-16 in Boston. $300 early bird savings are good through this Friday, July 31.

    Awesome keynote presentations include:

    Check out the The Ajax Experience at-a-glance. Register now to save $300!

    Posted by tberardi at 9:35 am
    Comment here

    ++---
    2.6 rating from 16 votes

    Adding your own scripts to Web Workers

    Category: JavaScript

    Over in Geneva, they have posted on coupling PHP and Workers.

    They build on the great intro from John and tweak it to use simple PHP on the backend to do things such as making sure that your favourite library has been loaded into each Worker, so you can use it in your script.

    JAVASCRIPT:
    1.  
    2. //  Recieve data FROM the client with postMessage()
    3. onmessage = function(event){
    4.   if ( event.data === 'load' ) {
    5.     postMessage( '-----BEGIN TRANSMISSION-----');
    6.     postMessage( {'server_objects': this} );
    7.  
    8.     $.ajax.get({
    9.       url: 'xhr_test_content.txt',
    10.       callback: function(response) {
    11.         var text = response.text;
    12.  
    13.         postMessage( 'AJAX GET RETURNED: ' + text );
    14.       }
    15.     });   
    16.     postMessage( '-----END TRANSMISSION-------');
    17.   }
    18. };
    19.  

    The Worker implementations are doing well these days. For awhile Safari didn't have importScripts but that changed before Safari 4. Chrome had some weird side effects too recently, and Malte Ubl posted on some strangeness that we ran into with our Bespin Worker Facade.

    We tested for:

    JAVASCRIPT:
    1.  
    2. if (typeof Worker == "undefined") { 
    3.  

    But that didn't work. Malte explains:

    For some reason the statement above is actually true in Chrome 2, even though as stated above support for the Worker API has not been implemented.

    I then tried to instantiate the Worker object. All this does is to throw an exception with the message "Worker is not enabled". This looks like an unfinished implementation that was only partially removed or something in that direction.

    This code handles the special case:

    JAVASCRIPT:
    1.  
    2. var noWorker = typeof Worker == "undefined" ? true : false
    3.  if(!noWorker) { 
    4.   try { new Worker("test.js") } 
    5.   catch(e) { 
    6.       e = e + "" 
    7.       if(e.indexOf("Worker is not enabled") != -1) { 
    8.           noWorker = true
    9.       } 
    10.   } 
    11. } 
    12.  

    The bug is filed. The good news is that workers are looking pretty good these days!

    Posted by Dion Almaer at 6:03 am
    2 Comments

    ++---
    2.6 rating from 17 votes

    Thursday, July 23rd, 2009

    Multiple font weights via CSS 3 and more font fun

    Category: CSS

    Ilia Draznin has been using CSS3 font face to fake font weights:

    The way @font-face works is that whatever font attributes you specify for a @font-face rule, they don’t determine how the font looks but rather when it’s gonna get used. For example if you have the following two rules

    CSS:
    1.  
    2. @font-face {
    3.     font-family: newfont;
    4.     src: local(Arial);
    5.     font-weight: 200;
    6. }
    7.  
    8. @font-face {
    9.     font-family: newfont;
    10.     src: local(Calibri);
    11.     font-weight: 300;
    12. }
    13.  

    Then if you use the “newfont” font-family with weight 200 it’s going to use Arial, but if you use it with weight 300 it’s going to use Calibri. So we can take advantage of that, and since it uses @font-face we don’t even have to worry if the user’s computer has fonts or not.

    We posted on TypeKit recently, and we have another playa Kernest in the "fix friggin type on the Web" game.

    And for a final little nugget of font goodness, from @schill:

    Typekit looks to include jQuery, loads CSS with base64-encoded data:font/otf URLs for @font-face. "Safer" than a plain open .TTF, I suppose.

    Posted by Dion Almaer at 6:47 am
    2 Comments

    +++--
    3.6 rating from 22 votes

    Wednesday, July 22nd, 2009

    Jetpack to the future with recording Audio API

    Category: JavaScript, Mozilla

    The Jetpack project is still a young 'un from Mozilla Labs (disclaimer: I work for labs!) but they are moving swiftly indeed, and each new release has a wicked cool new API that let's you do something you couldn't easily do before.

    With the Jetpack 0.4 release we see two cool APIs:

    Audio Recording API

    We have a shiny new <audio> tag which is great for playing audio and all, but how about adding the ability for users to easily create audio?

    The new Audio Recording API lets you do just that:

    JAVASCRIPT:
    1.  
    2. jetpack.future.import('audio');
    3. jetpack.audio.recordToFile();
    4. var path = jetpack.audio.stopRecording();
    5.  

    Play the local file back with jetpack.audio.playFile() or upload it and just use the audio tag itself.

    A great showcase of this is the voice memo jetpack "which lets you annotate any webpage you are looking at with your voice." Live streaming is even coming soon. Here comes video conferencing the Open Web way?

    Page Mods API

    Jetpack is a great way to do Greasemonkey-like work. To make it even easier, you need a way to define when the jetpack kicks in etc, and this is exactly what the Page Mods API gives you.

    Check out the blacklist example:

    JAVASCRIPT:
    1.  
    2. jetpack.future.import("pageMods");
    3.  
    4. var callback = function(document){
    5.   // check the current time if it is between 9 and 5
    6.   // 'blacklist' the sites in options.matches
    7.   var currentTime;
    8.   var currentHour;
    9.   currentTime = new Date();
    10.   currentHour = currentTime.getHours();
    11.   if (currentHour> 8 && currentHour <17){
    12.     document.title = "This site is blacklisted. Get some work done!";
    13.     $(document).find("body").css({border:"3px solid #000000"});
    14.     $(document).find("body").children().hide();
    15.     $(document).find("body").prepend($('<h1>Sorry this site is blacklisted until 17:00. sadface.'));
    16.   }
    17.  
    18. };
    19.  
    20. var options = {};
    21. options.matches = ["http://*.reddit.com/*",
    22.                    "http://*.cnn.com/*",
    23.                    "http://*.bbc.co.uk/*",
    24.                    "http://*.dpreview.com/*",
    25.                    "http://dpreview.com/*",
    26.                    "http://*.bloglines.com/*",
    27.                    "http://bloglines.com/*"];
    28. jetpack.pageMods.add(callback, options);
    29.  

    Nice work guys.

    Posted by Dion Almaer at 6:15 am
    4 Comments

    ++++-
    4.2 rating from 21 votes

    Tuesday, July 21st, 2009

    Wouldn’t it be Swell to be able to drag and drop between Web and desktop

    Category: Framework, HTML, JavaScript

    Christophe Eblé has kindly written a guest post on Swell JS and his drag and drop manager that works with your desktop. Here he tells us more:

    At Swell we were about to create a Drag & Drop Manager just like in other Javascript libraries such as Jquery, YUI, Mootools, Scriptaculous, but we were not really satisfied with this decision.

    What motivated us to adopt another strategy is that we didn't want to provide yet another simulated solution but instead a drag & drop library that would use the real power of the web browser.

    We've been faced to a lot of problems and we are still struggling with API differences. The Pros and cons of using system drag&drop over simulated solutions:

    Pros

    • Accuracy and performance, mouse move tricks to position an element under the pointer and detect target collision are things of the past, system DD is wicked fast!
    • system DD can be anything you like (simple images or complex dom nodes) and can interact within your browser window, the chrome (search field, address bar...) or tabs (if the browser allows it, FF 3.5 does it right) and even your OS.
    • system DD through the dataTransfer object can carry powerful meta information that are not necessary the dragged object itself, this can be arbitrary text (JSON data for ex.), urls and for the latest browsers complex data types see this
    • system DD has true DOM Events

    Cons

    • Browser differences in this subject are a real pain, I couldn't list all the oddities here :)

    The drag & drop implementation in Swell is still at an early stage, and not officially released but here's some details on what we're working on.

    • Provide a single way to create native drag & drop objects in every possible browser
    • Provide setDragImage method on browsers that don't support it yet
    • Provide a DD Manager that acts as a container for all drag and drop events on which you can place your handlers, cancel events, or quickly batch all the DD objects on the page. (useful when you deal with dozens of DD Objects)
    • Provide a way to associate complex metadata with each DD objects
    • Provide a way to easily create visual feedback for your DD Objects
    • Tight integration with our event library
    • and much more...

    There's a TRAC available on the project with a roadmap and release dates, a blog, and even a SVN repo that you can check out. Be careful, as I said above the library is still in heavy development and is missing docs! We are looking for any kind of help and just hope to receive massive feedback ;).

    See some examples in action:

    In the video, we are providing a simple yet powerful application to import a RSS feed in your webpage. The classical way is to type in the feed URL and then getting redirected to it, which commonly takes 3 to 5 steps. With this implementation you just have to drop the RSS icon onto an appropriate target and that’s all folks!

    We use YQL and JSONP to transform RSS into JSON and of course a Swell Element to dynamically attach the behavior to the webpage:

    JAVASCRIPT:
    1.  
    2. var dd2 = new Swell.Lib.DD.Droppable('moo');
    3.  
    4. dd2.ondrop = function(e) {
    5.     var file = this.getData(e, 'DD_URL').split("\n")[0];
    6.     if (/^http\:\/\//i.test(file) !== true) {
    7.         return false;
    8.     }
    9.     $('debug').setHTML('loading…');
    10.     e.target.className = '';
    11.  
    12.     var yqlRequest = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss%20where%20url=%22'+file+'%22&amp;format=json&amp;callback=moo';
    13.     html.script({
    14.         'type' : 'text/javascript',
    15.         'src'  : yqlRequest
    16.     }).appendTo(document.getElementsByTagName('head')[0]);
    17. }
    18.  

    Posted by Dion Almaer at 6:06 am
    60 Comments

    ++++-
    4.6 rating from 46 votes

    Monday, July 20th, 2009

    A detailed look at how tracing, and TraceMonkey works

    Category: JavaScript, Performance

    David Mandelin has generously detailed an overview of tracing and TraceMonkey in particular.

    He starts out by explaining the problem at hand: making a dynamic language such as JavaScript fast is hard.

    How do you get type info in dynamic type land?

    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.

    Then it gets practical, with examples of tracing in action, and even discussing what items are not traced yet:

    • 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.

    Before you optimize for that.... there is already work on the way to trace here too. Finally, we end up with a comparison of various JIT approaches, for example how Nitro/V8 do their thang.

    A really nice article.

    Posted by Dion Almaer at 1:06 pm
    6 Comments

    ++++-
    4.6 rating from 23 votes

    Next Page »