diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp index 1e29a0c124..579c5fad2e 100644 --- a/accessible/atk/AccessibleWrap.cpp +++ b/accessible/atk/AccessibleWrap.cpp @@ -145,7 +145,7 @@ MaiAtkObject::GetAtkHyperlink() void MaiAtkObject::Shutdown() { - accWrap = 0; + accWrap.SetBits(0); MaiHyperlink* maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink); if (maiHyperlink) { @@ -559,7 +559,7 @@ initializeCB(AtkObject *aAtkObj, gpointer aData) ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData); /* initialize object */ - MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast(aData); + MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast(aData)); } void @@ -567,7 +567,7 @@ finalizeCB(GObject *aObj) { if (!IS_MAI_OBJECT(aObj)) return; - NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null"); + NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null"); // call parent finalize function // finalize of GObjectClass will unref the accessible parent if has @@ -597,7 +597,8 @@ static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName) { NS_ConvertUTF16toUTF8 newNameUTF8(aNewName); - if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name)) + if (aAtkObj->name && + !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length())) return; // Below we duplicate the functionality of atk_object_set_name(), @@ -649,22 +650,17 @@ getRoleCB(AtkObject *aAtkObj) if (aAtkObj->role != ATK_ROLE_INVALID) return aAtkObj->role; - AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); - a11y::role role; - if (!accWrap) { - ProxyAccessible* proxy = GetProxy(aAtkObj); - if (!proxy) - return ATK_ROLE_INVALID; + AccessibleOrProxy acc = GetInternalObj(aAtkObj); + if (acc.IsNull()) { + return ATK_ROLE_INVALID; + } - role = proxy->Role(); - } else { #ifdef DEBUG + if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) { NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), "Does not support Text interface when it should"); -#endif - - role = accWrap->Role(); } +#endif #define ROLE(geckoRole, stringRole, atkRole, macRole, \ msaaRole, ia2Role, nameRule) \ @@ -672,7 +668,7 @@ getRoleCB(AtkObject *aAtkObj) aAtkObj->role = atkRole; \ break; - switch (role) { + switch (acc.Role()) { #include "RoleMap.h" default: MOZ_CRASH("Unknown role."); @@ -1064,7 +1060,7 @@ GetAccessibleWrap(AtkObject* aAtkObj) nullptr); uintptr_t accWrapPtr = isMAIObject ? - MAI_ATK_OBJECT(aAtkObj)->accWrap : + MAI_ATK_OBJECT(aAtkObj)->accWrap.Bits() : reinterpret_cast(MAI_ATK_SOCKET(aAtkObj)->accWrap); if (accWrapPtr & IS_PROXY) return nullptr; @@ -1088,11 +1084,10 @@ ProxyAccessible* GetProxy(AtkObject* aObj) { if (!aObj || !IS_MAI_OBJECT(aObj) || - !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY)) + !MAI_ATK_OBJECT(aObj)->accWrap.IsProxy()) return nullptr; - return reinterpret_cast(MAI_ATK_OBJECT(aObj)->accWrap - & ~IS_PROXY); + return MAI_ATK_OBJECT(aObj)->accWrap.AsProxy(); } AtkObject* diff --git a/accessible/atk/nsMai.h b/accessible/atk/nsMai.h index 4618524f7c..2e814df7ce 100644 --- a/accessible/atk/nsMai.h +++ b/accessible/atk/nsMai.h @@ -11,6 +11,7 @@ #include #include +#include "AccessibleOrProxy.h" #include "AccessibleWrap.h" namespace mozilla { @@ -95,7 +96,7 @@ struct MaiAtkObject * The AccessibleWrap whose properties and features are exported * via this object instance. */ - uintptr_t accWrap; + mozilla::a11y::AccessibleOrProxy accWrap; /* * Get the AtkHyperlink for this atk object. diff --git a/accessible/atk/nsMaiHyperlink.cpp b/accessible/atk/nsMaiHyperlink.cpp index e0703d8d9f..3994bba3f9 100644 --- a/accessible/atk/nsMaiHyperlink.cpp +++ b/accessible/atk/nsMaiHyperlink.cpp @@ -100,7 +100,7 @@ mai_atk_hyperlink_get_type(void) return type; } -MaiHyperlink::MaiHyperlink(uintptr_t aHyperLink) : +MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) : mHyperlink(aHyperLink), mMaiAtkHyperlink(nullptr) { diff --git a/accessible/atk/nsMaiHyperlink.h b/accessible/atk/nsMaiHyperlink.h index 44420323cd..7dc1b73551 100644 --- a/accessible/atk/nsMaiHyperlink.h +++ b/accessible/atk/nsMaiHyperlink.h @@ -23,31 +23,29 @@ namespace a11y { class MaiHyperlink { public: - explicit MaiHyperlink(uintptr_t aHyperLink); + explicit MaiHyperlink(AccessibleOrProxy aHyperLink); ~MaiHyperlink(); public: AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; } Accessible* GetAccHyperlink() { - if (!mHyperlink || mHyperlink & IS_PROXY) + if (!mHyperlink.IsAccessible()) return nullptr; - Accessible* link = reinterpret_cast(mHyperlink); + Accessible* link = mHyperlink.AsAccessible(); + if (!link) { + return nullptr; + } + NS_ASSERTION(link->IsLink(), "Why isn't it a link!"); return link; } - ProxyAccessible* Proxy() const - { - if (!(mHyperlink & IS_PROXY)) - return nullptr; - - return reinterpret_cast(mHyperlink & ~IS_PROXY); - } + ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); } protected: - uintptr_t mHyperlink; + AccessibleOrProxy mHyperlink; AtkHyperlink* mMaiAtkHyperlink; }; diff --git a/accessible/base/AccessibleOrProxy.h b/accessible/base/AccessibleOrProxy.h new file mode 100644 index 0000000000..72cbeb0344 --- /dev/null +++ b/accessible/base/AccessibleOrProxy.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_AccessibleOrProxy_h +#define mozilla_a11y_AccessibleOrProxy_h + +#include "mozilla/a11y/Accessible.h" +#include "mozilla/a11y/ProxyAccessible.h" + +#include + +namespace mozilla { +namespace a11y { + +/** + * This class stores an Accessible* or a ProxyAccessible* in a safe manner + * with size sizeof(void*). + */ +class AccessibleOrProxy +{ +public: + MOZ_IMPLICIT AccessibleOrProxy(Accessible* aAcc) : + mBits(reinterpret_cast(aAcc)) {} + MOZ_IMPLICIT AccessibleOrProxy(ProxyAccessible* aProxy) : + mBits(reinterpret_cast(aProxy) | IS_PROXY) {} + MOZ_IMPLICIT AccessibleOrProxy(decltype(nullptr)) : mBits(0) {} + + bool IsProxy() const { return mBits & IS_PROXY; } + ProxyAccessible* AsProxy() const + { + if (IsProxy()) { + return reinterpret_cast(mBits & ~IS_PROXY); + } + + return nullptr; + } + + bool IsAccessible() const { return !IsProxy(); } + Accessible* AsAccessible() const + { + if (IsAccessible()) { + return reinterpret_cast(mBits); + } + + return nullptr; + } + + bool IsNull() const { return mBits == 0; } + + // XXX these are implementation details that ideally would not be exposed. + uintptr_t Bits() const { return mBits; } + void SetBits(uintptr_t aBits) { mBits = aBits; } + +private: + uintptr_t mBits; + static const uintptr_t IS_PROXY = 0x1; +}; + +} +} + +#endif diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index dde68f3f2b..9d605845c6 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -321,43 +321,42 @@ MinorGC(JSContext* cx, unsigned argc, Value* vp) return true; } -#define FOR_EACH_GC_PARAM(_) \ - _("maxBytes", JSGC_MAX_BYTES, true, false) \ - _("maxMallocBytes", JSGC_MAX_MALLOC_BYTES, true, false) \ - _("gcBytes", JSGC_BYTES, false, false) \ - _("gcNumber", JSGC_NUMBER, false, false) \ - _("mode", JSGC_MODE, true, true) \ - _("unusedChunks", JSGC_UNUSED_CHUNKS, false, false) \ - _("totalChunks", JSGC_TOTAL_CHUNKS, false, false) \ - _("sliceTimeBudget", JSGC_SLICE_TIME_BUDGET, true, false) \ - _("markStackLimit", JSGC_MARK_STACK_LIMIT, true, false) \ - _("highFrequencyTimeLimit", JSGC_HIGH_FREQUENCY_TIME_LIMIT, true, false) \ - _("highFrequencyLowLimit", JSGC_HIGH_FREQUENCY_LOW_LIMIT, true, false) \ - _("highFrequencyHighLimit", JSGC_HIGH_FREQUENCY_HIGH_LIMIT, true, false) \ - _("highFrequencyHeapGrowthMax", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, true, false) \ - _("highFrequencyHeapGrowthMin", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, true, false) \ - _("lowFrequencyHeapGrowth", JSGC_LOW_FREQUENCY_HEAP_GROWTH, true, false) \ - _("dynamicHeapGrowth", JSGC_DYNAMIC_HEAP_GROWTH, true, true) \ - _("dynamicMarkSlice", JSGC_DYNAMIC_MARK_SLICE, true, true) \ - _("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true, false) \ - _("decommitThreshold", JSGC_DECOMMIT_THRESHOLD, true, false) \ - _("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true, true) \ - _("maxEmptyChunkCount", JSGC_MAX_EMPTY_CHUNK_COUNT, true, true) \ - _("compactingEnabled", JSGC_COMPACTING_ENABLED, true, true) +#define FOR_EACH_GC_PARAM(_) \ + _("maxBytes", JSGC_MAX_BYTES, true) \ + _("maxMallocBytes", JSGC_MAX_MALLOC_BYTES, true) \ + _("gcBytes", JSGC_BYTES, false) \ + _("gcNumber", JSGC_NUMBER, false) \ + _("mode", JSGC_MODE, true) \ + _("unusedChunks", JSGC_UNUSED_CHUNKS, false) \ + _("totalChunks", JSGC_TOTAL_CHUNKS, false) \ + _("sliceTimeBudget", JSGC_SLICE_TIME_BUDGET, true) \ + _("markStackLimit", JSGC_MARK_STACK_LIMIT, true) \ + _("highFrequencyTimeLimit", JSGC_HIGH_FREQUENCY_TIME_LIMIT, true) \ + _("highFrequencyLowLimit", JSGC_HIGH_FREQUENCY_LOW_LIMIT, true) \ + _("highFrequencyHighLimit", JSGC_HIGH_FREQUENCY_HIGH_LIMIT, true) \ + _("highFrequencyHeapGrowthMax", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, true) \ + _("highFrequencyHeapGrowthMin", JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, true) \ + _("lowFrequencyHeapGrowth", JSGC_LOW_FREQUENCY_HEAP_GROWTH, true) \ + _("dynamicHeapGrowth", JSGC_DYNAMIC_HEAP_GROWTH, true) \ + _("dynamicMarkSlice", JSGC_DYNAMIC_MARK_SLICE, true) \ + _("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true) \ + _("decommitThreshold", JSGC_DECOMMIT_THRESHOLD, true) \ + _("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true) \ + _("maxEmptyChunkCount", JSGC_MAX_EMPTY_CHUNK_COUNT, true) \ + _("compactingEnabled", JSGC_COMPACTING_ENABLED, true) static const struct ParamInfo { const char* name; JSGCParamKey param; bool writable; - bool allowZero; } paramMap[] = { -#define DEFINE_PARAM_INFO(name, key, writable, allowZero) \ - {name, key, writable, allowZero}, +#define DEFINE_PARAM_INFO(name, key, writable) \ + {name, key, writable}, FOR_EACH_GC_PARAM(DEFINE_PARAM_INFO) #undef DEFINE_PARAM_INFO }; -#define PARAM_NAME_LIST_ENTRY(name, key, writable, allowZero) \ +#define PARAM_NAME_LIST_ENTRY(name, key, writable) \ " " name #define GC_PARAMETER_ARGS_LIST FOR_EACH_GC_PARAM(PARAM_NAME_LIST_ENTRY) @@ -414,12 +413,6 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp) } uint32_t value = floor(d); - if (!info.allowZero && value == 0) { - JS_ReportError(cx, "the second argument must be convertable to uint32_t " - "with non-zero value"); - return false; - } - if (param == JSGC_MARK_STACK_LIMIT && JS::IsIncrementalGCInProgress(cx->runtime())) { JS_ReportError(cx, "attempt to set markStackLimit while a GC is in progress"); return false; @@ -436,7 +429,18 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp) } } - JS_SetGCParameter(cx->runtime(), param, value); + bool ok; + { + JSRuntime* rt = cx->runtime(); + AutoLockGC lock(rt); + ok = rt->gc.setParameter(param, value, lock); + } + + if (!ok) { + JS_ReportError(cx, "Parameter value out of range"); + return false; + } + args.rval().setUndefined(); return true; } diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 3cb45407f8..0464f8f9a2 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -231,8 +231,8 @@ const Class js::ScalarTypeDescr::class_ = { const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), - {"array", {nullptr, nullptr}, 0, 0, "ArrayShorthand"}, - {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"}, + JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, JSFUN_HAS_REST), + JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), JS_FS_END }; diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 0ee6357a11..035006b5a8 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -154,8 +154,8 @@ class GCSchedulingTunables /* * Controls the number of empty chunks reserved for future allocation. */ - unsigned minEmptyChunkCount_; - unsigned maxEmptyChunkCount_; + uint32_t minEmptyChunkCount_; + uint32_t maxEmptyChunkCount_; public: GCSchedulingTunables() @@ -190,7 +190,7 @@ class GCSchedulingTunables unsigned minEmptyChunkCount(const AutoLockGC&) const { return minEmptyChunkCount_; } unsigned maxEmptyChunkCount() const { return maxEmptyChunkCount_; } - void setParameter(JSGCParamKey key, uint32_t value, const AutoLockGC& lock); + bool setParameter(JSGCParamKey key, uint32_t value, const AutoLockGC& lock); }; /* @@ -593,7 +593,7 @@ class GCRuntime void removeRoot(Value* vp); void setMarkStackLimit(size_t limit, AutoLockGC& lock); - void setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock); + bool setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock); uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock); bool triggerGC(JS::gcreason::Reason reason); diff --git a/js/src/jit-test/tests/gc/bug-1238548.js b/js/src/jit-test/tests/gc/bug-1238548.js new file mode 100644 index 0000000000..9424ffb9c6 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1238548.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error +gcparam("highFrequencyHeapGrowthMax", 1); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 645cf493ab..f0864379bb 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1460,7 +1460,7 @@ JS_PUBLIC_API(void) JS_SetGCParameter(JSRuntime* rt, JSGCParamKey key, uint32_t value) { AutoLockGC lock(rt); - rt->gc.setParameter(key, value, lock); + MOZ_ALWAYS_TRUE(rt->gc.setParameter(key, value, lock)); } JS_PUBLIC_API(void) @@ -3401,7 +3401,10 @@ JS::NewFunctionFromSpec(JSContext* cx, const JSFunctionSpec* fs, HandleId id) { return nullptr; } - return &funVal.toObject().as(); + JSFunction* fun = &funVal.toObject().as(); + if (fs->flags & JSFUN_HAS_REST) + fun->setHasRest(); + return fun; } RootedAtom atom(cx, IdToFunctionName(cx, id)); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index cf833f86ff..ae0ab31cc8 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -840,7 +840,9 @@ class MOZ_STACK_CLASS SourceBufferHolder final */ #define JSFUN_GENERIC_NATIVE 0x800 -#define JSFUN_FLAGS_MASK 0xe00 /* | of all the JSFUN_* flags */ +#define JSFUN_HAS_REST 0x1000 /* function has ...rest parameter. */ + +#define JSFUN_FLAGS_MASK 0x1e00 /* | of all the JSFUN_* flags */ /* * If set, will allow redefining a non-configurable property, but only on a diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index d5e232c39c..e05aed6598 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1671,7 +1671,7 @@ const JSFunctionSpec js::function_methods[] = { JS_FN(js_apply_str, fun_apply, 2,0), JS_FN(js_call_str, fun_call, 1,0), JS_FN("isGenerator", fun_isGenerator,0,0), - JS_SELF_HOSTED_FN("bind", "FunctionBind", 1,JSPROP_DEFINE_LATE), + JS_SELF_HOSTED_FN("bind", "FunctionBind", 2,JSPROP_DEFINE_LATE|JSFUN_HAS_REST), JS_FS_END }; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9bab8b5d57..d2851578c9 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1293,7 +1293,7 @@ GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) * for default backward API compatibility. */ AutoLockGC lock(rt); - tunables.setParameter(JSGC_MAX_BYTES, maxbytes, lock); + MOZ_ALWAYS_TRUE(tunables.setParameter(JSGC_MAX_BYTES, maxbytes, lock)); setMaxMallocBytes(maxbytes); const char* size = getenv("JSGC_MARK_STACK_LIMIT"); @@ -1401,7 +1401,7 @@ GCRuntime::finishRoots() FinishPersistentRootedChains(rt->mainThread.roots); } -void +bool GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock) { switch (key) { @@ -1420,24 +1420,30 @@ GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock) decommitThreshold = (uint64_t)value * 1024 * 1024; break; case JSGC_MODE: + if (mode != JSGC_MODE_GLOBAL && + mode != JSGC_MODE_COMPARTMENT && + mode != JSGC_MODE_INCREMENTAL) + { + return false; + } mode = JSGCMode(value); - MOZ_ASSERT(mode == JSGC_MODE_GLOBAL || - mode == JSGC_MODE_COMPARTMENT || - mode == JSGC_MODE_INCREMENTAL); break; case JSGC_COMPACTING_ENABLED: compactingEnabled = value != 0; break; default: - tunables.setParameter(key, value, lock); + if (!tunables.setParameter(key, value, lock)) + return false; for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { zone->threshold.updateAfterGC(zone->usage.gcBytes(), GC_NORMAL, tunables, schedulingState, lock); } } + + return true; } -void +bool GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value, const AutoLockGC& lock) { switch(key) { @@ -1447,31 +1453,50 @@ GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value, const AutoL case JSGC_HIGH_FREQUENCY_TIME_LIMIT: highFrequencyThresholdUsec_ = value * PRMJ_USEC_PER_MSEC; break; - case JSGC_HIGH_FREQUENCY_LOW_LIMIT: - highFrequencyLowLimitBytes_ = (uint64_t)value * 1024 * 1024; + case JSGC_HIGH_FREQUENCY_LOW_LIMIT: { + uint64_t newLimit = (uint64_t)value * 1024 * 1024; + if (newLimit == UINT64_MAX) + return false; + highFrequencyLowLimitBytes_ = newLimit; if (highFrequencyLowLimitBytes_ >= highFrequencyHighLimitBytes_) highFrequencyHighLimitBytes_ = highFrequencyLowLimitBytes_ + 1; MOZ_ASSERT(highFrequencyHighLimitBytes_ > highFrequencyLowLimitBytes_); break; - case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: - MOZ_ASSERT(value > 0); - highFrequencyHighLimitBytes_ = (uint64_t)value * 1024 * 1024; + } + case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: { + uint64_t newLimit = (uint64_t)value * 1024 * 1024; + if (newLimit == 0) + return false; + highFrequencyHighLimitBytes_ = newLimit; if (highFrequencyHighLimitBytes_ <= highFrequencyLowLimitBytes_) highFrequencyLowLimitBytes_ = highFrequencyHighLimitBytes_ - 1; MOZ_ASSERT(highFrequencyHighLimitBytes_ > highFrequencyLowLimitBytes_); break; - case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: - highFrequencyHeapGrowthMax_ = value / 100.0; + } + case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: { + double newGrowth = value / 100.0; + if (newGrowth <= 0.85) + return false; + highFrequencyHeapGrowthMax_ = newGrowth; MOZ_ASSERT(highFrequencyHeapGrowthMax_ / 0.85 > 1.0); break; - case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: - highFrequencyHeapGrowthMin_ = value / 100.0; + } + case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: { + double newGrowth = value / 100.0; + if (newGrowth <= 0.85) + return false; + highFrequencyHeapGrowthMin_ = newGrowth; MOZ_ASSERT(highFrequencyHeapGrowthMin_ / 0.85 > 1.0); break; - case JSGC_LOW_FREQUENCY_HEAP_GROWTH: - lowFrequencyHeapGrowth_ = value / 100.0; + } + case JSGC_LOW_FREQUENCY_HEAP_GROWTH: { + double newGrowth = value / 100.0; + if (newGrowth <= 0.9) + return false; + lowFrequencyHeapGrowth_ = newGrowth; MOZ_ASSERT(lowFrequencyHeapGrowth_ / 0.9 > 1.0); break; + } case JSGC_DYNAMIC_HEAP_GROWTH: dynamicHeapGrowthEnabled_ = value != 0; break; @@ -1496,6 +1521,8 @@ GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value, const AutoL default: MOZ_CRASH("Unknown GC parameter."); } + + return true; } uint32_t diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 527d26ae85..7763b53ad0 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4243,7 +4243,7 @@ static const JSFunctionSpec string_static_methods[] = { JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode), JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 1,0), - JS_SELF_HOSTED_FN("raw", "String_static_raw", 1,0), + JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,JSFUN_HAS_REST), JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0), JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0), JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0), diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 5b0fdcf76c..b55865178d 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -301,7 +301,7 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) RootedFunction ctor(cx); if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, - /* nargs = */ 0, + /* nargs = */ !!derived, proto, TenuredObject, &ctor)) { return nullptr; @@ -309,6 +309,8 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) ctor->setIsConstructor(); ctor->setIsClassConstructor(); + if (derived) + ctor->setHasRest(); MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx)); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 42bfe996a4..13c84ce38b 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2276,19 +2276,8 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, return false; MOZ_ASSERT(!targetFun->isInterpretedLazy()); - // ...rest args don't count as formal args, but are included in nargs. We don't, - // however, want to introduce a flag "has rest args" in the declaration of - // self-hosted functions, so we fix up the flag and the nargs value here. - // Since the target function might have been cloned and relazified before, - // this only happens if the target function isn't marked as having rest - // args. - MOZ_ASSERT(sourceFun->nargs() - sourceFun->hasRest() == - targetFun->nargs() - targetFun->hasRest()); - MOZ_ASSERT_IF(targetFun->hasRest(), sourceFun->hasRest()); - if (sourceFun->hasRest() && !targetFun->hasRest()) { - targetFun->setHasRest(); - targetFun->setArgCount(sourceFun->nargs()); - } + MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs()); + MOZ_ASSERT(sourceFun->hasRest() == targetFun->hasRest()); // The target function might have been relazified after its flags changed. targetFun->setFlags(targetFun->flags() | sourceFun->flags()); diff --git a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp index 0e4e5d876a..09c193f47e 100644 --- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp +++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp @@ -58,40 +58,52 @@ void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JSObject** aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + if (*aPtr) { + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure); + if (aPtr->getPtr()) { + mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index fd114b76f0..5b65770e5e 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -468,11 +468,10 @@ DowncastCCParticipant(void* aPtr) NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, aCallbacks, aClosure); #define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \ - if (tmp->_field) \ - aCallbacks.Trace(&tmp->_field, #_field, aClosure); + aCallbacks.Trace(&tmp->_field, #_field, aClosure); #define NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(_field) \ - aCallbacks.Trace(&tmp->_field, #_field, aClosure); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) // NB: The (void)tmp; hack in the TRACE_END macro exists to support // implementations that don't need to do anything in their Trace method.