Surfin’ Safari

Cameron Zwarich is a WebKit Reviewer

Posted by Maciej Stachowiak on Monday, June 23rd, 2008 at 12:58 pm

Cameron Zwarich is now a qualified WebKit Reviewer. Cameron has been doing amazing work on the JavaScript implementation and was one of the core developers on the new bytecode engine. He has also branched out into other areas of the code and squashed bugs of all varieties. Please join me in congratulating Cameron on his reviewer status and thanking him for all of his contributions to WebKit.

Announcing SquirrelFish

Posted by ggaren on Monday, June 2nd, 2008 at 5:37 pm

SquirrelFish Mascot

“Hello, Internet!”

WebKit’s core JavaScript engine just got a new interpreter, code-named SquirrelFish.

SquirrelFish is fast—much faster than WebKit’s previous interpreter. Check out the numbers. On the SunSpider JavaScript benchmark, SquirrelFish is 1.6 times faster than WebKit’s previous interpreter.

SunSpider runs per minute

bar graph of SunSpider runs

Longer bars are better.

What Is SquirrelFish?

SquirrelFish is a register-based, direct-threaded, high-level bytecode engine, with a sliding register window calling convention. It lazily generates bytecodes from a syntax tree, using a simple one-pass compiler with built-in copy propagation.

SquirrelFish owes a lot of its design to some of the latest research in the field of efficient virtual machines, including research done by Professor M. Anton Ertl, et al, Professor David Gregg, et al, and the developers of the Lua programming language.

Some great introductory reading on these topics includes:

I’ve also pored over stacks of terrible books and papers on these topics. I’ll spare you those.

Why It’s Fast

Like the interpreters for many scripting languages, WebKit’s previous JavaScript interpreter was a simple syntax tree walker. To execute a program, it would first parse the program into a tree of statements and expressions. For example, the expression “x + y” might parse to

        +
      /   \
     x     y

Having created a syntax tree, the interpreter would recursively visit the nodes in the tree, performing their operations and propagating execution state. This execution model incurred a few types of run-time cost.

First, a syntax tree describes a program’s grammatical structure, not the operations needed to execute it. Therefore, during execution, the interpreter would repeatedly visit nodes that did no useful work. For example, for the block “{ x++; }”, the interpreter would first visit the block node “{…}”, which did nothing, and then visit its first child, the increment node “x++”, which incremented x.

Second, even nodes that did useful work were expensive to visit. Each visit required a virtual function call and return, which meant a couple of indirect memory reads to retrieve the function being called, and two indirect branches—one for the call, and one for the return. On modern hardware, “indirect” is a synonym for “slow”, since indirection tends to defeat caching and branch prediction.

Third, to propagate execution state between nodes, the interpreter had to pass around a bunch of data. For example, when processing a subtree involving a local variable, the interpreter would copy the variable’s value between all the nodes in the subtree. So, starting at the “x” part of the expression “f((x) + 1)”, a variable node “x” would return x to a parentheses node “(x)”, which would return x to a plus node “(x) + 1”. Then, the plus node would return (x) + 1 to an argument list node “((x) + 1)”, which would copy that value into an argument list object, which, in turn, it would pass to the function node for f. Sheesh!

In our first rounds of optimization, we squeezed out as much performance as we could without changing this underlying architecture. Doing so allowed us to regression test each optimization we wrote. It also set a very high bar for any replacement technology. Finally, having realized the full potential of the syntax tree architecture, we switched to bytecode.

SquirrelFish’s bytecode engine elegantly eliminates almost all of the overhead of a tree-walking interpreter. First, a bytecode stream exactly describes the operations needed to execute a program. Compiling to bytecode implicitly strips away irrelevant grammatical structure. Second, a bytecode dispatch is a single direct memory read, followed by a single indirect branch. Therefore, executing a bytecode instruction is much faster than visiting a syntax tree node. Third, with the syntax tree gone, the interpreter no longer needs to propagate execution state between syntax tree nodes.

The bytecode’s register representation and calling convention work together to produce other speedups, as well. For example, jumping to the first instruction in a JavaScript function, which used to require two C++ function calls, one of them virtual, now requires just a single bytecode dispatch. At the same time, the bytecode compiler, which knows how to strip away many forms of intermediate copying, can often arrange to pass arguments to a JavaScript function without any copying.

Just the Beginning

In a typical compiler, conversion to bytecode is just a means to an end, not an end in itself. The purpose of the conversion is to “lower” an abstract tree of grammatical constructs to a concrete vector of execution primitives, the latter form being more amenable to well-known optimization techniques.

Therefore, though we’re very happy with SquirrelFish’s current performance, we also believe that it’s just the beginning. Some of the compile-time optimizations we’re looking at, now that we have a bytecode representation, include:

  • constant folding
  • more aggressive copy propagation
  • type inference—both exact and speculative
  • specialization based on expression context—especially void and boolean context
  • peephole optimization
  • escape analysis

This is an interesting problem space. Since many scripts on the web are executed once and then thrown away, we need to invent versions of these optimizations that are simple and efficient. Moreover, since JavaScript is such a dynamic language, we also need to invent versions of these optimizations that are resilient in the context of an unknown environment.

We’re also looking at further optimizing the virtual machine, including:

  • constant pool instructions
  • superinstructions
  • instructions with implicit register operands
  • advanced dispatch techniques, like instruction duplication and context threading
  • getting computed goto working on Windows

Performance on Windows has extra room to grow because the interpreter on Windows is not direct-threaded yet. In place of computed goto, it uses a switch statement inside a loop.

Getting Involved

If you’re interested in compilers or virtual machines, this is a great project to join. We’re moving quickly, so the best way to come up to speed is to log on to our IRC channel.

As always, testing out nightly builds and reporting bugs is also a great help.

Extra Bonus Updates

We’ve got some extra bonus info: very early draft documentation of the SquirrelFish VM’s opcodes. For those of you who know about VMs, you may find this enlightening, for those who don’t, you may find it is simpler than you expect.

In addition, we have a detailed comparison of Safari 3.1 vs. SquirrelFish, looking at the individual tests, it is interesting to see which sped up the most. If you look at this comparison to Safari 3.0, you can see that we’ve sped up 4.34x overall since Safari 3, and have improved some kinds of code by over an order of magnitude.

SquirrelFish around the web: There’s lots of interesting discussion in the reddit article about this post. And posts from key SquirrelFish developer Cameron Zwarich has performance data and other info, as does occasional WebKit contributor Charles Ying.

Safari Hits 6.25% Market Share

Posted by Maciej Stachowiak on Saturday, May 31st, 2008 at 9:04 pm

The latest browser market share data is in, and Safari has hit 6.25%, breaking 6% for the first time. Last month’s share was 5.81%, so this is a significant increase. It was only nine months ago that Safari broke 5%. Safari market share has now almost tripled from 2.14% in June 2005, when the WebKit Open Source project launched.

This growth, combined with recent WebKit adoption in projects such as the Iris Browser, Qt 4.4, Android, Adobe AIR, Epiphany, KDE Plasma, iCab and more, is breathtaking and shows huge positive momentum for the WebKit project. Thanks and congratulations to everyone who has contributed to the project.

Third Annual WebKit Open Source Party

Posted by Adele Peterson on Wednesday, May 28th, 2008 at 11:08 am

It’s that time of year again! Web developers, WebKit hackers, browser developers, or anyone with an interest in cool technology should come have a drink and some snacks, and meet WebKit contributors from Apple and around the world. This event is open to anyone who is interested, free of charge.

Don’t miss out on the nerd party of the century!!!!

Details

Place: Thirsty Bear Restaurant & Brewery (map)
Date: Tuesday, June 10th
Time: 7:30 PM
upcoming.org

Reporting WebKit Security Bugs

Posted by Sam Weinig on Wednesday, May 7th, 2008 at 6:22 pm

Security is a top priority for the WebKit project. As contributors to the project have grown, it has become apparent that we need a process for safely reporting security vulnerabilities to the WebKit project in addition to the process for reporting vulnerabilities to Apple. Today, we are announcing a new mailing list for this purpose, security@webkit.org. In addition, you can now safely report vulnerabilities over https to our bug tracker, https://bugs.webkit.org, by placing the bug in the Security component. The people privy to the mailing list and the Security component are members of the Security group. It currently includes vendors shipping products that include WebKit, active port owners and trusted security experts. If you are shipping a product that includes WebKit and would like to be notified of security issues, please email security@webkit.org.

CSS Reflections

Posted by Dave Hyatt on Tuesday, April 29th, 2008 at 1:07 pm

WebKit now supports reflections in CSS. Continuing the trend of using adorable baby photos to make features appear more impressive, let me introduce Kate again. :)

A reflection is a replica of the original object with its own specific transform and mask. The box-reflect property can be used to specify the specialized transform and mask that should be used for the replica.

-webkit-box-reflect: <direction> <offset> <mask-box-image>

<direction> can be one of above, below, left or right.
<offset> is a length or percentage that specifies the distance of the reflection from the edge of the original border box (using the direction specified). It can be omitted, in which case it defaults to 0.
<mask-box-image> is a mask-box-image that can be used to overlay the reflection. If omitted, the reflection has no mask.

Reflections will update automatically as the source changes. If you hover over links, you’ll see the hover effect happen in the reflection. If you reflect the <video> element, you will see the video playing in the reflection.

Giving an element a reflection has the effect of creating a stacking context (so it joins opacity, masks and transforms). The reflection is non-interactive, so from the point of view of hit testing, it’s like it isn’t there. The reflection will have no effect on layout (other than being part of a container’s overflow), and can be thought of as similar to box-shadow in this respect.

The example above uses a gradient mask. Here is the sample code:

<img src=”bubbles.jpg” style=”border:5px solid white;-webkit-box-reflect:below 5px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.5, transparent), to(white));”>

CSS Masks

Posted by Dave Hyatt on Thursday, April 24th, 2008 at 11:53 am

WebKit now supports alpha masks in CSS. Masks allow you to overlay the content of a box with a pattern that can be used to knock out portions of that box in the final display. In other words, you can clip to complex shapes based off the alpha of an image.

Here is a snapshot of the Speed Racer movie trailer clipped to the Safari compass icon. This is in fact a mask applied to the <video> element.

We have introduced new properties to provide Web designers with a lot of control over these masks and how they are applied. The new properties are analogous to the background and border-image properties that already exist.

-webkit-mask (background)
-webkit-mask-attachment (background-attachment)
-webkit-mask-clip (background-clip)
-webkit-mask-origin (background-origin)
-webkit-mask-image (background-image)
-webkit-mask-repeat (background-repeat)
-webkit-mask-composite (background-composite)
-webkit-mask-box-image (border-image)

Use of a mask results in a stacking context being created (similar to how opacity and transforms work). The mask will therefore overlay the child and all of its descendants, and at a minimum will knock out everything outside the border box of the object.

From a Web designer’s perspective, think of the mask as being constructed the way the backgrounds and border-image of a box are constructed. Multiple backgrounds are stacking on top of one another (possibly overlapping) with their own tiling and clipping rules. A border-image can then potentially be stretched or tiled over the backgrounds.

The final resultant image built from putting all of the mask images together, tiling them, stretching them, etc., then becomes the mask used to clip the content. Alpha values of 0 in the mask mean that nothing should be drawn. Alpha values of 1 mean the content should display normally. Anything in between ends up partially transparent.

One key difference between mask-box-image and its border-image counterpart is that it doesn’t attempt to fit itself to border widths. It will just render the corners unscaled and tile/stretch itself into the border box without regard for the border itself. This lets you easily use nine-piece-image effects as masks on elements without borders (often image or video elements).

Here are two sample images. The source image that we want to mask and then the image that we will use as the mask.

We can place a mask on the image element simply by doing this:

<img src=”kate.png” style=”-webkit-mask-box-image: url(mask.png) 75 stretch;”>

The result looks like this:

CSS gradients can be used as the mask image source as well. In the following example a linear gradient is used to achieve a fade effect. For example:

<img src=”kate.png” style=”-webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1), to(rgba(0,0,0,0))”>

Masks respect the border-radius curves of an object. We can add a border-radius to the previous example, and have both the gradient fade effect with rounded corners.

<img src=”kate.png” style=”-webkit-border-radius: 10px; -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1), to(rgba(0,0,0,0))”>

SVG images can be used as masks. For example, a partially transparent circle:

can be applied as a mask like so:

<img src=”kate.png” style=”-webkit-mask-image: url(circle.svg)”>

The end result is shown below:

All of the power of the multiple background and border-image syntax is at your disposal when building masks!

As usual leave feedback in the comments and file bugs on any problems you notice at http://bugs.webkit.org/.

WebKit GSoC Students Announced

Posted by Eric Seidel on Monday, April 21st, 2008 at 12:10 pm

Google has released the list of students they will be sponsoring to work on WebKit as part of the Google Summer of Code this year. Congratulations to all of the students. We look forward to working with you closely this summer!

Thank you again to all the great students who applied! Unfortunately we had over twice as many applications as we had funding slots from Google. You’re certainly all welcome to come hack with us in #webkit any time.

Google’s official announcement

CSS Canvas Drawing

Posted by Dave Hyatt on Thursday, April 17th, 2008 at 11:33 am

Currently the set of images you can use from CSS consists of the following:

Bitmap Images (PNG, GIF, JPG)
SVG Images
Gradients

A notable missing ability when compared with explicit DOM content is programmatic drawing into CSS images. The <canvas> element represents a foreground bitmap image that can be drawn into programmatically, but - aside from inefficient hacks involving toDataURL - there hasn’t been any way to draw into the image buffers used by CSS images.

Until now!

In the latest nightlies, you can try out a new feature: the ability to specify named image buffers in CSS and then to draw into them programmatically from JavaScript. Here’s how it works.

background: -webkit-canvas(mycanvas);

Instead of specifying an image URL, you specify a canvas and an identifier to use for that canvas. The following new API on documents can then be used to obtain a drawing context for that canvas.

CanvasRenderingContext getCSSCanvasContext(in DOMString contextType, in DOMString identifier, in long width, in long height);

There is only one CSS canvas for a given global identifier per document. When you obtain the drawing context you also specify the size. The canvas will not be cleared as long as you repeatedly request the same size. Specifying a new size is equivalent to the kind of behavior you’d expect if you resized a <canvas> element, and so the canvas buffer will be cleared.

All objects that observe a CSS canvas of the same name are sharing that canvas. This means that (similar to how animated GIFs work), you can do animations and have them happen in lockstep on all the clients of the canvas. Drawing changes will be propagated to all clients automatically.

Here is an example:

Canvas as Background Image

Introducing CSS Gradients

Posted by Dave Hyatt on Monday, April 14th, 2008 at 12:39 pm

WebKit now supports gradients specified in CSS. There are two types of gradients: linear gradients and radial gradients.

The syntax is as follows:

-webkit-gradient(<type>, <point> [, <radius>]?, <point> [, <radius>]? [, <stop>]*)

The type of a gradient is either linear or radial.

A point is a pair of space-separated values. The syntax supports numbers, percentages or the keywords top, bottom, left and right for point values.

A radius is a number and may only be specified when the gradient type is radial.

A stop is a function, color-stop, that takes two arguments, the stop value (either a percentage or a number between 0 and 1.0), and a color (any valid CSS color). In addition the shorthand functions from and to are supported. These functions only require a color argument and are equivalent to color-stop(0, …) and color-stop(1.0, …) respectively.

Paraphrasing the HTML5 spec and adjusting the language slightly to not be canvas-specific:

“The color of the gradient at each stop is the color specified for that stop. Between each such stop, the colors and the alpha component must be linearly interpolated over the RGBA space without premultiplying the alpha value to find the color to use at that offset. Before the first stop, the color must be the color of the first stop. After the last stop, the color must be the color of the last stop. When there are no stops, the gradient is transparent black.

If multiple stops are added at the same offset on a gradient, they must be placed in the order added, with the first one closest to the start of the gradient, and each subsequent one infinitesimally further along towards the end point (in effect causing all but the first and last stop added at each point to be ignored).”

The points of a linear gradient specify a line. Linear gradients must be rendered such that at and before the starting point the color at offset 0 is used, that at and after the ending point the color at offset 1 is used, and that all points on a line perpendicular to the line that crosses the start and end points have the color at the point where those two lines cross (with the colors coming from the interpolation described above).

If x0 = x1 and y0 = y1, then the linear gradient must paint nothing.

For a radial gradient, the first two arguments represent a start circle with origin (x0, y0) and radius r0, and the next two arguments represent an end circle with origin (x1, y1) and radius r1.

Radial gradients must be rendered by following these steps:

If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing. Abort these steps.

Let x(ω) = (x1-x0)ω + x0

Let y(ω) = (y1-y0)ω + y0

Let r(ω) = (r1-r0)ω + r0

Let the color at ω be the color of the gradient at offset 0.0 for all values of ω less than 0.0, the color at offset 1.0 for all values of ω greater than 1.0, and the color at the given offset for values of ω in the range 0.0 ≤ ω ≤ 1.0

For all values of ω where r(ω) > 0, starting with the value of ω nearest to positive infinity and ending with the value of ω nearest to negative infinity, draw the circumference of the circle with radius r(ω) at position (x(ω), y(ω)), with the color at ω, but only painting on the parts of the surface that have not yet been painted on by earlier circles in this step for this rendering of the gradient.

This effectively creates a cone, touched by the two circles defined in the creation of the gradient, with the part of the cone before the start circle (0.0) using the color of the first offset, the part of the cone after the end circle (1.0) using the color of the last offset, and areas outside the cone untouched by the gradient (transparent black).”

So what exactly is a gradient in CSS? It is an image, usable anywhere that image URLs were used before. That’s right… anywhere. :)

You can use gradients in the following places:

background-image
border-image
list-style-image
content property

Gradients as Backgrounds

When specifying a gradient as a background, the gradient becomes a background tile. If no size is specified, then the gradient will size to the box specified by the background-origin CSS3 property. This value defaults to padding, so you the gradient will be as large as the padding-box. This is equivalent to a specified background-size of 100% in both directions.

If you want to achieve effects like tiling of a vertical gradient using a narrow strip, you should specify background-size to give the gradient tile an explicit size.

Gradients used as backgrounds will respect full page zoom, acquiring sharper resolution as the page is zoomed in.

Background Gradients Example

Border Image Gradients

Gradients can be used as border images. The most sensible use for them is specifying only horizontal or only vertical borders (and splitting the gradients up between the top and bottom or left and right borders).

The size of the gradient image is always the size of the border box.

Border Image Gradient Example

List Bullet Gradients

Gradients can be specified as list bullets. One problem with list bullet gradients is that there is currently no way in WebKit to specify the size of the marker box. Therefore the size of the image cannot be specified. WebKit has therefore chosen a default size based off the current font size of the list item.

List Item Gradients Example

Generated Content Gradients

Gradients can be used inside the content property. The image will fill the available width and height of its containing block. Therefore when using gradients inside ::before and ::after content with a specified size, it is important to set the display type to block or inline-block.

Gradients can also be used to do image replacement, so can be used with the img element in HTML or to replace the contents of other elements like spans and divs.

Generated Content Gradients Example

Final Notes

WebKit now supports a generic architecture for generated images, making it easy to add new generator effects to CSS in the future (lenticular halos, checkerboards, starbursts, etc.). The rules for sizing of these generated images will match whatever is decided for SVG content with no intrinsic size (the two are sharing the same rules right now).

We encourage you to try gradients out and file bugs if you see any unexpected or weird behavior. They will degrade safely in other browsers as long as you use multiple declarations (e.g., specify the image in one declaration and the gradient in a following declaration).