mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-05-28 20:41:33 +00:00
commit
f32a975b75
|
@ -1 +1 @@
|
|||
45.19.0
|
||||
45.20.0
|
||||
|
|
|
@ -1 +1 @@
|
|||
Feature Parity Release 10
|
||||
Feature Parity Release 11
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
45.19.0
|
||||
45.20.0
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() ?
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2757,6 +2757,12 @@ imgCacheValidator::AddProxy(imgRequestProxy* aProxy)
|
|||
mProxies.AppendObject(aProxy);
|
||||
}
|
||||
|
||||
void
|
||||
imgCacheValidator::RemoveProxy(imgRequestProxy* aProxy)
|
||||
{
|
||||
mProxies.RemoveObject(aProxy);
|
||||
}
|
||||
|
||||
/** nsIRequestObserver methods **/
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -529,6 +529,7 @@ public:
|
|||
bool forcePrincipalCheckForCacheEntry);
|
||||
|
||||
void AddProxy(imgRequestProxy* aProxy);
|
||||
void RemoveProxy(imgRequestProxy* aProxy);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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));
|
||||
|
|
32
js/src/jit-test/tests/ion/fold-in.js
Normal file
32
js/src/jit-test/tests/ion/fold-in.js
Normal 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);
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -4560,6 +4560,7 @@ GetSymbolDescription(HandleSymbol symbol);
|
|||
macro(iterator) \
|
||||
macro(match) \
|
||||
macro(species) \
|
||||
macro(hasInstance) \
|
||||
macro(toPrimitive) \
|
||||
macro(toStringTag) \
|
||||
macro(unscopables)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
96
js/src/tests/ecma_6/Function/has-instance-jitted.js
Normal file
96
js/src/tests/ecma_6/Function/has-instance-jitted.js
Normal 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);
|
88
js/src/tests/ecma_6/Function/has-instance.js
Normal file
88
js/src/tests/ecma_6/Function/has-instance.js
Normal 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);
|
|
@ -5,6 +5,10 @@ var names = [
|
|||
"iterator",
|
||||
"match",
|
||||
"species",
|
||||
"hasInstance",
|
||||
"toPrimitive",
|
||||
"toStringTag",
|
||||
"unscopables"
|
||||
];
|
||||
|
||||
for (var name of names) {
|
||||
|
|
|
@ -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|');
|
|
@ -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);
|
||||
});
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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, 'b’s 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, 'c’s value is `f.c`');
|
||||
|
||||
assert.sameValue(
|
||||
Object.keys(result).length,
|
||||
2,
|
||||
'result has same number of own property names as f'
|
||||
);
|
|
@ -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
|
||||
);
|
|
@ -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');
|
|
@ -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');
|
|
@ -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');
|
|
@ -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"');
|
||||
|
|
@ -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');
|
|
@ -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");
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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`');
|
|
@ -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');
|
|
@ -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');
|
0
js/src/tests/test262/built-ins/Object/shell.js
Normal file
0
js/src/tests/test262/built-ins/Object/shell.js
Normal file
0
js/src/tests/test262/built-ins/shell.js
Normal file
0
js/src/tests/test262/built-ins/shell.js
Normal 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") \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user