зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1054906
- Implement ES6 Symbol.hasInstance 2/2; r=jandem
--HG-- extra : rebase_source : 862c135973071b1cb8abc3a97ab446b7b137d7a8
This commit is contained in:
Родитель
df95ec2891
Коммит
6cd35e0297
|
@ -7763,6 +7763,20 @@ TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallba
|
||||||
if (fun->isBoundFunction())
|
if (fun->isBoundFunction())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If the user has supplied their own @@hasInstance method we shouldn't
|
||||||
|
// clobber it.
|
||||||
|
if (!js::FunctionHasDefaultHasInstance(fun, cx->wellKnownSymbols()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Refuse to optimize any function whose [[Prototype]] isn't
|
||||||
|
// Function.prototype.
|
||||||
|
if (!fun->hasStaticPrototype() || fun->hasUncacheableProto())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Value funProto = cx->global()->getPrototype(JSProto_Function);
|
||||||
|
if (funProto.isObject() && fun->staticPrototype() != &funProto.toObject())
|
||||||
|
return true;
|
||||||
|
|
||||||
Shape* shape = fun->lookupPure(cx->names().prototype);
|
Shape* shape = fun->lookupPure(cx->names().prototype);
|
||||||
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
|
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13887,10 +13887,36 @@ IonBuilder::jsop_instanceof()
|
||||||
if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
|
if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Refuse to optimize anything whose [[Prototype]] isn't Function.prototype
|
||||||
|
// since we can't guarantee that it uses the default @@hasInstance method.
|
||||||
|
if (rhsObject->hasUncacheableProto() || !rhsObject->hasStaticPrototype())
|
||||||
|
break;
|
||||||
|
|
||||||
|
Value funProto = script()->global().getPrototype(JSProto_Function);
|
||||||
|
if (!funProto.isObject() || rhsObject->staticPrototype() != &funProto.toObject())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If the user has supplied their own @@hasInstance method we shouldn't
|
||||||
|
// clobber it.
|
||||||
|
JSFunction* fun = &rhsObject->as<JSFunction>();
|
||||||
|
const WellKnownSymbols* symbols = &compartment->runtime()->wellKnownSymbols();
|
||||||
|
if (!js::FunctionHasDefaultHasInstance(fun, *symbols))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Ensure that we will bail if the @@hasInstance property or [[Prototype]]
|
||||||
|
// change.
|
||||||
TypeSet::ObjectKey* rhsKey = TypeSet::ObjectKey::get(rhsObject);
|
TypeSet::ObjectKey* rhsKey = TypeSet::ObjectKey::get(rhsObject);
|
||||||
|
if (!rhsKey->hasStableClassAndProto(constraints()))
|
||||||
|
break;
|
||||||
|
|
||||||
if (rhsKey->unknownProperties())
|
if (rhsKey->unknownProperties())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
HeapTypeSetKey hasInstanceObject =
|
||||||
|
rhsKey->property(SYMBOL_TO_JSID(symbols->hasInstance));
|
||||||
|
if (hasInstanceObject.isOwnProperty(constraints()))
|
||||||
|
break;
|
||||||
|
|
||||||
HeapTypeSetKey protoProperty =
|
HeapTypeSetKey protoProperty =
|
||||||
rhsKey->property(NameToId(names().prototype));
|
rhsKey->property(NameToId(names().prototype));
|
||||||
JSObject* protoObject = protoProperty.singleton(constraints());
|
JSObject* protoObject = protoProperty.singleton(constraints());
|
||||||
|
|
|
@ -1156,6 +1156,20 @@ fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent)
|
||||||
return FunctionToString(cx, fun, indent != JS_DONT_PRETTY_PRINT);
|
return FunctionToString(cx, fun, indent != JS_DONT_PRETTY_PRINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols)
|
||||||
|
{
|
||||||
|
jsid id = SYMBOL_TO_JSID(symbols.hasInstance);
|
||||||
|
Shape* shape = fun->lookupPure(id);
|
||||||
|
if (shape) {
|
||||||
|
if (!shape->hasSlot() || !shape->hasDefaultGetter())
|
||||||
|
return false;
|
||||||
|
const Value hasInstance = fun->as<NativeObject>().getSlot(shape->slot());
|
||||||
|
return IsNativeFunction(hasInstance, js::fun_symbolHasInstance);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::fun_toString(JSContext* cx, unsigned argc, Value* vp)
|
js::fun_toString(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -677,6 +677,11 @@ FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
|
||||||
extern bool
|
extern bool
|
||||||
fun_toString(JSContext* cx, unsigned argc, Value* vp);
|
fun_toString(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
struct WellKnownSymbols;
|
||||||
|
|
||||||
|
extern bool
|
||||||
|
FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
|
fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
const OriginalHasInstance = Function.prototype[Symbol.hasInstance];
|
||||||
|
|
||||||
|
// Ensure that folding doesn't impact user defined @@hasInstance methods.
|
||||||
|
{
|
||||||
|
function Test() {
|
||||||
|
this.x = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(Test, Symbol.hasInstance,
|
||||||
|
{writable: true, value: () => false});
|
||||||
|
|
||||||
|
function x(t) {
|
||||||
|
return t instanceof Test;
|
||||||
|
}
|
||||||
|
|
||||||
|
function y() {
|
||||||
|
let t = new Test;
|
||||||
|
let b = true;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
b = b && x(t);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function z() {
|
||||||
|
let f = 0;
|
||||||
|
let t = 0;
|
||||||
|
for (let i = 0; i < 100; i++)
|
||||||
|
assertEq(y(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
z();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the jitting does not clobber user defined @@hasInstance methods.
|
||||||
|
{
|
||||||
|
function a() {
|
||||||
|
function b() {};
|
||||||
|
b.__proto__ = a.prototype;
|
||||||
|
return b;
|
||||||
|
};
|
||||||
|
let c = new a();
|
||||||
|
|
||||||
|
let t = 0;
|
||||||
|
let f = 0;
|
||||||
|
let e = 0;
|
||||||
|
for (let i = 0; i < 40000; i++) {
|
||||||
|
if (i == 20000)
|
||||||
|
Object.defineProperty(a.prototype, Symbol.hasInstance,
|
||||||
|
{writable: true, value: () => true});
|
||||||
|
if (i == 30000)
|
||||||
|
Object.setPrototypeOf(c, Function.prototype);
|
||||||
|
|
||||||
|
if (1 instanceof c) {
|
||||||
|
t++;
|
||||||
|
} else {
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEq(t, 10000);
|
||||||
|
assertEq(f, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
function a() {};
|
||||||
|
function b() {};
|
||||||
|
Object.defineProperty(a, Symbol.hasInstance, {writable: true, value: () => true});
|
||||||
|
assertEq(b instanceof a, true);
|
||||||
|
for (let _ of Array(10000))
|
||||||
|
assertEq(b instanceof a, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
function a(){};
|
||||||
|
function b(){};
|
||||||
|
function c(){};
|
||||||
|
function d(){};
|
||||||
|
function e(){};
|
||||||
|
Object.defineProperty(a, Symbol.hasInstance, {value: () => true });
|
||||||
|
Object.defineProperty(b, Symbol.hasInstance, {value: () => true });
|
||||||
|
Object.defineProperty(c, Symbol.hasInstance, {value: () => true });
|
||||||
|
Object.defineProperty(d, Symbol.hasInstance, {value: () => true });
|
||||||
|
let funcs = [a, b, c, d];
|
||||||
|
for (let f of funcs)
|
||||||
|
assertEq(e instanceof f, true);
|
||||||
|
|
||||||
|
for (let _ of Array(10001)) {
|
||||||
|
for (let f of funcs)
|
||||||
|
assertEq(e instanceof f, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -475,6 +475,10 @@ struct WellKnownSymbols
|
||||||
const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
|
const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
|
||||||
return get(size_t(code));
|
return get(size_t(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WellKnownSymbols() {}
|
||||||
|
WellKnownSymbols(const WellKnownSymbols&) = delete;
|
||||||
|
WellKnownSymbols& operator=(const WellKnownSymbols&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
|
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче