import change from rmottola/Arctic-Fox:

- Bug 1130439 - Trigger compacting GCs after the user becomes inactive (aa5936222)
- Bug 1139429 - Fix ICU configuration for SunOS/OpenSolaris. (a0e4467b4)
- Bug 1143521 - Remove IsPoisonedPtr stuff (341899b88)
- Bug 1142351 - Part 1: Collect telemetry about deprecated flag argument for String.prototype.{search,match,replace}. (3ad712689) (partly)
- Bug 1142351 - Part 2: Warn about deprecated flag argument for String.prototype (66c280d79)
- Bug 1083498 - Remove SpiderMonkey's nonstandard behavior for destructuring for..in loops in JS1.7. (428b6a0d1)
This commit is contained in:
2019-05-17 23:28:53 +08:00
parent 32174fa57b
commit 4a37a0ce80
40 changed files with 177 additions and 255 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ if test -n "$USE_ICU"; then
MOZ_ICU_DBG_SUFFIX=d
fi
;;
Darwin|Linux|DragonFly|FreeBSD|NetBSD|OpenBSD|GNU/kFreeBSD)
Darwin|Linux|DragonFly|FreeBSD|NetBSD|OpenBSD|GNU/kFreeBSD|SunOS)
ICU_LIB_NAMES="icui18n icuuc icudata"
;;
*)
+76 -16
View File
@@ -107,6 +107,10 @@ const size_t gStackSize = 8192;
#define NS_FULL_GC_DELAY 60000 // ms
// The amount of time to wait from the user being idle to starting a shrinking
// GC.
#define NS_SHRINKING_GC_DELAY 15000 // ms
// Maximum amount of time that should elapse between incremental GC slices
#define NS_INTERSLICE_GC_DELAY 100 // ms
@@ -148,6 +152,7 @@ static const uint32_t kMaxICCDuration = 2000; // ms
static nsITimer *sGCTimer;
static nsITimer *sShrinkGCBuffersTimer;
static nsITimer *sShrinkingGCTimer;
static nsITimer *sCCTimer;
static nsITimer *sICCTimer;
static nsITimer *sFullGCTimer;
@@ -212,6 +217,7 @@ static nsIScriptSecurityManager *sSecurityManager;
// the appropriate pref is set.
static bool sGCOnMemoryPressure;
static bool sCompactOnUserInactive;
// In testing, we call RunNextCollectorTimer() to ensure that the collectors are run more
// aggressively than they would be in regular browsing. sExpensiveCollectorPokes keeps
@@ -234,6 +240,7 @@ static void
KillTimers()
{
nsJSContext::KillGCTimer();
nsJSContext::KillShrinkingGCTimer();
nsJSContext::KillShrinkGCBuffersTimer();
nsJSContext::KillCCTimer();
nsJSContext::KillICCTimer();
@@ -266,22 +273,30 @@ NS_IMETHODIMP
nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
if (sGCOnMemoryPressure && !nsCRT::strcmp(aTopic, "memory-pressure")) {
if(StringBeginsWith(nsDependentString(aData),
NS_LITERAL_STRING("low-memory-ongoing"))) {
// Don't GC/CC if we are in an ongoing low-memory state since its very
// slow and it likely won't help us anyway.
return NS_OK;
}
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::ShrinkingGC);
nsJSContext::CycleCollectNow();
if (NeedsGCAfterCC()) {
if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
if (sGCOnMemoryPressure) {
if(StringBeginsWith(nsDependentString(aData),
NS_LITERAL_STRING("low-memory-ongoing"))) {
// Don't GC/CC if we are in an ongoing low-memory state since its very
// slow and it likely won't help us anyway.
return NS_OK;
}
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::ShrinkingGC);
nsJSContext::CycleCollectNow();
if (NeedsGCAfterCC()) {
nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::ShrinkingGC);
}
}
} else if (!nsCRT::strcmp(aTopic, "user-interaction-inactive")) {
if (sCompactOnUserInactive) {
nsJSContext::PokeShrinkingGC();
}
} else if (!nsCRT::strcmp(aTopic, "user-interaction-active")) {
nsJSContext::KillShrinkingGCTimer();
} else if (!nsCRT::strcmp(aTopic, "quit-application") ||
!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
sShuttingDown = true;
@@ -1284,12 +1299,11 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
return;
}
JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
JS::PrepareForFullGC(sRuntime);
if (aIncremental == IncrementalGC) {
MOZ_ASSERT(aShrinking == NonShrinkingGC);
JS::StartIncrementalGC(sRuntime, GC_NORMAL, aReason, aSliceMillis);
JS::StartIncrementalGC(sRuntime, gckind, aReason, aSliceMillis);
} else {
JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
JS::GCForReason(sRuntime, gckind, aReason);
}
}
@@ -1798,6 +1812,16 @@ ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
nsJSContext::ShrinkGCBuffersNow();
}
// static
void
ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure)
{
nsJSContext::KillShrinkingGCTimer();
nsJSContext::GarbageCollectNow(JS::gcreason::USER_INACTIVE,
nsJSContext::IncrementalGC,
nsJSContext::ShrinkingGC);
}
static bool
ShouldTriggerCC(uint32_t aSuspected)
{
@@ -2030,6 +2054,26 @@ nsJSContext::PokeShrinkGCBuffers()
nsITimer::TYPE_ONE_SHOT);
}
// static
void
nsJSContext::PokeShrinkingGC()
{
if (sShrinkingGCTimer || sShuttingDown) {
return;
}
CallCreateInstance("@mozilla.org/timer;1", &sShrinkingGCTimer);
if (!sShrinkingGCTimer) {
// Failed to create timer (probably because we're in XPCOM shutdown)
return;
}
sShrinkingGCTimer->InitWithFuncCallback(ShrinkingGCTimerFired, nullptr,
NS_SHRINKING_GC_DELAY,
nsITimer::TYPE_ONE_SHOT);
}
// static
void
nsJSContext::MaybePokeCC()
@@ -2091,6 +2135,16 @@ nsJSContext::KillShrinkGCBuffersTimer()
}
}
//static
void
nsJSContext::KillShrinkingGCTimer()
{
if (sShrinkingGCTimer) {
sShrinkingGCTimer->Cancel();
NS_RELEASE(sShrinkingGCTimer);
}
}
//static
void
nsJSContext::KillCCTimer()
@@ -2282,7 +2336,7 @@ void
mozilla::dom::StartupJSEnvironment()
{
// initialize all our statics, so that we can restart XPCOM
sGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr;
sGCTimer = sShrinkingGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr;
sCCLockedOut = false;
sCCLockedOutTime = 0;
sLastCCEndTime = TimeStamp();
@@ -2692,8 +2746,14 @@ nsJSContext::EnsureStatics()
"javascript.options.gc_on_memory_pressure",
true);
Preferences::AddBoolVarCache(&sCompactOnUserInactive,
"javascript.options.compact_on_user_inactive",
true);
nsIObserver* observer = new nsJSEnvironmentObserver();
obs->AddObserver(observer, "memory-pressure", false);
obs->AddObserver(observer, "user-interaction-inactive", false);
obs->AddObserver(observer, "user-interaction-active", false);
obs->AddObserver(observer, "quit-application", false);
obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+3
View File
@@ -116,6 +116,9 @@ public:
static void PokeShrinkGCBuffers();
static void KillShrinkGCBuffersTimer();
static void PokeShrinkingGC();
static void KillShrinkingGCTimer();
static void MaybePokeCC();
static void KillCCTimer();
static void KillICCTimer();
-5
View File
@@ -91,11 +91,6 @@ struct GCMethods<nsXBLMaybeCompiled<UncompiledT> >
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
}
static bool needsPostBarrier(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::needsPostBarrier(function.GetJSFunction());
+2 -1
View File
@@ -99,7 +99,8 @@ namespace JS {
D(REFRESH_FRAME) \
D(FULL_GC_TIMER) \
D(SHUTDOWN_CC) \
D(FINISH_LARGE_EVALUATE)
D(FINISH_LARGE_EVALUATE) \
D(USER_INACTIVE)
namespace gcreason {
-3
View File
@@ -546,7 +546,6 @@ struct PointerHasher
{
typedef Key Lookup;
static HashNumber hash(const Lookup& l) {
MOZ_ASSERT(!JS::IsPoisonedPtr(l));
size_t word = reinterpret_cast<size_t>(l) >> zeroBits;
static_assert(sizeof(HashNumber) == 4,
"subsequent code assumes a four-byte hash");
@@ -560,8 +559,6 @@ struct PointerHasher
#endif
}
static bool match(const Key& k, const Lookup& l) {
MOZ_ASSERT(!JS::IsPoisonedPtr(k));
MOZ_ASSERT(!JS::IsPoisonedPtr(l));
return k == l;
}
static void rekey(Key& k, const Key& newKey) {
-12
View File
@@ -126,7 +126,6 @@ SYMBOL_TO_JSID(JS::Symbol* sym)
MOZ_ASSERT(sym != nullptr);
MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0);
MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(sym)));
MOZ_ASSERT(!JS::IsPoisonedPtr(sym));
JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL);
return id;
}
@@ -169,20 +168,9 @@ extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE;
namespace js {
inline bool
IsPoisonedId(jsid id)
{
if (JSID_IS_STRING(id))
return JS::IsPoisonedPtr(JSID_TO_STRING(id));
if (JSID_IS_SYMBOL(id))
return JS::IsPoisonedPtr(JSID_TO_SYMBOL(id));
return false;
}
template <> struct GCMethods<jsid>
{
static jsid initial() { return JSID_VOID; }
static bool poisoned(jsid id) { return IsPoisonedId(id); }
static bool needsPostBarrier(jsid id) { return false; }
static void postBarrier(jsid* idp) {}
static void relocate(jsid* idp) {}
-13
View File
@@ -282,14 +282,12 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
private:
void init(T newPtr) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
ptr = newPtr;
if (js::GCMethods<T>::needsPostBarrier(ptr))
post();
}
void set(T newPtr) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
if (js::GCMethods<T>::needsPostBarrier(newPtr)) {
ptr = newPtr;
post();
@@ -362,7 +360,6 @@ class TenuredHeap : public js::HeapBase<T>
void setPtr(T newPtr) {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
if (newPtr)
AssertGCThingMustBeTenured(newPtr);
bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr);
@@ -526,7 +523,6 @@ class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
public:
void set(T v) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(v));
*ptr = v;
}
@@ -642,7 +638,6 @@ template <typename T>
struct GCMethods<T*>
{
static T* initial() { return nullptr; }
static bool poisoned(T* v) { return JS::IsPoisonedPtr(v); }
static bool needsPostBarrier(T* v) { return false; }
static void postBarrier(T** vp) {}
static void relocate(T** vp) {}
@@ -652,7 +647,6 @@ template <>
struct GCMethods<JSObject*>
{
static JSObject* initial() { return nullptr; }
static bool poisoned(JSObject* v) { return JS::IsPoisonedPtr(v); }
static gc::Cell* asGCThingOrNull(JSObject* v) {
if (!v)
return nullptr;
@@ -674,7 +668,6 @@ template <>
struct GCMethods<JSFunction*>
{
static JSFunction* initial() { return nullptr; }
static bool poisoned(JSFunction* v) { return JS::IsPoisonedPtr(v); }
static bool needsPostBarrier(JSFunction* v) {
return v != nullptr && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(v));
}
@@ -708,8 +701,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
this->stack = &cx->thingGCRooters[kind];
this->prev = *stack;
*stack = reinterpret_cast<Rooted<void*>*>(this);
MOZ_ASSERT(!js::GCMethods<T>::poisoned(ptr));
}
public:
@@ -789,7 +780,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
* interchangeably with a MutableHandleValue.
*/
void set(T value) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
ptr = value;
}
@@ -889,7 +879,6 @@ class FakeRooted : public RootedBase<T>
T ptr;
void set(const T& value) {
MOZ_ASSERT(!GCMethods<T>::poisoned(value));
ptr = value;
}
@@ -912,7 +901,6 @@ class FakeMutableHandle : public js::MutableHandleBase<T>
}
void set(T v) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(v));
*ptr = v;
}
@@ -1169,7 +1157,6 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
private:
void set(T value) {
MOZ_ASSERT(initialized());
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
ptr = value;
}
-34
View File
@@ -415,40 +415,6 @@ ScrambleHashCode(HashNumber h)
} /* namespace js */
namespace JS {
/*
* Methods for poisoning GC heap pointer words and checking for poisoned words.
* These are in this file for use in Value methods and so forth.
*
* If the moving GC hazard analysis is in use and detects a non-rooted stack
* pointer to a GC thing, one byte of that pointer is poisoned to refer to an
* invalid location. For both 32 bit and 64 bit systems, the fourth byte of the
* pointer is overwritten, to reduce the likelihood of accidentally changing
* a live integer value.
*/
inline void PoisonPtr(void* v)
{
#if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
uint8_t* ptr = (uint8_t*) v + 3;
*ptr = JS_FREE_PATTERN;
#endif
}
template <typename T>
inline bool IsPoisonedPtr(T* v)
{
#if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
uint32_t mask = uintptr_t(v) & 0xff000000;
return mask == uint32_t(JS_FREE_PATTERN << 24);
#else
return false;
#endif
}
}
/* sixgill annotation defines */
#ifndef HAVE_STATIC_ANNOTATIONS
# define HAVE_STATIC_ANNOTATIONS
-15
View File
@@ -1043,17 +1043,14 @@ class Value
}
void setString(JSString* str) {
MOZ_ASSERT(!IsPoisonedPtr(str));
data = STRING_TO_JSVAL_IMPL(str);
}
void setSymbol(JS::Symbol* sym) {
MOZ_ASSERT(!IsPoisonedPtr(sym));
data = SYMBOL_TO_JSVAL_IMPL(sym);
}
void setObject(JSObject& obj) {
MOZ_ASSERT(!IsPoisonedPtr(&obj));
data = OBJECT_TO_JSVAL_IMPL(&obj);
}
@@ -1641,17 +1638,11 @@ namespace js {
template <> struct GCMethods<const JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
static bool poisoned(const JS::Value& v) {
return v.isMarkable() && JS::IsPoisonedPtr(v.toGCThing());
}
};
template <> struct GCMethods<JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
static bool poisoned(const JS::Value& v) {
return v.isMarkable() && JS::IsPoisonedPtr(v.toGCThing());
}
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
return v.isMarkable() ? v.toGCThing() : nullptr;
}
@@ -1890,12 +1881,6 @@ IMPL_TO_JSVAL(jsval_layout l)
namespace JS {
inline bool
IsPoisonedValue(const Value& v)
{
return js::GCMethods<Value>::poisoned(v);
}
#ifdef JS_DEBUG
namespace detail {
-3
View File
@@ -56,7 +56,6 @@ using JS::BooleanValue;
using JS::DoubleValue;
using JS::Float32Value;
using JS::Int32Value;
using JS::IsPoisonedValue;
using JS::MagicValue;
using JS::NullValue;
using JS::NumberValue;
@@ -67,8 +66,6 @@ using JS::PrivateValue;
using JS::StringValue;
using JS::UndefinedValue;
using JS::IsPoisonedPtr;
using JS::Latin1Char;
using JS::Latin1Chars;
using JS::Latin1CharsZ;
+12 -71
View File
@@ -56,7 +56,6 @@ typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
typedef Rooted<NestedScopeObject*> RootedNestedScopeObject;
typedef Handle<NestedScopeObject*> HandleNestedScopeObject;
/* Read a token. Report an error and return null() if that token isn't of type tt. */
#define MUST_MATCH_TOKEN(tt, errno) \
JS_BEGIN_MACRO \
@@ -568,7 +567,7 @@ template <typename ParseHandler>
ObjectBox*
Parser<ParseHandler>::newObjectBox(NativeObject* obj)
{
MOZ_ASSERT(obj && !IsPoisonedPtr(obj));
MOZ_ASSERT(obj);
/*
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
@@ -646,7 +645,7 @@ FunctionBox*
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, ParseContext<ParseHandler>* outerpc,
Directives inheritedDirectives, GeneratorKind generatorKind)
{
MOZ_ASSERT(fun && !IsPoisonedPtr(fun));
MOZ_ASSERT(fun);
/*
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
@@ -4378,40 +4377,16 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode* pn1, JSVersion versi
bool isForDecl, bool isForEach,
ParseNodeKind headKind)
{
if (isForDecl) {
if (pn1->pn_count > 1)
return false;
if (pn1->isKind(PNK_CONST))
return false;
// In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
// Hence all other destructuring decls are banned there.
if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN) {
ParseNode* lhs = pn1->pn_head;
if (lhs->isKind(PNK_ASSIGN))
lhs = lhs->pn_left;
if (lhs->isKind(PNK_OBJECT))
return false;
if (lhs->isKind(PNK_ARRAY) && lhs->pn_count != 2)
return false;
}
return true;
}
if (isForDecl)
return pn1->pn_count < 2 && !pn1->isKind(PNK_CONST);
switch (pn1->getKind()) {
case PNK_NAME:
case PNK_DOT:
case PNK_CALL:
case PNK_ELEM:
return true;
case PNK_ARRAY:
case PNK_CALL:
case PNK_DOT:
case PNK_ELEM:
case PNK_NAME:
case PNK_OBJECT:
// In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
// Hence all other destructuring left-hand sides are banned there.
if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN)
return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
return true;
default:
@@ -4703,29 +4678,12 @@ Parser<FullParseHandler>::forStatement()
return null();
}
switch (pn2->getKind()) {
case PNK_NAME:
ParseNodeKind kind2 = pn2->getKind();
MOZ_ASSERT(kind2 != PNK_ASSIGN, "forStatement TOK_ASSIGN");
if (kind2 == PNK_NAME) {
/* Beware 'for (arguments in ...)' with or without a 'var'. */
pn2->markAsAssigned();
break;
case PNK_ASSIGN:
MOZ_CRASH("forStatement TOK_ASSIGN");
case PNK_ARRAY:
case PNK_OBJECT:
if (versionNumber() == JSVERSION_1_7) {
/*
* Destructuring for-in requires [key, value] enumeration
* in JS1.7.
*/
if (!isForEach && headKind == PNK_FORIN) {
iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
}
}
break;
default:;
}
} else {
if (isForEach) {
@@ -5840,7 +5798,6 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
return null();
return classStatement();
/* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
case TOK_CATCH:
report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
@@ -6877,22 +6834,6 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
case TOK_LC:
if (!checkDestructuring(&data, pn3))
return null();
if (versionNumber() == JSVERSION_1_7 &&
!(pn2->pn_iflags & JSITER_FOREACH) &&
!isForOf)
{
/* Destructuring requires [key, value] enumeration in JS1.7. */
if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
report(ParseError, false, null(), JSMSG_BAD_FOR_LEFTSIDE);
return null();
}
MOZ_ASSERT(pn2->isOp(JSOP_ITER));
MOZ_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
MOZ_ASSERT(headKind == PNK_FORIN);
pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
}
break;
case TOK_NAME:
-2
View File
@@ -115,7 +115,6 @@ struct Token
void setName(PropertyName* name) {
MOZ_ASSERT(type == TOK_NAME);
MOZ_ASSERT(!IsPoisonedPtr(name));
u.name = name;
}
@@ -123,7 +122,6 @@ struct Token
MOZ_ASSERT(type == TOK_STRING ||
type == TOK_TEMPLATE_HEAD ||
type == TOK_NO_SUBS_TEMPLATE);
MOZ_ASSERT(!IsPoisonedPtr(atom));
u.atom = atom;
}
-9
View File
@@ -443,7 +443,6 @@ class MOZ_NON_MEMMOVABLE BarrieredBase : public BarrieredBaseMixins<T>
public:
void init(T v) {
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
}
@@ -508,7 +507,6 @@ class PreBarriered : public BarrieredBase<T>
private:
void set(const T& v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
}
};
@@ -541,7 +539,6 @@ class HeapPtr : public BarrieredBase<T>
#endif
void init(T v) {
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
post();
}
@@ -554,7 +551,6 @@ class HeapPtr : public BarrieredBase<T>
private:
void set(const T& v) {
this->pre();
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
this->value = v;
post();
}
@@ -652,7 +648,6 @@ class RelocatablePtr : public BarrieredBase<T>
}
void postBarrieredSet(const T& v) {
MOZ_ASSERT(!GCMethods<T>::poisoned(v));
if (GCMethods<T>::needsPostBarrier(v)) {
this->value = v;
post();
@@ -858,14 +853,12 @@ class HeapSlot : public BarrieredBase<Value>
explicit HeapSlot(NativeObject* obj, Kind kind, uint32_t slot, const Value& v)
: BarrieredBase<Value>(v)
{
MOZ_ASSERT(!IsPoisonedValue(v));
post(obj, kind, slot, v);
}
explicit HeapSlot(NativeObject* obj, Kind kind, uint32_t slot, const HeapSlot& s)
: BarrieredBase<Value>(s.value)
{
MOZ_ASSERT(!IsPoisonedValue(s.value));
post(obj, kind, slot, s);
}
@@ -886,7 +879,6 @@ class HeapSlot : public BarrieredBase<Value>
void set(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
MOZ_ASSERT(preconditionForSet(owner, kind, slot));
MOZ_ASSERT(!IsPoisonedValue(v));
pre();
value = v;
post(owner, kind, slot, v);
@@ -894,7 +886,6 @@ class HeapSlot : public BarrieredBase<Value>
void set(Zone* zone, NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
MOZ_ASSERT(preconditionForSet(zone, owner, kind, slot));
MOZ_ASSERT(!IsPoisonedValue(v));
pre(zone);
value = v;
post(owner, kind, slot, v);
-6
View File
@@ -226,8 +226,6 @@ class ImmMaybeNurseryPtr
public:
explicit ImmMaybeNurseryPtr(const gc::Cell* ptr) : value(ptr)
{
MOZ_ASSERT(!IsPoisonedPtr(ptr));
// asm.js shouldn't be creating GC things
MOZ_ASSERT(!IsCompilingAsmJS());
}
@@ -257,7 +255,6 @@ class ImmGCPtr
explicit ImmGCPtr(const gc::Cell* ptr) : value(ptr)
{
MOZ_ASSERT(!IsPoisonedPtr(ptr));
MOZ_ASSERT_IF(ptr, ptr->isTenured());
// asm.js shouldn't be creating GC things
@@ -266,7 +263,6 @@ class ImmGCPtr
explicit ImmGCPtr(IonNurseryPtr ptr) : value(ptr.ptr)
{
MOZ_ASSERT(!IsPoisonedPtr(value));
MOZ_ASSERT(value);
// asm.js shouldn't be creating GC things
@@ -279,8 +275,6 @@ class ImmGCPtr
friend class AssemblerShared;
explicit ImmGCPtr(ImmMaybeNurseryPtr ptr) : value(ptr.value)
{
MOZ_ASSERT(!IsPoisonedPtr(ptr.value));
// asm.js shouldn't be creating GC things
MOZ_ASSERT(!IsCompilingAsmJS());
}
+1
View File
@@ -231,6 +231,7 @@ MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 0, JSEXN_SYNTAXERR, "missing } in compoun
MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_DEPRECATED_FLAGS_ARG, 0, JSEXN_NONE, "flags argument of String.prototype.{search,match,replace} is deprecated")
MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_NONE, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead")
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
-6
View File
@@ -2670,12 +2670,6 @@ namespace js {
template <>
struct GCMethods<JSPropertyDescriptor> {
static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
static bool poisoned(const JSPropertyDescriptor& desc) {
return (desc.obj && JS::IsPoisonedPtr(desc.obj)) ||
(desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) ||
(desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) ||
(desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing()));
}
};
template <>
-1
View File
@@ -383,7 +383,6 @@ ExclusiveContext::typeLifoAlloc()
inline void
JSContext::setPendingException(js::Value v)
{
MOZ_ASSERT(!IsPoisonedValue(v));
// overRecursed_ is set after the fact by ReportOverRecursed.
this->overRecursed_ = false;
this->throwing = true;
+1 -3
View File
@@ -46,6 +46,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
isSelfHosting(false),
marked(true),
warnedAboutNoSuchMethod(false),
warnedAboutFlagsArgument(false),
addonId(options.addonIdOrNull()),
#ifdef DEBUG
firedOnNewGlobalObject(false),
@@ -241,9 +242,6 @@ bool
JSCompartment::putWrapper(JSContext* cx, const CrossCompartmentKey& wrapped, const js::Value& wrapper)
{
MOZ_ASSERT(wrapped.wrapped);
MOZ_ASSERT(!IsPoisonedPtr(wrapped.wrapped));
MOZ_ASSERT(!IsPoisonedPtr(wrapped.debugger));
MOZ_ASSERT(!IsPoisonedPtr(wrapper.toGCThing()));
MOZ_ASSERT_IF(wrapped.kind == CrossCompartmentKey::StringWrapper, wrapper.isString());
MOZ_ASSERT_IF(wrapped.kind != CrossCompartmentKey::StringWrapper, wrapper.isObject());
bool success = crossCompartmentWrappers.put(wrapped, ReadBarriered<Value>(wrapper));
+3 -2
View File
@@ -110,7 +110,6 @@ struct CrossCompartmentKey
struct WrapperHasher : public DefaultHasher<CrossCompartmentKey>
{
static HashNumber hash(const CrossCompartmentKey& key) {
MOZ_ASSERT(!IsPoisonedPtr(key.wrapped));
static_assert(sizeof(HashNumber) == sizeof(uint32_t),
"subsequent code assumes a four-byte hash");
return uint32_t(uintptr_t(key.wrapped)) | uint32_t(key.kind);
@@ -150,6 +149,7 @@ struct JSCompartment
bool isSelfHosting;
bool marked;
bool warnedAboutNoSuchMethod;
bool warnedAboutFlagsArgument;
// A null add-on ID means that the compartment is not associated with an
// add-on.
@@ -542,12 +542,13 @@ struct JSCompartment
enum DeprecatedLanguageExtension {
DeprecatedForEach = 0, // JS 1.6+
DeprecatedDestructuringForIn = 1, // JS 1.7 only
// NO LONGER USING 1
DeprecatedLegacyGenerator = 2, // JS 1.7+
DeprecatedExpressionClosure = 3, // Added in JS 1.8
DeprecatedLetBlock = 4, // Added in JS 1.7
// No longer using 5 (was: let expressions)
DeprecatedNoSuchMethod = 6, // JS 1.7+
DeprecatedFlagsArgument = 7, // JS 1.3 or older
DeprecatedLanguageExtensionCount
};
};
+3 -1
View File
@@ -363,7 +363,9 @@ js::AssertSameCompartment(JSObject* objA, JSObject* objB)
JS_FRIEND_API(void)
js::NotifyAnimationActivity(JSObject* obj)
{
obj->compartment()->lastAnimationTime = PRMJ_Now();
int64_t timeNow = PRMJ_Now();
obj->compartment()->lastAnimationTime = timeNow;
obj->runtimeFromMainThread()->lastAnimationTime = timeNow;
}
JS_FRIEND_API(uint32_t)
+4 -1
View File
@@ -1893,7 +1893,10 @@ ArenaLists::allocateFromArenaInner(JS::Zone* zone, ArenaHeader* aheader, AllocKi
bool
GCRuntime::shouldCompact()
{
return invocationKind == GC_SHRINK && isCompactingGCEnabled();
// Compact on shrinking GC if enabled, but skip compacting in incremental
// GCs if we are currently animating.
return invocationKind == GC_SHRINK && isCompactingGCEnabled() &&
(!isIncremental || rt->lastAnimationTime + PRMJ_USEC_PER_SEC < PRMJ_Now());
}
void
-3
View File
@@ -323,9 +323,6 @@ class Bindings
template <>
struct GCMethods<Bindings> {
static Bindings initial();
static bool poisoned(const Bindings& bindings) {
return IsPoisonedPtr(bindings.callObjShape());
}
};
class ScriptCounts
+7
View File
@@ -2139,6 +2139,13 @@ class MOZ_STACK_CLASS StringRegExpGuard
/* Build RegExp from pattern string. */
RootedString opt(cx);
if (optarg < args.length()) {
if (!cx->compartment()->warnedAboutFlagsArgument) {
if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
JSMSG_DEPRECATED_FLAGS_ARG))
return false;
cx->compartment()->warnedAboutFlagsArgument = true;
}
opt = ToString<CanGC>(cx, args[optarg]);
if (!opt)
return false;
@@ -0,0 +1,15 @@
// |reftest| skip-if(!xulRuntime.shell)
var BUGNUMBER = 1142351;
var summary = 'Add console warnings for non-standard flag argument of String.prototype.{search,match,replace}.';
printBugNumber(BUGNUMBER);
printStatus (summary);
options("werror");
assertEq(evaluate("'aaaA'.match('a', 'i')", {catchTermination: true}), "terminated");
assertEq(evaluate("'aaaA'.search('a', 'i')", {catchTermination: true}), "terminated");
assertEq(evaluate("'aaaA'.replace('a', 'b', 'g')", {catchTermination: true}), "terminated");
if (typeof reportCompare === "function")
reportCompare(true, true);
@@ -24,19 +24,23 @@ function f() {
}
function g() {
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected values were a == "x" and b == 7.
for (var [a,b] in {x:7}) {
if (a != "x" || b != 7)
if (a !== "x" || typeof b !== "undefined")
throw "fail";
}
{
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected values were a == "y" and b == 8.
for (let [a,b] in {y:8}) {
if (a != "y" || b != 8)
if (a !== "y" || typeof b !== "undefined")
throw "fail";
}
}
if (a != "x" || b != 7)
if (a !== "x" || typeof b !== "undefined")
throw "fail";
}
@@ -47,17 +51,17 @@ if (typeof a != "undefined" || typeof b != "undefined" || typeof x != "undefined
throw "fail";
function h() {
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected values were a == "x" and b == 9.
for ([a,b] in {z:9}) {
if (a != "z" || b != 9)
if (a !== "z" || typeof b !== "undefined")
throw "fail";
}
}
h();
if (a != "z" || b != 9)
if (a !== "z" || typeof b !== "undefined")
throw "fail";
reportCompare(expect, actual, summary);
+8 -2
View File
@@ -34,13 +34,19 @@ function test()
actual = arr.toString();
reportCompare(expect, actual, summary);
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected result was 'aa,bb,cc'.
arr=[x+x for ([,x] in ["a","b","c"])];
expect = 'aa,bb,cc';
expect = 'NaN,NaN,NaN';
actual = arr.toString();
reportCompare(expect, actual, summary);
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected result was '0a,1b,2c'.
arr=[x+y for ([x,y] in ["a","b","c"])];
expect = '0a,1b,2c';
expect = '0undefined,1undefined,2undefined';
actual = arr.toString();
reportCompare(expect, actual, summary);
exitFunc ('test');
}
+14 -8
View File
@@ -19,15 +19,21 @@ function test()
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
expect = '23';
actual = '';
for (let [, { a: b }] in [{ a: 2 }, { a: 3 }])
{
actual += b;
}
reportCompare(expect, actual, summary);
// Before JS1.7's destructuring for…in was fixed to match JS1.8's,
// the expected result was '23'.
expect = 'TypeError';
actual = '';
try {
for (let [, { a: b }] in [{ a: 2 }, { a: 3 }]) {
actual += b;
}
reportCompare(expect, actual, summary);
} catch (ex) {
actual = ex.name;
}
expect = '23';
actual = '';
for each (let { a: b } in [{ a: 2 }, { a: 3 }])
{
+6 -6
View File
@@ -60,24 +60,24 @@ function test()
reportCompare(expect, actual, summary + ': 3');
// syntax error in js17
// Before JS1.7's destructuring forin was fixed to match JS1.8's,
// the expected result was a SyntaxError about the for…in loop's lhs.
var iter2 = gen(list2);
expect = /SyntaxError: (invalid for.in left-hand side|Left hand side of for..in loop must be an array of length 2 to accept key.value pair.)/;
expect = '1,2,3;4,5,6;7,8,9;';
actual = '';
try
{
eval('for (var [foo, bar, baz] in iter2) {' +
'actual += foo + "," + bar + "," + baz + ";";' +
'actual += foo + "," + bar + "," + baz + ";";' +
'}');
actual = 'No Error';
}
catch(ex)
{
actual = ex + '';
}
reportMatch(expect, actual, summary + ': 4');
reportCompare(expect, actual, summary + ': 4');
exitFunc ('test');
}
-2
View File
@@ -6122,8 +6122,6 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
MOZ_ASSERT_IF(frame, thisv.get() == frame.thisValue());
MOZ_ASSERT_IF(frame, pc);
MOZ_ASSERT(!IsPoisonedPtr(chars.start().get()));
/*
* NB: This function breaks the assumption that the compiler can see all
* calls and properly compute a static level. In practice, any non-zero
-2
View File
@@ -71,13 +71,11 @@ struct RootKind<TaggedProto>
template <> struct GCMethods<const TaggedProto>
{
static TaggedProto initial() { return TaggedProto(); }
static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
};
template <> struct GCMethods<TaggedProto>
{
static TaggedProto initial() { return TaggedProto(); }
static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
};
template<class Outer>
+2 -1
View File
@@ -214,7 +214,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
#endif
largeAllocationFailureCallback(nullptr),
oomCallback(nullptr),
debuggerMallocSizeOf(ReturnZeroSize)
debuggerMallocSizeOf(ReturnZeroSize),
lastAnimationTime(0)
{
setGCStoreBufferPtr(&gc.storeBuffer);
+3
View File
@@ -1435,6 +1435,9 @@ struct JSRuntime : public JS::shadow::Runtime,
* function to assess the size of malloc'd blocks of memory.
*/
mozilla::MallocSizeOf debuggerMallocSizeOf;
/* Last time at which an animation was played for this runtime. */
int64_t lastAnimationTime;
};
namespace js {
+1 -4
View File
@@ -162,10 +162,7 @@ AutoRooterGetterSetter::Inner::Inner(ExclusiveContext *cx, uint8_t attrs,
GetterOp *pgetter_, SetterOp *psetter_)
: CustomAutoRooter(cx), attrs(attrs),
pgetter(pgetter_), psetter(psetter_)
{
MOZ_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter));
MOZ_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter));
}
{}
inline
AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext *cx, uint8_t attrs,
-3
View File
@@ -1289,9 +1289,6 @@ struct StackShape
{}
void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) {
MOZ_ASSERT_IF((attrs & JSPROP_GETTER) && rawGetter, !IsPoisonedPtr(rawGetter));
MOZ_ASSERT_IF((attrs & JSPROP_SETTER) && rawSetter, !IsPoisonedPtr(rawSetter));
if (rawGetter || rawSetter || (attrs & (JSPROP_GETTER|JSPROP_SETTER)))
flags |= Shape::ACCESSOR_SHAPE;
else
-1
View File
@@ -136,7 +136,6 @@ MOZ_ALWAYS_INLINE void
JSDependentString::init(js::ExclusiveContext *cx, JSLinearString *base, size_t start,
size_t length)
{
MOZ_ASSERT(!js::IsPoisonedPtr(base));
MOZ_ASSERT(start + length <= base->length());
d.u1.length = length;
JS::AutoCheckCannotGC nogc;
-8
View File
@@ -1098,20 +1098,12 @@ template <>
struct GCMethods<const TypeSet::Type>
{
static TypeSet::Type initial() { return TypeSet::UnknownType(); }
static bool poisoned(TypeSet::Type v) {
return (v.isGroup() && IsPoisonedPtr(v.group()))
|| (v.isSingleton() && IsPoisonedPtr(v.singleton()));
}
};
template <>
struct GCMethods<TypeSet::Type>
{
static TypeSet::Type initial() { return TypeSet::UnknownType(); }
static bool poisoned(TypeSet::Type v) {
return (v.isGroup() && IsPoisonedPtr(v.group()))
|| (v.isSingleton() && IsPoisonedPtr(v.singleton()));
}
};
} // namespace js
+2 -2
View File
@@ -29,11 +29,11 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 255;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 256;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 383,
static_assert(JSErr_Limit == 384,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
+1
View File
@@ -1386,6 +1386,7 @@ pref("javascript.options.mem.gc_compacting", true);
pref("javascript.options.mem.log", false);
pref("javascript.options.mem.notify", false);
pref("javascript.options.gc_on_memory_pressure", true);
pref("javascript.options.compact_on_user_inactive", true);
pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1000);
pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 100);
+1 -1
View File
@@ -340,7 +340,7 @@
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 10,
"description": "Use of SpiderMonkey's deprecated language extensions in web content: ForEach=0, DestructuringForIn=1, LegacyGenerator=2, ExpressionClosure=3, LetBlock=4, LetExpression=5, NoSuchMethod=6"
"description": "Use of SpiderMonkey's deprecated language extensions in web content: ForEach=0, DestructuringForIn=1, LegacyGenerator=2, ExpressionClosure=3, LetBlock=4, LetExpression=5, NoSuchMethod=6, FlagsArgument=7"
},
"TELEMETRY_PING": {
"expires_in_version": "never",