Hi,
Currently SquirrelFish doesn't optimize/cache access to properties
across scope objects if the scope object is "dynamic", i.e. can gain
properties at any time. This makes sense since a new property could be
introduced in the scope object that shadows a previously cached one.
For bindings to native objects, such as QObjects, we have the case of a
JS object that's not fully dynamic (in the sense that properties can't
be added to it ad hoc), but the only way to achieve the scope
optimization seems to be to pre-populate a static scope object's symbol
table with the object's available properties (in order for the
bytecompiler to determine that the optimization is safe).
Would it make sense to introduce a notion of a "semi-static" scope
object, in which case a special bytecode is produced that
1) does the fully scoped lookup the first time;
2) patches itself to cache / look up the property directly subsequently
(knowing that it's safe to skip the "semi-static" objects where the
lookup failed the first time)?
An alternative approach: Always cache the object where the property was
resolved, and have hooks at property creation and deletion time that
take care of invalidating the cache when properties are added to /
removed from an object that's in some scope chain. This is more generic
(works for all types of objects), but is probably more expensive (works
under the assumption that property creation+deletion is a lot rarer than
assigning to an existing property).
Example use case:
with (qtObject) {
for (i = 0; i < 10000; ++i)
Math.sin(i);
}
In this case, qtObject could have a property called Math that would
shadow the Global Object's Math. But after the first lookup, we know
whether this is the case. If it's not, it's safe to cache the Global
Object's Math. On the other hand, if qtObject _does_ have a Math
property, it can be cached / looked up directly in qtObject henceforth,
since it's never going away (native Qt properties can't be deleted).
Here's a benchmark I've been using:
a = 123;
o = {};
with (o) {
(function() {
for (var i = 0; i < 100000; ++i) {
a; a; a; a; a; a;
}
})();
}
Commenting out the "with" makes it 5x faster, because JSC is then
permitted to do the caching. I'd like to achieve that if "o" were a
QObject wrapper with no property "a", the benchmark would be about as
fast with "with" as without.
Kent