Merge pull request #16 from classilla/master

Keep Up with FPR
This commit is contained in:
Riccardo 2018-10-31 18:32:00 +01:00 committed by GitHub
commit f32a975b75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 1050 additions and 56 deletions

View File

@ -1 +1 @@
45.19.0
45.20.0

View File

@ -1 +1 @@
Feature Parity Release 10
Feature Parity Release 11

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
45.19.0
45.20.0

View File

@ -10591,6 +10591,25 @@ nsDocShell::DoURILoad(nsIURI* aURI,
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
}
if (!inherit) {
// We can confidently assume this is a channel that does not inherit
// the principal, and thus does not have flags on the protocol that
// ask for it. If the load is for a data: URI, inherit the principal if
// the system principal initiated the load to maintain compatibility
// with addons, but warn the user as a penalty (TenFourFox issue 525).
bool isData = false;
rv = aURI->SchemeIs("data", &isData);
if (NS_SUCCEEDED(rv) && isData) {
if (nsContentUtils::IsSystemPrincipal(triggeringPrincipal)) {
fprintf(stderr,
"Warning: TenFourFox enabling inherited principal for data: URI from system.\n"
"Warning: Make sure you are using a minimum set of up-to-date addons.\n"
);
inherit = true;
}
}
}
nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
if (inherit) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;

View File

@ -1168,17 +1168,6 @@ Element::GetDestinationInsertionPoints()
void
Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
{
// Complete the illusion of TenFourFox issue 517 by preventing Rocket Loader
// from seeing the data-cf-nonce attribute. This doesn't seem to be used
// anywhere else in the Cloudflare stack.
if (!IsXULElement() && MOZ_UNLIKELY(aName.LowerCaseEqualsASCII("data-cf-nonce"))) {
#if DEBUG
fprintf(stderr, "TenFourFox: blocked access to proscribed property data-cf-nonce.\n");
#endif
aReturn.SetNull();
return;
}
const nsAttrValue* val =
mAttrsAndChildren.GetAttr(aName,
IsHTMLElement() && IsInHTMLDocument() ?

View File

@ -7216,10 +7216,10 @@ nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType)
}
}
// Workaround for Rocket Script; current versions do not load properly.
// Workaround for Rocket Loader; current versions do not work properly.
// This version just relaxes the limits on the MIME type so that the
// browser loads the scripts for us and RocketScript is not involved.
// Old-school Rocket Script that used text/rocketscript is OK; we don't
// browser loads the scripts for us and Rocket Loader is not involved.
// Old-school Rocket Loader that used text/rocketscript works OK; we don't
// interfere with that.
// (TenFourFox issue 517.)
if (StringEndsWith(aMIMEType, NS_LITERAL_STRING("-text/javascript"),
@ -7227,7 +7227,7 @@ nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType)
// Don't use Find(). We really care just if it's at the end.
// If we need to look elsewhere, use FindInReadable().
#if DEBUG
fprintf(stderr, "TenFourFox: Rocket Script detected\n");
fprintf(stderr, "TenFourFox: Rocket Loader dependent script detected\n");
#endif
return true;
}

View File

@ -467,6 +467,26 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
NS_ASSERTION(!aElement->IsMalformed(), "Executing malformed script");
// TenFourFox issue 517. Complete the illusion by just not loading
// the Rocket Loader script in the first place. Not only is this much
// faster, but it also can be very reliably detected by looking for a
// |data-cf-nonce| property on the script tag which appears nowhere else
// in the Cloudflare stack presently, eliminates a hack in querying
// attributes for that property, and works better for certain sites
// where the load can clash with certain inline script elements.
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(aElement);
NS_ASSERTION(domElement, "script could not be QIed to nsIDOMElement");
if (MOZ_LIKELY(domElement)) {
nsAutoString foo;
domElement->GetAttribute(NS_LITERAL_STRING("data-cf-nonce"), foo);
if (MOZ_UNLIKELY(!foo.IsEmpty())) {
#if DEBUG
fprintf(stderr, "TenFourFox blocking Rocket Loader main script.\n");
#endif
return false;
}
}
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
// Step 12. Check that the script is not an eventhandler

View File

@ -2757,6 +2757,12 @@ imgCacheValidator::AddProxy(imgRequestProxy* aProxy)
mProxies.AppendObject(aProxy);
}
void
imgCacheValidator::RemoveProxy(imgRequestProxy* aProxy)
{
mProxies.RemoveObject(aProxy);
}
/** nsIRequestObserver methods **/
NS_IMETHODIMP

View File

@ -529,6 +529,7 @@ public:
bool forcePrincipalCheckForCacheEntry);
void AddProxy(imgRequestProxy* aProxy);
void RemoveProxy(imgRequestProxy* aProxy);
NS_DECL_ISUPPORTS
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER

View File

@ -338,14 +338,20 @@ imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
mCanceled = true;
imgRequest* owner = GetOwner();
if (owner) {
imgCacheValidator* validator = owner->GetValidator();
if (validator) {
validator->RemoveProxy(this);
}
owner->RemoveProxy(this, aStatus);
}
// Now cheat and make sure our removal from loadgroup happens async
bool oldIsInLoadGroup = mIsInLoadGroup;
mIsInLoadGroup = false;
if (GetOwner()) {
GetOwner()->RemoveProxy(this, aStatus);
}
mIsInLoadGroup = oldIsInLoadGroup;
if (mIsInLoadGroup) {

View File

@ -16,6 +16,7 @@ namespace JS {
_(GetProp_ArgumentsCallee) \
_(GetProp_InferredConstant) \
_(GetProp_Constant) \
_(GetProp_NotDefined) \
_(GetProp_StaticName) \
_(GetProp_SimdGetter) \
_(GetProp_TypedObject) \
@ -74,6 +75,7 @@ namespace JS {
_(NotObject) \
_(NotStruct) \
_(NotUnboxed) \
_(NotUndefined) \
_(UnboxedConvertedToNative) \
_(StructNoField) \
_(InconsistentFieldType) \

View File

@ -1204,6 +1204,7 @@ static const JSFunctionSpec object_static_methods[] = {
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, JSPROP_DEFINE_LATE),
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0),
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0),
JS_SELF_HOSTED_FN("getOwnPropertyDescriptors", "ObjectGetOwnPropertyDescriptors", 1, JSPROP_DEFINE_LATE),
JS_FN("keys", obj_keys, 1, 0),
JS_FN("values", obj_values, 1, 0),
JS_FN("entries", obj_entries, 1, 0),

View File

@ -41,6 +41,33 @@ function ObjectStaticAssign(target, firstSource) {
return to;
}
// ES stage 4 proposal
function ObjectGetOwnPropertyDescriptors(O) {
// Step 1.
var obj = ToObject(O);
// Step 2.
var keys = OwnPropertyKeys(obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Step 3.
var descriptors = {};
// Step 4.
for (var index = 0, len = keys.length; index < len; index++) {
var key = keys[index];
// Steps 4.a-b.
var desc = std_Object_getOwnPropertyDescriptor(obj, key);
// Step 4.c.
if (typeof desc !== "undefined")
_DefineDataProperty(descriptors, key, desc);
}
// Step 5.
return descriptors;
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.9. */
function ObjectGetPrototypeOf(obj) {
return std_Reflect_getPrototypeOf(ToObject(obj));

View File

@ -0,0 +1,32 @@
// Singleton
function f() {
var res = 0;
for (var i=0; i<500; i++)
res += ("abcd" in Math);
return res;
}
assertEq(f(), 0);
Math.abcd = 3;
assertEq(f(), 500);
delete Math.abcd;
assertEq(f(), 0);
// Non-singleton
function O(x) { if (x) this.x = 1; }
var arr = [];
for (var i=0; i<4; i++)
arr.push(new O(i % 2));
function g(arr) {
var res = 0;
for (var i=0; i<500; i++) {
var o = arr[i % arr.length];
res += "x" in o;
res += "abcd" in o;
}
return res;
}
assertEq(g(arr), 250);
arr[0].abcd = 3;
assertEq(g(arr), 375);

View File

@ -135,9 +135,9 @@ function withinIf(i) {
// Check case where one successor can have multiple times the same predecessor.
function unknownLoad(i) {
var obj = { foo: i };
// Unknown properties are inlined as undefined.
assertEq(obj.bar, undefined);
// Unknown properties are using GetPropertyCache.
assertRecoveredOnBailout(obj, false);
assertRecoveredOnBailout(obj, true);
}
// Check with dynamic slots.

View File

@ -8029,6 +8029,20 @@ TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallba
if (fun->isBoundFunction())
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->hasLazyPrototype() || fun->hasUncacheableProto())
return true;
Value funProto = cx->global()->getPrototype(JSProto_Function);
if (funProto.isObject() && fun->getProto() != &funProto.toObject())
return true;
Shape* shape = fun->lookupPure(cx->names().prototype);
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
return true;

View File

@ -7928,6 +7928,51 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id)
return nullptr;
}
bool
IonBuilder::testNotDefinedProperty(MDefinition* obj, jsid id)
{
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType_Object)
return false;
for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
while (true) {
if (!key->hasStableClassAndProto(constraints()) || key->unknownProperties())
return false;
const Class* clasp = key->clasp();
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key,
id))
return false;
// If the object is a singleton, we can do a lookup now to avoid
// unnecessary invalidations later on, in case the property types
// have not yet been instantiated.
if (key->isSingleton() &&
key->singleton()->is<NativeObject>() &&
key->singleton()->as<NativeObject>().lookupPure(id))
{
return false;
}
HeapTypeSetKey property = key->property(id);
if (property.isOwnProperty(constraints()))
return false;
JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
if (!proto)
break;
key = TypeSet::ObjectKey::get(proto);
}
}
return true;
}
bool
IonBuilder::pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind)
{
@ -8931,6 +8976,13 @@ IonBuilder::getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* inde
return *emitted;
}
trackOptimizationAttempt(TrackedStrategy::GetProp_NotDefined);
if (!getPropTryNotDefined(emitted, obj, id, types) || *emitted) {
if (*emitted)
index->setImplicitlyUsedUnchecked();
return *emitted;
}
return true;
}
@ -10966,6 +11018,11 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryConstant(&emitted, obj, NameToId(name), types) || emitted)
return emitted;
// Try to hardcode known not-defined
trackOptimizationAttempt(TrackedStrategy::GetProp_NotDefined);
if (!getPropTryNotDefined(&emitted, obj, NameToId(name), types) || emitted)
return emitted;
// Try to emit SIMD getter loads
trackOptimizationAttempt(TrackedStrategy::GetProp_SimdGetter);
if (!getPropTrySimdGetter(&emitted, obj, name) || emitted)
@ -11212,6 +11269,30 @@ IonBuilder::getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, Tempora
return true;
}
bool
IonBuilder::getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types)
{
MOZ_ASSERT(*emitted == false);
if (!types->mightBeMIRType(MIRType_Undefined)) {
// Only optimize if we expect this property access to return undefined.
trackOptimizationOutcome(TrackedOutcome::NotUndefined);
return true;
}
if (!testNotDefinedProperty(obj, id)) {
trackOptimizationOutcome(TrackedOutcome::GenericFailure);
return true;
}
obj->setImplicitlyUsedUnchecked();
pushConstant(UndefinedValue());
trackOptimizationSuccess();
*emitted = true;
return true;
}
MIRType
IonBuilder::SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
{
@ -13289,21 +13370,13 @@ IonBuilder::jsop_in()
MDefinition* obj = convertUnboxedObjects(current->pop());
MDefinition* id = current->pop();
do {
if (shouldAbortOnPreliminaryGroups(obj))
break;
bool emitted = false;
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), obj, id))
break;
}
if (!inTryDense(&emitted, obj, id) || emitted)
return emitted;
if (ElementAccessHasExtraIndexedProperty(this, obj))
break;
return jsop_in_dense(obj, id, unboxedType);
} while (false);
if (!inTryFold(&emitted, obj, id) || emitted)
return emitted;
MIn* ins = MIn::New(alloc(), id, obj);
@ -13314,8 +13387,24 @@ IonBuilder::jsop_in()
}
bool
IonBuilder::jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType)
IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id)
{
MOZ_ASSERT(!*emitted);
if (shouldAbortOnPreliminaryGroups(obj))
return true;
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), obj, id))
return true;
}
if (ElementAccessHasExtraIndexedProperty(this, obj))
return true;
*emitted = true;
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
// Ensure id is an integer.
@ -13345,6 +13434,32 @@ IonBuilder::jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxed
return true;
}
bool
IonBuilder::inTryFold(bool* emitted, MDefinition* obj, MDefinition* id)
{
// Fold |id in obj| to |false|, if we know the object (or an object on its
// prototype chain) does not have this property.
MOZ_ASSERT(!*emitted);
jsid propId;
if (!id->isConstantValue() || !ValueToIdPure(id->constantValue(), &propId))
return true;
if (propId != IdToTypeId(propId))
return true;
if (!testNotDefinedProperty(obj, propId))
return true;
*emitted = true;
pushConstant(BooleanValue(false));
obj->setImplicitlyUsedUnchecked();
id->setImplicitlyUsedUnchecked();
return true;
}
bool
IonBuilder::hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto)
{
@ -13440,10 +13555,36 @@ IonBuilder::jsop_instanceof()
if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
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->hasLazyPrototype())
break;
Value funProto = script()->global().getPrototype(JSProto_Function);
if (!funProto.isObject() || rhsObject->getProto() != &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);
if (!rhsKey->hasStableClassAndProto(constraints()))
break;
if (rhsKey->unknownProperties())
break;
HeapTypeSetKey hasInstanceObject =
rhsKey->property(SYMBOL_TO_JSID(symbols->hasInstance));
if (hasInstanceObject.isOwnProperty(constraints()))
break;
HeapTypeSetKey protoProperty =
rhsKey->property(NameToId(names().prototype));
JSObject* protoObject = protoProperty.singleton(constraints());

View File

@ -431,6 +431,7 @@ class IonBuilder
bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyName* name);
bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
bool getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types);
bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
@ -503,13 +504,17 @@ class IonBuilder
// jsop_bitnot helpers.
bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
// jsop_compare helpes.
// jsop_compare helpers.
bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
// jsop_in helpers.
bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id);
bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id);
// binary data lookup helpers.
TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
@ -732,7 +737,6 @@ class IonBuilder
bool jsop_isnoiter();
bool jsop_iterend();
bool jsop_in();
bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType);
bool jsop_instanceof();
bool jsop_getaliasedvar(ScopeCoordinate sc);
bool jsop_setaliasedvar(ScopeCoordinate sc);
@ -980,6 +984,8 @@ class IonBuilder
JSObject* testSingletonProperty(JSObject* obj, jsid id);
JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
bool testNotDefinedProperty(MDefinition* obj, jsid id);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);
MDefinition* convertUnboxedObjects(MDefinition* obj,

View File

@ -5154,7 +5154,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
TypeSet::TypeList types;
if (!property.maybeTypes()->enumerateTypes(&types))
break;
if (types.length()) {
if (types.length() == 1) {
// Note: the return value here is ignored.
observed->addType(types[0], GetJitContext()->temp->lifoAlloc());
break;

View File

@ -4560,6 +4560,7 @@ GetSymbolDescription(HandleSymbol symbol);
macro(iterator) \
macro(match) \
macro(species) \
macro(hasInstance) \
macro(toPrimitive) \
macro(toStringTag) \
macro(unscopables)

View File

@ -644,23 +644,73 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleObject, HandleScript, Mu
template bool
js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleObject, HandleScript, MutableHandleFunction);
/* ES6 (04-25-16) 19.2.3.6 Function.prototype [ @@hasInstance ] */
bool
js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
args.rval().setBoolean(false);
return true;
}
/* Step 1. */
HandleValue func = args.thisv();
// Primitives are non-callable and will always return false from
// OrdinaryHasInstance.
if (!func.isObject()) {
args.rval().setBoolean(false);
return true;
}
RootedObject obj(cx, &func.toObject());
RootedValue v(cx, args[0]);
/* Step 2. */
bool result;
if (!OrdinaryHasInstance(cx, obj, &v, &result))
return false;
args.rval().setBoolean(result);
return true;
}
/*
* [[HasInstance]] internal method for Function objects: fetch the .prototype
* property of its 'this' parameter, and walks the prototype chain of v (only
* if v is an object) returning true if .prototype is found.
* ES6 (4-25-16) 7.3.19 OrdinaryHasInstance
*/
static bool
fun_hasInstance(JSContext* cx, HandleObject objArg, MutableHandleValue v, bool* bp)
bool
js::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, MutableHandleValue v, bool* bp)
{
RootedObject obj(cx, objArg);
while (obj->is<JSFunction>() && obj->isBoundFunction())
obj = obj->as<JSFunction>().getBoundFunctionTarget();
/* Step 1. */
if (!obj->isCallable()) {
*bp = false;
return true;
}
/* Step 2. */
if (obj->is<JSFunction>() && obj->isBoundFunction()) {
/* Steps 2a-b. */
obj = obj->as<JSFunction>().getBoundFunctionTarget();
return InstanceOfOperator(cx, obj, v, bp);
}
/* Step 3. */
if (!v.isObject()) {
*bp = false;
return true;
}
/* Step 4. */
RootedValue pval(cx);
if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval))
return false;
/* Step 5. */
if (pval.isPrimitive()) {
/*
* Throw a runtime error if instanceof is called on a function that
@ -671,6 +721,7 @@ fun_hasInstance(JSContext* cx, HandleObject objArg, MutableHandleValue v, bool*
return false;
}
/* Step 6. */
RootedObject pobj(cx, &pval.toObject());
bool isDelegate;
if (!IsDelegate(cx, pobj, v, &isDelegate))
@ -835,7 +886,7 @@ const Class JSFunction::class_ = {
fun_mayResolve,
nullptr, /* finalize */
nullptr, /* call */
fun_hasInstance,
nullptr,
nullptr, /* construct */
fun_trace,
{
@ -1122,6 +1173,20 @@ fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent)
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
js::fun_toString(JSContext* cx, unsigned argc, Value* vp)
{
@ -1733,6 +1798,7 @@ const JSFunctionSpec js::function_methods[] = {
JS_FN(js_call_str, fun_call, 1,0),
JS_FN("bind", fun_bind, 1,0),
JS_FN("isGenerator", fun_isGenerator,0,0),
JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
JS_FS_END
};

View File

@ -692,6 +692,17 @@ fun_toString(JSContext* cx, unsigned argc, Value* vp);
extern bool
fun_bind(JSContext* cx, unsigned argc, Value* vp);
struct WellKnownSymbols;
extern bool
FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols);
extern bool
fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
extern bool
OrdinaryHasInstance(JSContext* cx, HandleObject objArg, MutableHandleValue v, bool* bp);
/*
* Function extended with reserved slots for use by various kinds of functions.
* Most functions do not have these extensions, but enough do that efficient

View File

@ -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);

View File

@ -0,0 +1,88 @@
// It is possible to override Function.prototype[@@hasInstance].
let passed = false;
let obj = { foo: true };
let C = function(){};
Object.defineProperty(C, Symbol.hasInstance, {
value: function(inst) { passed = inst.foo; return false; }
});
assertEq(obj instanceof C, false);
assertEq(passed, true);
{
let obj = {
[Symbol.hasInstance](v) { return true; },
};
let whatevs = {};
assertEq(whatevs instanceof obj, true);
}
{
function zzzz() {};
let xxxx = new zzzz();
assertEq(xxxx instanceof zzzz, true);
assertEq(zzzz[Symbol.hasInstance](xxxx), true);
}
// Non-callable objects should return false.
const nonCallables = [
1,
undefined,
null,
"nope",
]
for (let nonCallable of nonCallables) {
assertEq(nonCallable instanceof Function, false);
assertEq(nonCallable instanceof Object, false);
}
// Non-callables should throw when used on the right hand side
// of `instanceof`.
assertThrowsInstanceOf(() => {
function foo() {};
let obj = {};
foo instanceof obj;
}, TypeError);
// Non-callables do not throw for overridden methods
let o = {[Symbol.hasInstance](v) { return true; }}
assertEq(1 instanceof o, true);
// Non-callables return false instead of an exception when
// Function.prototype[Symbol.hasInstance] is called directly.
for (let nonCallable of nonCallables) {
assertEq(Function.prototype[Symbol.hasInstance].call(nonCallable, Object), false);
}
// It should be possible to call the Symbol.hasInstance method directly.
assertEq(Function.prototype[Symbol.hasInstance].call(Function, () => 1), true);
assertEq(Function.prototype[Symbol.hasInstance].call(Function, Object), true);
assertEq(Function.prototype[Symbol.hasInstance].call(Function, null), false);
assertEq(Function.prototype[Symbol.hasInstance].call(Function, Array), true);
assertEq(Function.prototype[Symbol.hasInstance].call(Object, Array), true);
assertEq(Function.prototype[Symbol.hasInstance].call(Array, Function), false);
assertEq(Function.prototype[Symbol.hasInstance].call(({}), Function), false);
assertEq(Function.prototype[Symbol.hasInstance].call(), false)
assertEq(Function.prototype[Symbol.hasInstance].call(({})), false)
// Ensure that bound functions are unwrapped properly
let bindme = {x: function() {}};
let instance = new bindme.x();
let xOuter = bindme.x;
let bound = xOuter.bind(bindme);
let doubleBound = bound.bind(bindme);
let tripleBound = bound.bind(doubleBound);
assertEq(Function.prototype[Symbol.hasInstance].call(bound, instance), true);
assertEq(Function.prototype[Symbol.hasInstance].call(doubleBound, instance), true);
assertEq(Function.prototype[Symbol.hasInstance].call(tripleBound, instance), true);
// Function.prototype[Symbol.hasInstance] is not configurable
let desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance)
assertEq(desc.configurable, false)
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -5,6 +5,10 @@ var names = [
"iterator",
"match",
"species",
"hasInstance",
"toPrimitive",
"toStringTag",
"unscopables"
];
for (var name of names) {

View File

@ -0,0 +1,38 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors on a proxy with duplicate ownKeys should work
esid: pending
author: Jordan Harband
features: [Proxy]
---*/
var i = 0;
var descriptors = [
{ enumerable: false, value: "A1", writable: true, configurable: true },
{ enumerable: true, value: "A2", writable: true, configurable: true }
];
var log = '';
var proxy = new Proxy({}, {
ownKeys() {
log += 'ownKeys|';
return ['DUPLICATE', 'DUPLICATE', 'DUPLICATE'];
},
getOwnPropertyDescriptor(t, name) {
log += 'getOwnPropertyDescriptor:' + name + '|';
return descriptors[i++];
}
});
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(result.hasOwnProperty('DUPLICATE'), true);
var lastDescriptor = descriptors[descriptors.length - 1];
assert.notSameValue(result.DUPLICATE, lastDescriptor);
assert.sameValue(result.DUPLICATE.enumerable, lastDescriptor.enumerable);
assert.sameValue(result.DUPLICATE.configurable, lastDescriptor.configurable);
assert.sameValue(result.DUPLICATE.value, lastDescriptor.value);
assert.sameValue(result.DUPLICATE.writable, lastDescriptor.writable);
assert.sameValue(log, 'ownKeys|getOwnPropertyDescriptor:DUPLICATE|getOwnPropertyDescriptor:DUPLICATE|getOwnPropertyDescriptor:DUPLICATE|');

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should fail if given a null or undefined value
esid: pending
author: Jordan Harband
---*/
assert.throws(TypeError, function () {
Object.getOwnPropertyDescriptors(null);
});
assert.throws(TypeError, function () {
Object.getOwnPropertyDescriptors(undefined);
});

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should have length 1
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
assert.sameValue(Object.getOwnPropertyDescriptors.length, 1, 'Expected Object.getOwnPropertyDescriptors.length to be 1');
var desc = Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptors, 'length');
assertEq(desc.enumerable, false);
assertEq(desc.writable, false);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,20 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should have name property with value 'getOwnPropertyDescriptors'
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
assert.sameValue(
Object.getOwnPropertyDescriptors.name,
'getOwnPropertyDescriptors',
'Expected Object.getOwnPropertyDescriptors.name to be "getOwnPropertyDescriptors"'
);
var desc = Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptors, 'name');
assertEq(desc.enumerable, false);
assertEq(desc.writable, false);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should be writable, non-enumerable, and configurable
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
var desc = Object.getOwnPropertyDescriptor(Object, 'getOwnPropertyDescriptors');
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,43 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors does not see inherited properties.
esid: pending
author: Jordan Harband
---*/
var F = function () {};
F.prototype.a = {};
F.prototype.b = {};
var f = new F();
var bValue = {};
f.b = bValue; // shadow the prototype
Object.defineProperty(f, 'c', {
enumerable: false,
configurable: true,
writable: false,
value: {}
}); // solely an own property
var result = Object.getOwnPropertyDescriptors(f);
assert.sameValue(!!result.b, true, 'b has a descriptor');
assert.sameValue(!!result.c, true, 'c has a descriptor');
assert.sameValue(result.b.enumerable, true, 'b is enumerable');
assert.sameValue(result.b.configurable, true, 'b is configurable');
assert.sameValue(result.b.writable, true, 'b is writable');
assert.sameValue(result.b.value, bValue, 'bs value is `bValue`');
assert.sameValue(result.c.enumerable, false, 'c is enumerable');
assert.sameValue(result.c.configurable, true, 'c is configurable');
assert.sameValue(result.c.writable, false, 'c is writable');
assert.sameValue(result.c.value, f.c, 'cs value is `f.c`');
assert.sameValue(
Object.keys(result).length,
2,
'result has same number of own property names as f'
);

View File

@ -0,0 +1,13 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should produce a normal object inheriting from Object.prototype
esid: pending
author: Jordan Harband
---*/
assert.sameValue(
Object.getPrototypeOf(Object.getOwnPropertyDescriptors({})),
Object.prototype
);

View File

@ -0,0 +1,34 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should perform observable operations in the correct order
esid: pending
author: Jordan Harband
features: [Proxy]
includes: [proxyTrapsHelper.js]
---*/
var log = "";
var object = { a: 0, b: 0, c: 0 };
var handler = {
getOwnPropertyDescriptor: function (target, propertyKey) {
assert.sameValue(target, object, "getOwnPropertyDescriptor");
log += "|getOwnPropertyDescriptor:" + propertyKey;
return Object.getOwnPropertyDescriptor(target, propertyKey);
},
ownKeys: function (target) {
assert.sameValue(target, object, "ownKeys");
log += "|ownKeys";
return Object.getOwnPropertyNames(target);
}
};
var check = {
get: function (target, propertyKey, receiver) {
assertEq(propertyKey in target, true, "handler check: " + propertyKey);
return target[propertyKey];
}
};
var proxy = new Proxy(object, new Proxy(handler, check));
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(log, "|ownKeys|getOwnPropertyDescriptor:a|getOwnPropertyDescriptor:b|getOwnPropertyDescriptor:c", 'log');

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts boolean primitives.
esid: pending
author: Jordan Harband
---*/
var trueResult = Object.getOwnPropertyDescriptors(true);
assert.sameValue(Object.keys(trueResult).length, 0, 'trueResult has 0 items');
var falseResult = Object.getOwnPropertyDescriptors(false);
assert.sameValue(Object.keys(falseResult).length, 0, 'falseResult has 0 items');

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts number primitives.
esid: pending
author: Jordan Harband
---*/
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(0)).length, 0, '0 has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(-0)).length, 0, '-0 has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(Infinity)).length, 0, 'Infinity has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(-Infinity)).length, 0, '-Infinity has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(NaN)).length, 0, 'NaN has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(Math.PI)).length, 0, 'Math.PI has zero descriptors');

View File

@ -0,0 +1,33 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts string primitives.
esid: pending
author: Jordan Harband
---*/
var result = Object.getOwnPropertyDescriptors('abc');
assert.sameValue(Object.keys(result).length, 4, 'string has 4 descriptors');
assert.sameValue(result.length.configurable, false, 'length is not configurable');
assert.sameValue(result.length.enumerable, false, 'length is not enumerable');
assert.sameValue(result.length.writable, false, 'length is not writable');
assert.sameValue(result.length.value, 3, 'length is 3');
assert.sameValue(result[0].configurable, false, 'index 0 is not configurable');
assert.sameValue(result[0].enumerable, true, 'index 0 is enumerable');
assert.sameValue(result[0].writable, false, 'index 0 is not writable');
assert.sameValue(result[0].value, 'a', 'index 0 is "a"');
assert.sameValue(result[1].configurable, false, 'index 1 is not configurable');
assert.sameValue(result[1].enumerable, true, 'index 1 is enumerable');
assert.sameValue(result[1].writable, false, 'index 1 is not writable');
assert.sameValue(result[1].value, 'b', 'index 1 is "b"');
assert.sameValue(result[2].configurable, false, 'index 2 is not configurable');
assert.sameValue(result[2].enumerable, true, 'index 2 is enumerable');
assert.sameValue(result[2].writable, false, 'index 2 is not writable');
assert.sameValue(result[2].value, 'c', 'index 2 is "c"');

View File

@ -0,0 +1,13 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts Symbol primitives.
esid: pending
author: Jordan Harband
features: [Symbol]
---*/
var result = Object.getOwnPropertyDescriptors(Symbol());
assert.sameValue(Object.keys(result).length, 0, 'symbol primitive has no descriptors');

View File

@ -0,0 +1,32 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should filter out undefined OwnPropertyDescriptors
esid: sec-object.getownpropertydescriptors
author: Jordan Harband
featurewws: [Proxy]
includes: [proxyTrapsHelper.js]
---*/
var key = "a";
var ownKeys = [key];
var badProxyHandlers = {
getOwnPropertyDescriptor: function () {},
ownKeys: function () {
return ownKeys;
}
};
var proxy = new Proxy({}, badProxyHandlers);
var keys = Reflect.ownKeys(proxy);
assert.notSameValue(keys, ownKeys, 'Object.keys returns a new Array');
assert.sameValue(Array.isArray(keys), true, 'Object.keys returns an Array');
assert.sameValue(keys.length, ownKeys.length, 'keys and ownKeys have the same length');
assert.sameValue(keys[0], ownKeys[0], 'keys and ownKeys have the same contents');
var descriptor = Object.getOwnPropertyDescriptor(proxy, key);
assert.sameValue(descriptor, undefined, "Descriptor matches result of [[GetOwnPropertyDescriptor]] trap");
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(key in result, false, "key is not present in result");

View File

@ -0,0 +1,27 @@
var assert = {
sameValue: assertEq,
notSameValue(a, b, msg) {
try {
assertEq(a, b);
throw "equal"
} catch (e) {
if (e === "equal")
throw new Error("Assertion failed: expected different values, got " + a);
}
},
throws(ctor, f) {
var fullmsg;
try {
f();
} catch (exc) {
if (exc instanceof ctor)
return;
fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
}
if (fullmsg === undefined)
fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
if (msg !== undefined)
fullmsg += " - " + msg;
throw new Error(fullmsg);
}
}

View File

@ -0,0 +1,38 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors includes Symbol keys.
esid: pending
author: Jordan Harband
features: [Symbol]
---*/
var value = {};
var enumSym = Symbol('enum');
var nonEnumSym = Symbol('nonenum');
var symValue = Symbol('value');
var obj = { key: symValue };
obj[enumSym] = value;
Object.defineProperty(obj, nonEnumSym, { writable: true, enumerable: false, configurable: true, value: value });
var result = Object.getOwnPropertyDescriptors(obj);
assert.sameValue(Object.keys(result).length, 1, 'obj has 1 string-keyed descriptor');
assert.sameValue(Object.getOwnPropertySymbols(result).length, 2, 'obj has 2 symbol-keyed descriptors');
assert.sameValue(result.key.configurable, true, 'result.key is configurable');
assert.sameValue(result.key.enumerable, true, 'result.key is enumerable');
assert.sameValue(result.key.writable, true, 'result.key is writable');
assert.sameValue(result.key.value, symValue, 'result.key has value symValue');
assert.sameValue(result[enumSym].configurable, true, 'result[enumSym] is configurable');
assert.sameValue(result[enumSym].enumerable, true, 'result[enumSym] is enumerable');
assert.sameValue(result[enumSym].writable, true, 'result[enumSym] is writable');
assert.sameValue(result[enumSym].value, value, 'result[enumSym] has value `value`');
assert.sameValue(result[nonEnumSym].configurable, true, 'result[nonEnumSym] is configurable');
assert.sameValue(result[nonEnumSym].enumerable, false, 'result[nonEnumSym] is not enumerable');
assert.sameValue(result[nonEnumSym].writable, true, 'result[nonEnumSym] is writable');
assert.sameValue(result[nonEnumSym].value, value, 'result[nonEnumSym] has value `value`');

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Object.getOwnPropertyDescriptors should not have its behavior impacted by modifications to the global property Object
esid: pending
author: Jordan Harband
---*/
function fakeObject() {
$ERROR('The overriden version of Object was called!');
}
fakeObject.getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
fakeObject.keys = Object.keys;
var global = this;
global.Object = fakeObject;
assert.sameValue(Object, fakeObject, 'Sanity check failed: could not modify the global Object');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors('a')).length, 2, 'Expected string primitive to have 2 descriptors');

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Object.getOwnPropertyDescriptors should not have its behavior impacted by modifications to Object.getOwnPropertyDescriptor
esid: pending
author: Jordan Harband
---*/
function fakeObjectGetOwnPropertyDescriptor() {
$ERROR('The overriden version of Object.getOwnPropertyDescriptor was called!');
}
Object.getOwnPropertyDescriptor = fakeObjectGetOwnPropertyDescriptor;
assert.sameValue(
Object.getOwnPropertyDescriptor,
fakeObjectGetOwnPropertyDescriptor,
'Sanity check failed: could not modify the global Object.getOwnPropertyDescriptor'
);
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors({ a: 1 })).length, 1, 'Expected object with 1 key to have 1 descriptor');

View File

View File

@ -285,15 +285,16 @@
macro(iterator, iterator, "iterator") \
macro(match, match, "match") \
macro(species, species, "species") \
macro(hasInstance, hasInstance, "hasInstance") \
macro(toPrimitive, toPrimitive, "toPrimitive") \
macro(toStringTag, toStringTag, "toStringTag") \
macro(unscopables, unscopables, "unscopables") \
/* Same goes for the descriptions of the well-known symbols. */ \
macro(Symbol_hasInstance, Symbol_hasInstance, "Symbol.hasInstance") \
macro(Symbol_isConcatSpreadable, Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") \
macro(Symbol_iterator, Symbol_iterator, "Symbol.iterator") \
macro(Symbol_match, Symbol_match, "Symbol.match") \
macro(Symbol_species, Symbol_species, "Symbol.species") \
macro(Symbol_hasInstance, Symbol_hasInstance, "Symbol.hasInstance") \
macro(Symbol_toPrimitive, Symbol_toPrimitive, "Symbol.toPrimitive") \
macro(Symbol_toStringTag, Symbol_toStringTag, "Symbol.toStringTag") \
macro(Symbol_unscopables, Symbol_unscopables, "Symbol.unscopables") \

View File

@ -685,6 +685,44 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
NullFramePtr() /* evalInFrame */, rval);
}
/*
* ES6 (4-25-16) 12.10.4 InstanceofOperator
*/
extern bool
js::InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
{
/* Step 1. is handled by caller. */
/* Step 2. */
RootedValue hasInstance(cx);
RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance));
if (!GetProperty(cx, obj, obj, id, &hasInstance))
return false;
if (!hasInstance.isNullOrUndefined()) {
if (!IsCallable(hasInstance))
ReportIsNotFunction(cx, hasInstance);
/* Step 3. */
RootedValue rval(cx);
RootedValue vv(cx, v);
if (!Call(cx, obj, hasInstance, HandleValueArray(vv), &rval))
return false;
*bp = ToBoolean(rval);
return true;
}
/* Step 4. */
if (!obj->isCallable()) {
RootedValue val(cx, ObjectValue(*obj));
ReportIsNotFunction(cx, val);
return false;
}
/* Step 5. */
return js::OrdinaryHasInstance(cx, obj, v, bp);
}
bool
js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
{
@ -693,10 +731,7 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
if (clasp->hasInstance)
return clasp->hasInstance(cx, obj, &local, bp);
RootedValue val(cx, ObjectValue(*obj));
ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
JSDVG_SEARCH_STACK, val, nullptr);
return false;
return js::InstanceOfOperator(cx, obj, &local, bp);
}
static inline bool

View File

@ -248,6 +248,9 @@ TypeOfObject(JSObject* obj);
extern JSType
TypeOfValue(const Value& v);
extern bool
InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp);
extern bool
HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);

View File

@ -456,6 +456,10 @@ struct WellKnownSymbols
const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
return get(size_t(code));
}
WellKnownSymbols() {}
WellKnownSymbols(const WellKnownSymbols&) = delete;
WellKnownSymbols& operator=(const WellKnownSymbols&) = delete;
};
#define NAME_OFFSET(name) offsetof(JSAtomState, name)

View File

@ -2008,8 +2008,8 @@ pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
// a NullPrincipal as the security context.
// Otherwise it will inherit the origin from parent node, this is the legacy
// behavior of Firefox.
// TenFourFox issue 525 -- hold until better chrome detection is working
pref("security.data_uri.unique_opaque_origin", false);
// See also TenFourFox issue 525 for a workaround for old-style addons.
pref("security.data_uri.unique_opaque_origin", true);
// Modifier key prefs: default to Windows settings,
// menu access key = alt, accelerator key = control.
@ -2236,7 +2236,11 @@ pref("layout.word_select.stop_at_punctuation", true);
pref("layout.selection.caret_style", 0);
// pref to report CSS errors to the error console
#if DEBUG
pref("layout.css.report_errors", true);
#else
pref("layout.css.report_errors", false);
#endif
// Should the :visited selector ever match (otherwise :link matches instead)?
pref("layout.css.visited_links_enabled", true);

View File

@ -975,6 +975,12 @@ Service::Observe(nsISupports *, const char *aTopic, const char16_t *)
getConnections(connections);
for (uint32_t i = 0, n = connections.Length(); i < n; i++) {
if (!connections[i]->isClosed()) {
// This seems to happen with uBlock origin ...
fprintf(stderr, "FATAL ERROR: Storage connections not closed! Bad add-on! %s:%i\n", __FILE__, __LINE__);
#if __ppc__
// Drop into the debugger.
__asm__("trap\n");
#endif
MOZ_CRASH();
}
}