JavaScriptCore merge & binary compatibility

Maciej Stachowiak mjs@apple.com
Mon, 17 Feb 2003 16:15:38 -0800


On Sunday, February 16, 2003, at 07:51  AM, Harri Porten wrote:

>
> In regards to API changes I'm still a bit more hesitant than just BIC
> changes.

I have some specific comments about these changes. But before going 
into specifics, I'd like to say a few words about the general approach. 
When deciding whether a particular API change is worthwhile for 
performance, or which of several alternatives is better, it is 
essential to measure the real effect on performance. For Safari we have 
been very careful to justify all our changes using both examples from 
real-world pages and from artificial benchmarks.

I would like JavaScriptCore to track the mainline kjs as closely as 
possible, so it would be great if we could come up with a shared 
methodology for measuring performance, and use that to make decisions. 
That way, we'd be able to make the right choices to get excellent 
performance for both Konqueror and Safari .

(I also wrote to Harri and Peter off-list about setting up a shared way 
of measuring performance).

> The most dramatic one will be the use of Identifier rather than
> UString in the extension API but a fallback virtual function should be
> possible so that old code will keep compiling.

I think the Identifier change has been a very important performance 
win, so I hope your fallback approach works. It greatly reduces both 
string compares

> When it comes to Apple's optimized storage of Numbers I would still 
> like
> to present the approach taken in QSA first. It allows for more types 
> to be
> stored more efficiently without coding any special excemptions.

I think it is a good idea to consider other approaches, and measure the 
results. However, based on some past measurements and my personal 
intuition, I think the SimpleNumber approach is very worthwhile, and 
may work even better in combination with your approach of using a 
union. Here is some information you may find useful:

- A while back, I instrumented KJS to count total JS ValueImp 
allocations of various types, and tried it on a particular suite of 
real-world JS-intensive web pages. I found that out of the 1 million 
total allocations over the course of the test, half were NumberImps. 
 From my background with Lisp, I knew of a technique for storing small 
integers inside the pointer for a GC-based system; to test it out I 
measured how many of the numbers allocated were integers that would fit 
in a 30-bit signed value. I found that this was true of nearly all of 
them. This is because most numbers used in a web page are either array 
indexes or screen coordinates. So by doing the "number in the pointer" 
optimization, we cut the number of allocations in half, and got nearly 
all the possible win of the more complex approach for numbers.

- On the other hand, the JavaScript iBench does a lot of math with real 
floating-point numbers, and keeps them in arrays. It would be nice to 
avoid allocating for this case, and I believe the fancier union-based 
approach can help with that.

- The SimpleNumber optimization has the advantage that you can store a 
small number anywhere that a ValueImp * goes, without increasing the 
storage requirements, or changing the API. With the new GC, it is 
especially important to keep objects as small as possible, so they fit 
within the cell allocator threshold. I don't know what the QSA approach 
for this is exactly, but I assume the union only goes in Value, and 
does not help places that store a ValueImp directly (like arrays or 
property maps), or that every place that might store a ValueImp 
directly instead stores the union. I don't think either of these is the 
best approach.


Based on all this, I think a hybrid approach might be the best of all. 
SimpleNumber would still exist and be stored directly in a ValueImp * 
using special bits inside the pointer, so small numbers could always 
avoid allocating, no matter what you do with them. The union would go 
inside a new class, called something like ValueRep. A ValueRep would be 
stored directly inside a union, but could also be stored in other 
places where it is important to avoid allocating. For example, the 
non-sparse part of Arrays, and perhaps even values in property maps 
could be stored as ValueRep, allowing floats to be stored there without 
allocation.

Can you give me access to the union-based code so I can make some more 
informed remarks?


In any case, I think we should decide what to do (number-in-pointer 
only, union only, or some combination of both), based on measurement.

Regards,

Maciej