--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.
--
No. You are misinterpreting results. Invocations of methods defined on
prototypes of objects cost roughly the same as invocations of local
functions (it's just a couple of additional checks/loads). V8 goes to
a great lengths to make such calls as fast as possible.
But the benchmark is measuring something completely different: cost of
calls of a non-builtin method defined on String.prototype with a
primitive receiver.
According to the ECMA-262 spec receiver has to be coerced to an
Object, so a temporary String object has to be created for each such
call.
String.prototype.foo = function () { };
var a = ""; for (var i = 0; i < 1e7; i++) a.foo();
actually does something like:
String.prototype.foo = function () { };
var a = ""; for (var i = 0; i < 1e7; i++) new String(a).foo();
Even more: V8 does not handle this neither in generated code nor does
it use specialized ICs or stubs for this case, so execution just falls
through to the runtime system for every foo invocation. This (memory
allocation + GCs + going to runtime system for each call) is quite
expensive.
There is of course an optimization in place that avoids such overhead
for built-in methods of String (like indexOf etc). But optimizing away
overhead in the general case is difficult (or even impossible for
certain cases): it requires proving that call target can operate on a
primitive receiver without noticing that it was not coerced to an
object.
--
Vyacheslav Egorov
Well. Actually they are much less expensive then falling though to the
runtime system on each call [try https://gist.github.com/846213].
> So, why doing them over and over?
While strings are immutable String objects are not. So you can't just
reuse the same wrapper all the time.
> maybe one can get access to
> the "temporary" String object (that would be better called
> "CoercedString" at the implementation level I guess) and add
> properties to it, but how?
Easily:
String.prototype.foo = function (a) {
if (this.bar) { throw new Error ("OMG! Somebody is not following
ECMA-262 and caching String objects!"); }
this.bar = true;
};
var a = "a";
a.foo(); // foo will set property "bar" on the implicitly created String object
a.foo(); // if we reuse the String object here it will have "bar"
property, but it should be fresh String object according to the spec.
But as I said above the performance penalty mostly comes from the fact
that call has to go through the runtime system.
I've filed an issue: http://code.google.com/p/v8/issues/detail?id=1212.
--
Vyacheslav Egorov
Copy-on-write looks as something basic until you try to implement it.
And as I tried to point in my previous messages: there are some more
serious performance pitfalls here than wrapper allocation.
> Put differently: want good perf? stick with primitive types and avoid
> dynamic dispatch... basically "avoid OO"
You are again misinterpreting results of the benchmark. As I said
earlier: V8 goes to a great length to optimize dispatch and property
accesses through prototype chain. 2 benchmarks in the V8 Benchmark
Suite (Richards and DeltaBlue) heavily use OO programming, inheritance
and polymorphism; their score highly depends on the quality of
dispatch mechanisms used by VM.
Back to your benchmark. Take a look at
http://jsperf.com/oo-vs-functional-calls-str/2.
I have fixed a small typo in str_starts (replaced 'this' by 'that')
and more importantly added another test-case "functional style with
coerced that."
You can notice that it shows the same performance (at least on the
recent Chrome 11) as your test case "oo style, more coerce". So
dynamic dispatch virtually costs no more than what looks like a
"direct" call --- the difference comes from the wrapping around 'that'
object.
My recommendation is: don't avoid OO, it's cheap --- avoid wrappers
around primitive types, they are expensive.
--
Vyacheslav Egorov
> (...) avoid wrappers
> around primitive types, they are expensive.
In strict mode this will run faster :-)
--
Jorge.
So I can extend my recommendation: when adding functions to prototypes
of String/Number define them as strict to avoid overhead with wrapping
and unwrapping on VMs that support strict mode.
I have extended http://jsperf.com/oo-vs-functional-calls-str/2 with an
appropriate test case. It will show good results on browsers with VMs
that implement this part of strict mode.
--
Vyacheslav Egorov