зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1384562 - Add OrdinaryToPrimitive fast path for stringifying plain objects. r=iain
The Ember subtest in Speedometer hits this a lot for some logging code and this is likely to also affect similar JS code elsewhere. This optimization is written so that even if it doesn't apply, there's little overhead in most cases because we do the `toString` lookup only once. Differential Revision: https://phabricator.services.mozilla.com/D160748
This commit is contained in:
Родитель
8dd1f60e09
Коммит
1b17a8466f
|
@ -0,0 +1,25 @@
|
|||
// Test for OrdinaryToPrimitive called on a plain object with hint "string".
|
||||
|
||||
function assertStr(o, s) {
|
||||
assertEq(String(o), s);
|
||||
}
|
||||
function test() {
|
||||
assertStr({x: 1}, "[object Object]");
|
||||
assertStr({[Symbol.toStringTag]: "Foo"}, "[object Foo]");
|
||||
assertStr({toString() { return 123; }}, "123");
|
||||
assertStr({toString: Math.abs}, "NaN");
|
||||
assertStr({x: "hello", toString() { return this.x; }}, "hello");
|
||||
|
||||
let c = 0;
|
||||
let fun = () => "hi-" + ++c;
|
||||
assertStr({toString: fun}, "hi-1");
|
||||
assertStr({toString: "foo", valueOf: fun}, "hi-2");
|
||||
assertStr({toString() { return {}; }, valueOf: fun}, "hi-3");
|
||||
|
||||
let proto = {};
|
||||
proto[Symbol.toStringTag] = null;
|
||||
assertStr(Object.create(proto), "[object Object]");
|
||||
proto[Symbol.toStringTag] = "Bar";
|
||||
assertStr(Object.create(proto), "[object Bar]");
|
||||
}
|
||||
test();
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "builtin/BigInt.h"
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/Object.h"
|
||||
#include "builtin/String.h"
|
||||
#include "builtin/Symbol.h"
|
||||
#include "builtin/WeakSetObject.h"
|
||||
|
@ -2372,17 +2373,37 @@ bool JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
|
|||
if (hint == JSTYPE_STRING) {
|
||||
id = NameToId(cx->names().toString);
|
||||
|
||||
/* Optimize (new String(...)).toString(). */
|
||||
bool calledToString = false;
|
||||
if (clasp == &StringObject::class_) {
|
||||
// Optimize (new String(...)).toString().
|
||||
StringObject* nobj = &obj->as<StringObject>();
|
||||
if (HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) {
|
||||
vp.setString(nobj->unbox());
|
||||
return true;
|
||||
}
|
||||
} else if (clasp == &PlainObject::class_) {
|
||||
JSFunction* fun;
|
||||
if (GetPropertyPure(cx, obj, id, vp.address()) &&
|
||||
IsFunctionObject(vp, &fun)) {
|
||||
// Common case: we have a toString function. Try to short-circuit if
|
||||
// it's Object.prototype.toString and there's no @@toStringTag.
|
||||
if (fun->maybeNative() == obj_toString &&
|
||||
!MaybeHasInterestingSymbolProperty(
|
||||
cx, obj, cx->wellKnownSymbols().toStringTag)) {
|
||||
vp.setString(cx->names().objectObject);
|
||||
return true;
|
||||
}
|
||||
if (!js::Call(cx, vp, obj, vp)) {
|
||||
return false;
|
||||
}
|
||||
calledToString = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MaybeCallMethod(cx, obj, id, vp)) {
|
||||
return false;
|
||||
if (!calledToString) {
|
||||
if (!MaybeCallMethod(cx, obj, id, vp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (vp.isPrimitive()) {
|
||||
return true;
|
||||
|
@ -2398,17 +2419,15 @@ bool JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
|
|||
} else {
|
||||
id = NameToId(cx->names().valueOf);
|
||||
|
||||
/* Optimize new String(...).valueOf(). */
|
||||
if (clasp == &StringObject::class_) {
|
||||
// Optimize new String(...).valueOf().
|
||||
StringObject* nobj = &obj->as<StringObject>();
|
||||
if (HasNativeMethodPure(nobj, cx->names().valueOf, str_toString, cx)) {
|
||||
vp.setString(nobj->unbox());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Optimize new Number(...).valueOf(). */
|
||||
if (clasp == &NumberObject::class_) {
|
||||
} else if (clasp == &NumberObject::class_) {
|
||||
// Optimize new Number(...).valueOf().
|
||||
NumberObject* nobj = &obj->as<NumberObject>();
|
||||
if (HasNativeMethodPure(nobj, cx->names().valueOf, num_valueOf, cx)) {
|
||||
vp.setNumber(nobj->unbox());
|
||||
|
|
Загрузка…
Ссылка в новой задаче