diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-03-23 15:12:36 -0400 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-04-07 11:46:46 -0400 |
commit | e024dc2e0014ef8e70ba5463cf206a05f7afc6ac (patch) | |
tree | 711f9b54df8cba0542a53dd4770c6b616754c2a8 /src/third_party | |
parent | c48f2983e1a525394449fd2f2f1323b964bc8968 (diff) | |
download | mongo-e024dc2e0014ef8e70ba5463cf206a05f7afc6ac.tar.gz |
SERVER-28400 Firefox ESR 45.8.0
Diffstat (limited to 'src/third_party')
91 files changed, 1615 insertions, 812 deletions
diff --git a/src/third_party/mozjs-45/SConscript b/src/third_party/mozjs-45/SConscript index dae5ab61ccb..4e9a8b07f9c 100644 --- a/src/third_party/mozjs-45/SConscript +++ b/src/third_party/mozjs-45/SConscript @@ -91,6 +91,7 @@ env.Prepend(CPPPATH=[ sources = [ "extract/js/src/builtin/RegExp.cpp", "extract/js/src/frontend/Parser.cpp", + "extract/js/src/jit/ProcessExecutableMemory.cpp", "extract/js/src/jsarray.cpp", "extract/js/src/jsatom.cpp", "extract/js/src/jsmath.cpp", @@ -112,13 +113,6 @@ if env.TargetOSIs('windows'): env.Prepend(CPPDEFINES=[ ("_CRT_RAND_S", "1") ]) - sources.extend([ - "extract/js/src/jit/ExecutableAllocatorWin.cpp", - ]) -else: - sources.extend([ - "extract/js/src/jit/ExecutableAllocatorPosix.cpp", - ]) sources.extend(Glob('platform/' + env["TARGET_ARCH"] + "/" + env["TARGET_OS"] + "/build/*.cpp")), diff --git a/src/third_party/mozjs-45/extract.sh b/src/third_party/mozjs-45/extract.sh index 589661b4ff9..18c51f7eaee 100644 --- a/src/third_party/mozjs-45/extract.sh +++ b/src/third_party/mozjs-45/extract.sh @@ -229,4 +229,5 @@ cp extract/mfbt/XorShift128PlusRNG.h include/mozilla git apply \ mongo_patches/SERVER-23358.patch \ mongo_patches/SERVER-24400.patch \ - mongo_patches/SERVER-22927-x86_64.patch + mongo_patches/SERVER-22927-x86_64.patch \ + mongo_patches/SERVER-28400-Solaris_MAP_NORESERVE.patch diff --git a/src/third_party/mozjs-45/extract/js/public/GCAPI.h b/src/third_party/mozjs-45/extract/js/public/GCAPI.h index 90f8e4eba3f..84b6150c36f 100644 --- a/src/third_party/mozjs-45/extract/js/public/GCAPI.h +++ b/src/third_party/mozjs-45/extract/js/public/GCAPI.h @@ -566,8 +566,6 @@ namespace gc { static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { - MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape); - /* * GC things residing in the nursery cannot be gray: they have no mark bits. * All live objects in the nursery are moved to tenured at the beginning of diff --git a/src/third_party/mozjs-45/extract/js/src/NamespaceImports.h b/src/third_party/mozjs-45/extract/js/src/NamespaceImports.h index 05a0e5dcf51..929263e69f4 100644 --- a/src/third_party/mozjs-45/extract/js/src/NamespaceImports.h +++ b/src/third_party/mozjs-45/extract/js/src/NamespaceImports.h @@ -49,6 +49,10 @@ class MOZ_STACK_CLASS SourceBufferHolder; class HandleValueArray; class ObjectOpResult; + +class Symbol; +enum class SymbolCode: uint32_t; + } // namespace JS // Do the importing. @@ -148,6 +152,9 @@ using JS::ObjectOpResult; using JS::Zone; +using JS::Symbol; +using JS::SymbolCode; + } /* namespace js */ #endif /* NamespaceImports_h */ diff --git a/src/third_party/mozjs-45/extract/js/src/asmjs/AsmJSModule.cpp b/src/third_party/mozjs-45/extract/js/src/asmjs/AsmJSModule.cpp index 350827042ee..9e707d06d0e 100644 --- a/src/third_party/mozjs-45/extract/js/src/asmjs/AsmJSModule.cpp +++ b/src/third_party/mozjs-45/extract/js/src/asmjs/AsmJSModule.cpp @@ -64,12 +64,11 @@ using JS::GenericNaN; static uint8_t* AllocateExecutableMemory(ExclusiveContext* cx, size_t bytes) { - // On most platforms, this will allocate RWX memory. On iOS, or when - // --non-writable-jitcode is used, this will allocate RW memory. In this - // case, DynamicallyLinkModule will reprotect the code as RX. - unsigned permissions = - ExecutableAllocator::initialProtectionFlags(ExecutableAllocator::Writable); - void* p = AllocateExecutableMemory(nullptr, bytes, permissions, "asm-js-code", AsmJSPageSize); + // bytes is a multiple of the system's page size, but not necessarily + // a multiple of ExecutableCodePageSize. + bytes = JS_ROUNDUP(bytes, ExecutableCodePageSize); + + void* p = AllocateExecutableMemory(bytes, ProtectionSetting::Writable); if (!p) ReportOutOfMemory(cx); return (uint8_t*)p; @@ -122,7 +121,8 @@ AsmJSModule::~AsmJSModule() exitDatum.baselineScript->removeDependentAsmJSModule(exit); } - DeallocateExecutableMemory(code_, pod.totalBytes_, AsmJSPageSize); + uint32_t size = JS_ROUNDUP(pod.totalBytes_, ExecutableCodePageSize); + DeallocateExecutableMemory(code_, size); } if (prevLinked_) diff --git a/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.cpp b/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.cpp index 94b97f434a5..8d474aefb50 100644 --- a/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.cpp +++ b/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.cpp @@ -15,6 +15,7 @@ #include "js/Utility.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" +#include "vm/Symbol.h" #include "jsobjinlines.h" @@ -63,13 +64,33 @@ HashableValue::setValue(JSContext* cx, HandleValue v) return true; } -HashNumber -HashableValue::hash() const +static HashNumber +HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs) { // HashableValue::setValue normalizes values so that the SameValue relation // on HashableValues is the same as the == relationship on - // value.data.asBits. - return value.asRawBits(); + // value.asRawBits(). So why not just return that? Security. + // + // To avoid revealing GC of atoms, string-based hash codes are computed + // from the string contents rather than any pointer; to avoid revealing + // addresses, pointer-based hash codes are computed using the + // HashCodeScrambler. + + if (v.isString()) + return v.toString()->asAtom().hash(); + if (v.isSymbol()) + return v.toSymbol()->hash(); + if (v.isObject()) + return hcs.scramble(v.asRawBits()); + + MOZ_ASSERT(v.isNull() || !v.isGCThing(), "do not reveal pointers via hash codes"); + return v.asRawBits(); +} + +HashNumber +HashableValue::hash(const mozilla::HashCodeScrambler& hcs) const +{ + return HashValue(value, hcs); } bool @@ -325,13 +346,15 @@ MapObject::mark(JSTracer* trc, JSObject* obj) struct UnbarrieredHashPolicy { typedef Value Lookup; - static HashNumber hash(const Lookup& v) { return v.asRawBits(); } + static HashNumber hash(const Lookup& v, const mozilla::HashCodeScrambler& hcs) { + return HashValue(v, hcs); + } static bool match(const Value& k, const Lookup& l) { return k == l; } static bool isEmpty(const Value& v) { return v.isMagic(JS_HASH_KEY_EMPTY); } static void makeEmpty(Value* vp) { vp->setMagic(JS_HASH_KEY_EMPTY); } }; -template <typename TableType> +template <typename RealTableType, typename TableType> class OrderedHashTableRef : public gc::BufferableRef { TableType* table; @@ -341,8 +364,9 @@ class OrderedHashTableRef : public gc::BufferableRef explicit OrderedHashTableRef(TableType* t, const Value& k) : table(t), key(k) {} void trace(JSTracer* trc) override { - MOZ_ASSERT(UnbarrieredHashPolicy::hash(key) == - HashableValue::Hasher::hash(*reinterpret_cast<HashableValue*>(&key))); + MOZ_ASSERT(reinterpret_cast<RealTableType*>(table) + ->hash(*reinterpret_cast<HashableValue*>(&key)) == + table->hash(key)); Value prior = key; TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key"); table->rekeyOneEntry(prior, key); @@ -354,7 +378,7 @@ WriteBarrierPost(JSRuntime* rt, ValueMap* map, const Value& key) { typedef OrderedHashMap<Value, Value, UnbarrieredHashPolicy, RuntimeAllocPolicy> UnbarrieredMap; if (MOZ_UNLIKELY(key.isObject() && IsInsideNursery(&key.toObject()))) { - rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<UnbarrieredMap>( + rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<ValueMap, UnbarrieredMap>( reinterpret_cast<UnbarrieredMap*>(map), key)); } } @@ -364,7 +388,7 @@ WriteBarrierPost(JSRuntime* rt, ValueSet* set, const Value& key) { typedef OrderedHashSet<Value, UnbarrieredHashPolicy, RuntimeAllocPolicy> UnbarrieredSet; if (MOZ_UNLIKELY(key.isObject() && IsInsideNursery(&key.toObject()))) { - rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<UnbarrieredSet>( + rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<ValueSet, UnbarrieredSet>( reinterpret_cast<UnbarrieredSet*>(set), key)); } } @@ -411,7 +435,8 @@ MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v) MapObject* MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */) { - auto map = cx->make_unique<ValueMap>(cx->runtime()); + auto map = cx->make_unique<ValueMap>(cx->runtime(), + cx->compartment()->randomHashCodeScrambler()); if (!map || !map->init()) { ReportOutOfMemory(cx); return nullptr; @@ -535,7 +560,7 @@ MapObject::is(HandleObject o) } #define ARG0_KEY(cx, args, key) \ - Rooted<HashableValue> key(cx); \ + Rooted<HashableValue> key(cx); \ if (args.length() > 0 && !key.setValue(cx, args[0])) \ return false @@ -1064,7 +1089,8 @@ SetObject::add(JSContext* cx, HandleObject obj, HandleValue k) SetObject* SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */) { - auto set = cx->make_unique<ValueSet>(cx->runtime()); + auto set = cx->make_unique<ValueSet>(cx->runtime(), + cx->compartment()->randomHashCodeScrambler()); if (!set || !set->init()) { ReportOutOfMemory(cx); return nullptr; diff --git a/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.h b/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.h index 1118675f873..9af58fc21cd 100644 --- a/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.h +++ b/src/third_party/mozjs-45/extract/js/src/builtin/MapObject.h @@ -29,7 +29,9 @@ class HashableValue : public JS::Traceable public: struct Hasher { typedef HashableValue Lookup; - static HashNumber hash(const Lookup& v) { return v.hash(); } + static HashNumber hash(const Lookup& v, const mozilla::HashCodeScrambler& hcs) { + return v.hash(hcs); + } static bool match(const HashableValue& k, const Lookup& l) { return k == l; } static bool isEmpty(const HashableValue& v) { return v.value.isMagic(JS_HASH_KEY_EMPTY); } static void makeEmpty(HashableValue* vp) { vp->value = MagicValue(JS_HASH_KEY_EMPTY); } @@ -38,7 +40,7 @@ class HashableValue : public JS::Traceable HashableValue() : value(UndefinedValue()) {} bool setValue(JSContext* cx, HandleValue v); - HashNumber hash() const; + HashNumber hash(const mozilla::HashCodeScrambler& hcs) const; bool operator==(const HashableValue& other) const; HashableValue mark(JSTracer* trc) const; Value get() const { return value.get(); } diff --git a/src/third_party/mozjs-45/extract/js/src/ds/OrderedHashTable.h b/src/third_party/mozjs-45/extract/js/src/ds/OrderedHashTable.h index c9927212976..cb58ac2f735 100644 --- a/src/third_party/mozjs-45/extract/js/src/ds/OrderedHashTable.h +++ b/src/third_party/mozjs-45/extract/js/src/ds/OrderedHashTable.h @@ -29,12 +29,15 @@ * * See the comment about "Hash policy" in HashTable.h for general features that * hash policy classes must provide. Hash policies for OrderedHashMaps and Sets - * must additionally provide a distinguished "empty" key value and the + * differ in that the hash() method takes an extra argument: + * static js::HashNumber hash(Lookup, const HashCodeScrambler&); + * They must additionally provide a distinguished "empty" key value and the * following static member functions: * bool isEmpty(const Key&); * void makeEmpty(Key*); */ +#include "mozilla/HashFunctions.h" #include "mozilla/Move.h" using mozilla::Forward; @@ -78,10 +81,11 @@ class OrderedHashTable uint32_t hashShift; // multiplicative hash shift Range* ranges; // list of all live Ranges on this table AllocPolicy alloc; + mozilla::HashCodeScrambler hcs; // don't reveal pointer hash codes public: - explicit OrderedHashTable(AllocPolicy& ap) - : hashTable(nullptr), data(nullptr), dataLength(0), ranges(nullptr), alloc(ap) {} + OrderedHashTable(AllocPolicy& ap, mozilla::HashCodeScrambler hcs) + : hashTable(nullptr), data(nullptr), dataLength(0), ranges(nullptr), alloc(ap), hcs(hcs) {} bool init() { MOZ_ASSERT(!hashTable, "init must be called at most once"); @@ -430,8 +434,8 @@ class OrderedHashTable void rekeyFront(const Key& k) { MOZ_ASSERT(valid()); Data& entry = ht.data[i]; - HashNumber oldHash = prepareHash(Ops::getKey(entry.element)) >> ht.hashShift; - HashNumber newHash = prepareHash(k) >> ht.hashShift; + HashNumber oldHash = ht.prepareHash(Ops::getKey(entry.element)) >> ht.hashShift; + HashNumber newHash = ht.prepareHash(k) >> ht.hashShift; Ops::setKey(entry.element, k); if (newHash != oldHash) { // Remove this entry from its old hash chain. (If this crashes @@ -527,10 +531,12 @@ class OrderedHashTable */ static double minDataFill() { return 0.25; } - static HashNumber prepareHash(const Lookup& l) { - return ScrambleHashCode(Ops::hash(l)); + public: + HashNumber prepareHash(const Lookup& l) const { + return ScrambleHashCode(Ops::hash(l, hcs)); } + private: /* The size of hashTable, in elements. Always a power of two. */ uint32_t hashBuckets() const { return 1 << (HashNumberSizeBits - hashShift); @@ -701,7 +707,7 @@ class OrderedHashMap public: typedef typename Impl::Range Range; - explicit OrderedHashMap(AllocPolicy ap = AllocPolicy()) : impl(ap) {} + OrderedHashMap(AllocPolicy ap, mozilla::HashCodeScrambler hcs) : impl(ap, hcs) {} bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const Key& key) const { return impl.has(key); } @@ -713,6 +719,8 @@ class OrderedHashMap bool remove(const Key& key, bool* foundp) { return impl.remove(key, foundp); } bool clear() { return impl.clear(); } + HashNumber hash(const Key& key) const { return impl.prepareHash(key); } + void rekeyOneEntry(const Key& current, const Key& newKey) { const Entry* e = get(current); if (!e) @@ -738,7 +746,7 @@ class OrderedHashSet public: typedef typename Impl::Range Range; - explicit OrderedHashSet(AllocPolicy ap = AllocPolicy()) : impl(ap) {} + explicit OrderedHashSet(AllocPolicy ap, mozilla::HashCodeScrambler hcs) : impl(ap, hcs) {} bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const T& value) const { return impl.has(value); } @@ -747,6 +755,8 @@ class OrderedHashSet bool remove(const T& value, bool* foundp) { return impl.remove(value, foundp); } bool clear() { return impl.clear(); } + HashNumber hash(const T& value) const { return impl.prepareHash(value); } + void rekeyOneEntry(const T& current, const T& newKey) { return impl.rekeyOneEntry(current, newKey, newKey); } diff --git a/src/third_party/mozjs-45/extract/js/src/gc/Allocator.cpp b/src/third_party/mozjs-45/extract/js/src/gc/Allocator.cpp index b409dfa4a1f..bdc17bdc8db 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/Allocator.cpp +++ b/src/third_party/mozjs-45/extract/js/src/gc/Allocator.cpp @@ -57,11 +57,14 @@ GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind) } #if defined(JS_GC_ZEAL) || defined(DEBUG) - MOZ_ASSERT_IF(rt->isAtomsCompartment(cx->compartment()), - kind == AllocKind::STRING || - kind == AllocKind::FAT_INLINE_STRING || + MOZ_ASSERT_IF(cx->compartment()->isAtomsCompartment(), + kind == AllocKind::ATOM || + kind == AllocKind::FAT_INLINE_ATOM || kind == AllocKind::SYMBOL || kind == AllocKind::JITCODE); + MOZ_ASSERT_IF(!cx->compartment()->isAtomsCompartment(), + kind != AllocKind::ATOM && + kind != AllocKind::FAT_INLINE_ATOM); MOZ_ASSERT(!rt->isHeapBusy()); MOZ_ASSERT(isAllocAllowed()); #endif @@ -221,6 +224,8 @@ js::Allocate(ExclusiveContext* cx) macro(JSFatInlineString) \ macro(JSScript) \ macro(JSString) \ + macro(js::NormalAtom) \ + macro(js::FatInlineAtom) \ macro(js::AccessorShape) \ macro(js::BaseShape) \ macro(js::LazyScript) \ diff --git a/src/third_party/mozjs-45/extract/js/src/gc/GCRuntime.h b/src/third_party/mozjs-45/extract/js/src/gc/GCRuntime.h index d2b45473862..e0ad996150d 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/GCRuntime.h +++ b/src/third_party/mozjs-45/extract/js/src/gc/GCRuntime.h @@ -923,7 +923,7 @@ class GCRuntime void purgeRuntime(); bool beginMarkPhase(JS::gcreason::Reason reason); bool shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime, - JS::gcreason::Reason reason); + JS::gcreason::Reason reason, bool canAllocateMoreCode); void bufferGrayRoots(); void markCompartments(); IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase); diff --git a/src/third_party/mozjs-45/extract/js/src/gc/Heap.h b/src/third_party/mozjs-45/extract/js/src/gc/Heap.h index 1ff1d9fa498..783da19a388 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/Heap.h +++ b/src/third_party/mozjs-45/extract/js/src/gc/Heap.h @@ -106,6 +106,8 @@ enum class AllocKind { FAT_INLINE_STRING, STRING, EXTERNAL_STRING, + FAT_INLINE_ATOM, + ATOM, SYMBOL, JITCODE, LIMIT, @@ -197,6 +199,8 @@ MapAllocToTraceKind(AllocKind kind) JS::TraceKind::String, /* AllocKind::FAT_INLINE_STRING */ JS::TraceKind::String, /* AllocKind::STRING */ JS::TraceKind::String, /* AllocKind::EXTERNAL_STRING */ + JS::TraceKind::String, /* AllocKind::FAT_INLINE_ATOM */ + JS::TraceKind::String, /* AllocKind::ATOM */ JS::TraceKind::Symbol, /* AllocKind::SYMBOL */ JS::TraceKind::JitCode, /* AllocKind::JITCODE */ }; diff --git a/src/third_party/mozjs-45/extract/js/src/gc/Marking.cpp b/src/third_party/mozjs-45/extract/js/src/gc/Marking.cpp index f52ab393f71..4e10b20b36c 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/Marking.cpp +++ b/src/third_party/mozjs-45/extract/js/src/gc/Marking.cpp @@ -171,6 +171,17 @@ template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JS::Symbol>(JS::Symbol* s return sym->isWellKnownSymbol(); } +template <typename T> +static inline bool +IsOwnedByOtherRuntime(JSRuntime* rt, T thing) +{ + bool other = thing->runtimeFromAnyThread() != rt; + MOZ_ASSERT_IF(other, + ThingIsPermanentAtomOrWellKnownSymbol(thing) || + thing->zoneFromAnyThread()->isSelfHostingZone()); + return other; +} + template<typename T> void js::CheckTracedThing(JSTracer* trc, T* thing) @@ -188,10 +199,10 @@ js::CheckTracedThing(JSTracer* trc, T* thing) MOZ_ASSERT_IF(!IsMovingTracer(trc) && !trc->isTenuringTracer(), !IsForwarded(thing)); /* - * Permanent atoms are not associated with this runtime, but will be - * ignored during marking. + * Permanent atoms and things in the self-hosting zone are not associated + * with this runtime, but will be ignored during marking. */ - if (ThingIsPermanentAtomOrWellKnownSymbol(thing)) + if (IsOwnedByOtherRuntime(trc->runtime(), thing)) return; Zone* zone = thing->zoneFromAnyThread(); @@ -675,16 +686,24 @@ GCMarker::markImplicitEdges(T* thing) template <typename T> static inline bool -MustSkipMarking(T thing) +MustSkipMarking(GCMarker* gcmarker, T thing) { + // Don't trace things that are owned by another runtime. + if (IsOwnedByOtherRuntime(gcmarker->runtime(), thing)) + return true; + // Don't mark things outside a zone if we are in a per-zone GC. return !thing->zone()->isGCMarking(); } template <> bool -MustSkipMarking<JSObject*>(JSObject* obj) +MustSkipMarking<JSObject*>(GCMarker* gcmarker, JSObject* obj) { + // Don't trace things that are owned by another runtime. + if (IsOwnedByOtherRuntime(gcmarker->runtime(), obj)) + return true; + // We may mark a Nursery thing outside the context of the // MinorCollectionTracer because of a pre-barrier. The pre-barrier is not // needed in this case because we perform a minor collection before each @@ -698,34 +717,12 @@ MustSkipMarking<JSObject*>(JSObject* obj) return !TenuredCell::fromPointer(obj)->zone()->isGCMarking(); } -template <> -bool -MustSkipMarking<JSString*>(JSString* str) -{ - // Don't mark permanent atoms, as they may be associated with another - // runtime. Note that traverse() also checks this, but we need to not - // run the isGCMarking test from off-main-thread, so have to check it here - // too. - return str->isPermanentAtom() || - !str->zone()->isGCMarking(); -} - -template <> -bool -MustSkipMarking<JS::Symbol*>(JS::Symbol* sym) -{ - // As for JSString, don't touch a globally owned well-known symbol from - // off-main-thread. - return sym->isWellKnownSymbol() || - !sym->zone()->isGCMarking(); -} - template <typename T> void DoMarking(GCMarker* gcmarker, T* thing) { // Do per-type marking precondition checks. - if (MustSkipMarking(thing)) + if (MustSkipMarking(gcmarker, thing)) return; CheckTracedThing(gcmarker, thing); @@ -752,13 +749,13 @@ void NoteWeakEdge(GCMarker* gcmarker, T** thingp) { // Do per-type marking precondition checks. - if (MustSkipMarking(*thingp)) + if (MustSkipMarking(gcmarker, *thingp)) return; CheckTracedThing(gcmarker, *thingp); // If the target is already marked, there's no need to store the edge. - if (IsMarkedUnbarriered(thingp)) + if (IsMarkedUnbarriered(gcmarker->runtime(), thingp)) return; gcmarker->noteWeakEdge(thingp); @@ -2329,17 +2326,22 @@ IsMarkedInternalCommon(T* thingp) template <typename T> static bool -IsMarkedInternal(T** thingp) +IsMarkedInternal(JSRuntime* rt, T** thingp) { + if (IsOwnedByOtherRuntime(rt, *thingp)) + return true; + return IsMarkedInternalCommon(thingp); } template <> /* static */ bool -IsMarkedInternal(JSObject** thingp) +IsMarkedInternal(JSRuntime* rt, JSObject** thingp) { + if (IsOwnedByOtherRuntime(rt, *thingp)) + return true; + if (IsInsideNursery(*thingp)) { - JSRuntime* rt = (*thingp)->runtimeFromAnyThread(); MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); return rt->gc.nursery.getForwardedPointer(thingp); } @@ -2348,18 +2350,18 @@ IsMarkedInternal(JSObject** thingp) template <typename S> struct IsMarkedFunctor : public IdentityDefaultAdaptor<S> { - template <typename T> S operator()(T* t, bool* rv) { - *rv = IsMarkedInternal(&t); + template <typename T> S operator()(T* t, JSRuntime* rt, bool* rv) { + *rv = IsMarkedInternal(rt, &t); return js::gc::RewrapTaggedPointer<S, T*>::wrap(t); } }; template <typename T> static bool -IsMarkedInternal(T* thingp) +IsMarkedInternal(JSRuntime* rt, T* thingp) { bool rv = true; - *thingp = DispatchTyped(IsMarkedFunctor<T>(), *thingp, &rv); + *thingp = DispatchTyped(IsMarkedFunctor<T>(), *thingp, rt, &rv); return rv; } @@ -2427,16 +2429,16 @@ namespace gc { template <typename T> bool -IsMarkedUnbarriered(T* thingp) +IsMarkedUnbarriered(JSRuntime* rt, T* thingp) { - return IsMarkedInternal(ConvertToBase(thingp)); + return IsMarkedInternal(rt, ConvertToBase(thingp)); } template <typename T> bool -IsMarked(WriteBarrieredBase<T>* thingp) +IsMarked(JSRuntime* rt, WriteBarrieredBase<T>* thingp) { - return IsMarkedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing())); + return IsMarkedInternal(rt, ConvertToBase(thingp->unsafeUnbarrieredForTracing())); } template <typename T> @@ -2469,8 +2471,8 @@ EdgeNeedsSweep(JS::Heap<T>* thingp) // Instantiate a copy of the Tracing templates for each derived type. #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \ - template bool IsMarkedUnbarriered<type>(type*); \ - template bool IsMarked<type>(WriteBarrieredBase<type>*); \ + template bool IsMarkedUnbarriered<type>(JSRuntime*, type*); \ + template bool IsMarked<type>(JSRuntime*, WriteBarrieredBase<type>*); \ template bool IsAboutToBeFinalizedUnbarriered<type>(type*); \ template bool IsAboutToBeFinalized<type>(WriteBarrieredBase<type>*); \ template bool IsAboutToBeFinalized<type>(ReadBarrieredBase<type>*); \ diff --git a/src/third_party/mozjs-45/extract/js/src/gc/Marking.h b/src/third_party/mozjs-45/extract/js/src/gc/Marking.h index 5c69cd1fdb6..5e237c2154b 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/Marking.h +++ b/src/third_party/mozjs-45/extract/js/src/gc/Marking.h @@ -142,7 +142,9 @@ namespace gc { struct WeakKeyTableHashPolicy { typedef JS::GCCellPtr Lookup; - static HashNumber hash(const Lookup& v) { return mozilla::HashGeneric(v.asCell()); } + static HashNumber hash(const Lookup& v, const mozilla::HashCodeScrambler&) { + return mozilla::HashGeneric(v.asCell()); + } static bool match(const JS::GCCellPtr& k, const Lookup& l) { return k == l; } static bool isEmpty(const JS::GCCellPtr& v) { return !v; } static void makeEmpty(JS::GCCellPtr* vp) { *vp = nullptr; } @@ -368,13 +370,19 @@ PushArena(GCMarker* gcmarker, ArenaHeader* aheader); /*** Liveness ***/ +// Report whether a thing has been marked. Things which are in zones that are +// not currently being collected or are owned by another runtime are always +// reported as being marked. template <typename T> bool -IsMarkedUnbarriered(T* thingp); +IsMarkedUnbarriered(JSRuntime* rt, T* thingp); +// Report whether a thing has been marked. Things which are in zones that are +// not currently being collected or are owned by another runtime are always +// reported as being marked. template <typename T> bool -IsMarked(WriteBarrieredBase<T>* thingp); +IsMarked(JSRuntime* rt, WriteBarrieredBase<T>* thingp); template <typename T> bool diff --git a/src/third_party/mozjs-45/extract/js/src/gc/Zone.cpp b/src/third_party/mozjs-45/extract/js/src/gc/Zone.cpp index 260f06dbe47..b001ecff9e6 100644 --- a/src/third_party/mozjs-45/extract/js/src/gc/Zone.cpp +++ b/src/third_party/mozjs-45/extract/js/src/gc/Zone.cpp @@ -29,6 +29,7 @@ JS::Zone::Zone(JSRuntime* rt) types(this), compartments(), gcGrayRoots(), + gcWeakKeys(SystemAllocPolicy(), rt->randomHashCodeScrambler()), gcMallocBytes(0), gcMallocGCTriggered(false), usage(&rt->gc.usage), diff --git a/src/third_party/mozjs-45/extract/js/src/irregexp/RegExpEngine.cpp b/src/third_party/mozjs-45/extract/js/src/irregexp/RegExpEngine.cpp index ba30fc7a72d..84dab0c8adf 100644 --- a/src/third_party/mozjs-45/extract/js/src/irregexp/RegExpEngine.cpp +++ b/src/third_party/mozjs-45/extract/js/src/irregexp/RegExpEngine.cpp @@ -32,6 +32,7 @@ #include "irregexp/NativeRegExpMacroAssembler.h" #include "irregexp/RegExpMacroAssembler.h" +#include "jit/ExecutableAllocator.h" #include "jit/JitCommon.h" using namespace js; @@ -1730,7 +1731,11 @@ irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler; RegExpMacroAssembler* assembler; - if (IsNativeRegExpEnabled(cx) && !force_bytecode) { + if (IsNativeRegExpEnabled(cx) && + !force_bytecode && + jit::CanLikelyAllocateMoreExecutableMemory() && + shared->getSource()->length() < 32 * 1024) + { NativeRegExpMacroAssembler::Mode mode = is_ascii ? NativeRegExpMacroAssembler::ASCII : NativeRegExpMacroAssembler::CHAR16; diff --git a/src/third_party/mozjs-45/extract/js/src/jit/BaselineIC.cpp b/src/third_party/mozjs-45/extract/js/src/jit/BaselineIC.cpp index 03236cff6cc..69c402bc1a9 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/BaselineIC.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/BaselineIC.cpp @@ -1061,6 +1061,14 @@ IsCacheableSetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh JSFunction* func = &shape->setterObject()->as<JSFunction>(); + if (IsWindow(obj)) { + if (!func->isNative()) + return false; + + if (!func->jitInfo() || func->jitInfo()->needsOuterizedThisObject()) + return false; + } + if (func->isNative()) { *isScripted = false; return true; @@ -6398,6 +6406,12 @@ ICCallStubCompiler::guardFunApply(MacroAssembler& masm, AllocatableGeneralRegist Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()), Imm32(BaselineFrame::HAS_ARGS_OBJ), failure); + + // Limit the length to something reasonable. + masm.branch32(Assembler::Above, + Address(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs()), + Imm32(ICCall_ScriptedApplyArray::MAX_ARGS_ARRAY_LENGTH), + failure); } else { MOZ_ASSERT(applyThing == FunApply_Array); diff --git a/src/third_party/mozjs-45/extract/js/src/jit/BaselineJIT.cpp b/src/third_party/mozjs-45/extract/js/src/jit/BaselineJIT.cpp index f0dc2655e83..293868a741f 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/BaselineJIT.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/BaselineJIT.cpp @@ -314,12 +314,17 @@ CanEnterBaselineJIT(JSContext* cx, HandleScript script, InterpreterFrame* osrFra if (script->nslots() > BaselineScript::MAX_JSSCRIPT_SLOTS) return Method_CantCompile; - if (!cx->compartment()->ensureJitCompartmentExists(cx)) - return Method_Error; - if (script->hasBaselineScript()) return Method_Compiled; + // Check this before calling ensureJitCompartmentExists, so we're less + // likely to report OOM in JSRuntime::createJitRuntime. + if (!CanLikelyAllocateMoreExecutableMemory()) + return Method_Skipped; + + if (!cx->compartment()->ensureJitCompartmentExists(cx)) + return Method_Error; + // Check script warm-up counter. if (script->incWarmUpCounter() <= JitOptions.baselineWarmUpThreshold) return Method_Skipped; diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.cpp b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.cpp index 55ad6b6d69c..aa24216c3a5 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.cpp @@ -29,15 +29,8 @@ #include "js/MemoryMetrics.h" -#ifdef __APPLE__ -#include <TargetConditionals.h> -#endif - using namespace js::jit; -size_t ExecutableAllocator::pageSize = 0; -size_t ExecutableAllocator::largeAllocSize = 0; - ExecutablePool::~ExecutablePool() { MOZ_ASSERT(m_ionCodeBytes == 0); @@ -48,28 +41,6 @@ ExecutablePool::~ExecutablePool() m_allocator->releasePoolPages(this); } -/* static */ void -ExecutableAllocator::initStatic() -{ - if (!pageSize) { - pageSize = determinePageSize(); - // On Windows, VirtualAlloc effectively allocates in 64K chunks. - // (Technically, it allocates in page chunks, but the starting - // address is always a multiple of 64K, so each allocation uses up - // 64K of address space.) So a size less than that would be - // pointless. But it turns out that 64KB is a reasonable size for - // all platforms. (This assumes 4KB pages.) On 64-bit windows, - // AllocateExecutableMemory prepends an extra page for structured - // exception handling data (see comments in function) onto whatever - // is passed in, so subtract one page here. -#if defined(JS_CPU_X64) && defined(XP_WIN) - largeAllocSize = pageSize * 15; -#else - largeAllocSize = pageSize * 16; -#endif - } -} - void ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const { @@ -88,8 +59,16 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const } } -#if TARGET_OS_IPHONE -bool ExecutableAllocator::nonWritableJitCode = true; -#else -bool ExecutableAllocator::nonWritableJitCode = false; -#endif +ExecutablePool::Allocation +ExecutableAllocator::systemAlloc(size_t n) +{ + void* allocation = AllocateExecutableMemory(n, ProtectionSetting::Executable); + ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n }; + return alloc; +} + +void +ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) +{ + DeallocateExecutableMemory(alloc.pages, alloc.size); +} diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.h b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.h index 874f6b7314f..cc0ad2b66ea 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.h +++ b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocator.h @@ -39,6 +39,7 @@ #include "jit/arm/Simulator-arm.h" #include "jit/mips32/Simulator-mips32.h" #include "jit/mips64/Simulator-mips64.h" +#include "jit/ProcessExecutableMemory.h" #include "js/GCAPI.h" #include "js/HashTable.h" #include "js/Vector.h" @@ -186,13 +187,7 @@ class ExecutableAllocator typedef void (*DestroyCallback)(void* addr, size_t size); DestroyCallback destroyCallback; -#ifdef XP_WIN - mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator; -#endif - public: - enum ProtectionSetting { Writable, Executable }; - ExecutableAllocator() : destroyCallback(nullptr) { @@ -263,14 +258,7 @@ class ExecutableAllocator this->destroyCallback = destroyCallback; } - static void initStatic(); - - static bool nonWritableJitCode; - private: - static size_t pageSize; - static size_t largeAllocSize; - static const size_t OVERSIZE_ALLOCATION = size_t(-1); static size_t roundUpAllocationSize(size_t request, size_t granularity) @@ -294,11 +282,10 @@ class ExecutableAllocator // On OOM, this will return an Allocation where pages is nullptr. ExecutablePool::Allocation systemAlloc(size_t n); static void systemRelease(const ExecutablePool::Allocation& alloc); - void* computeRandomAllocationAddress(); ExecutablePool* createPool(size_t n) { - size_t allocSize = roundUpAllocationSize(n, pageSize); + size_t allocSize = roundUpAllocationSize(n, ExecutableCodePageSize); if (allocSize == OVERSIZE_ALLOCATION) return nullptr; @@ -316,8 +303,8 @@ class ExecutableAllocator } if (!m_pools.put(pool)) { + // Note: this will call |systemRelease(a)|. js_delete(pool); - systemRelease(a); return nullptr; } @@ -344,11 +331,11 @@ class ExecutableAllocator } // If the request is large, we just provide a unshared allocator - if (n > largeAllocSize) + if (n > ExecutableCodePageSize) return createPool(n); // Create a new allocator - ExecutablePool* pool = createPool(largeAllocSize); + ExecutablePool* pool = createPool(ExecutableCodePageSize); if (!pool) return nullptr; // At this point, local |pool| is the owner. @@ -385,18 +372,12 @@ class ExecutableAllocator static void makeWritable(void* start, size_t size) { - if (nonWritableJitCode) - reprotectRegion(start, size, Writable); } static void makeExecutable(void* start, size_t size) { - if (nonWritableJitCode) - reprotectRegion(start, size, Executable); } - static unsigned initialProtectionFlags(ProtectionSetting protection); - #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) static void cacheFlush(void*, size_t) { @@ -469,8 +450,6 @@ class ExecutableAllocator ExecutableAllocator(const ExecutableAllocator&) = delete; void operator=(const ExecutableAllocator&) = delete; - static void reprotectRegion(void*, size_t, ProtectionSetting); - // These are strong references; they keep pools alive. static const size_t maxSmallPools = 4; typedef js::Vector<ExecutablePool*, maxSmallPools, js::SystemAllocPolicy> SmallExecPoolVector; @@ -482,17 +461,8 @@ class ExecutableAllocator typedef js::HashSet<ExecutablePool*, js::DefaultHasher<ExecutablePool*>, js::SystemAllocPolicy> ExecPoolHashSet; ExecPoolHashSet m_pools; // All pools, just for stats purposes. - - static size_t determinePageSize(); }; -extern void* -AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag, - size_t pageSize); - -extern void -DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize); - } // namespace jit } // namespace js diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorPosix.cpp b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorPosix.cpp deleted file mode 100644 index d6d791174d6..00000000000 --- a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorPosix.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mozilla/DebugOnly.h" -#include "mozilla/TaggedAnonymousMemory.h" - -#include <errno.h> -#include <sys/mman.h> -#include <unistd.h> - -#include "jit/ExecutableAllocator.h" -#include "js/Utility.h" - -using namespace js::jit; - -size_t -ExecutableAllocator::determinePageSize() -{ - return getpagesize(); -} - -void* -js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag, - size_t pageSize) -{ - MOZ_ASSERT(bytes % pageSize == 0); - void* p = MozTaggedAnonymousMmap(addr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0, tag); - return p == MAP_FAILED ? nullptr : p; -} - -void -js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize) -{ - MOZ_ASSERT(bytes % pageSize == 0); - mozilla::DebugOnly<int> result = munmap(addr, bytes); - MOZ_ASSERT(!result || errno == ENOMEM); -} - -ExecutablePool::Allocation -ExecutableAllocator::systemAlloc(size_t n) -{ - void* allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable), - "js-jit-code", pageSize); - ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n }; - return alloc; -} - -void -ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) -{ - DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize); -} - -static const unsigned FLAGS_RW = PROT_READ | PROT_WRITE; -static const unsigned FLAGS_RX = PROT_READ | PROT_EXEC; - -void -ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) -{ - MOZ_ASSERT(nonWritableJitCode); - MOZ_ASSERT(pageSize); - - // Calculate the start of the page containing this region, - // and account for this extra memory within size. - intptr_t startPtr = reinterpret_cast<intptr_t>(start); - intptr_t pageStartPtr = startPtr & ~(pageSize - 1); - void* pageStart = reinterpret_cast<void*>(pageStartPtr); - size += (startPtr - pageStartPtr); - - // Round size up - size += (pageSize - 1); - size &= ~(pageSize - 1); - - mprotect(pageStart, size, (setting == Writable) ? FLAGS_RW : FLAGS_RX); -} - -/* static */ unsigned -ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection) -{ - if (!nonWritableJitCode) - return FLAGS_RW | FLAGS_RX; - - return (protection == Writable) ? FLAGS_RW : FLAGS_RX; -} diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorWin.cpp b/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorWin.cpp deleted file mode 100644 index fe068b90814..00000000000 --- a/src/third_party/mozjs-45/extract/js/src/jit/ExecutableAllocatorWin.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mozilla/WindowsVersion.h" - -#include "jsfriendapi.h" -#include "jsmath.h" -#include "jswin.h" - -#include "jit/ExecutableAllocator.h" - -using namespace js::jit; - -size_t -ExecutableAllocator::determinePageSize() -{ - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - return system_info.dwPageSize; -} - -void* -ExecutableAllocator::computeRandomAllocationAddress() -{ - /* - * Inspiration is V8's OS::Allocate in platform-win32.cc. - * - * VirtualAlloc takes 64K chunks out of the virtual address space, so we - * keep 16b alignment. - * - * x86: V8 comments say that keeping addresses in the [64MiB, 1GiB) range - * tries to avoid system default DLL mapping space. In the end, we get 13 - * bits of randomness in our selection. - * x64: [2GiB, 4TiB), with 25 bits of randomness. - */ -#ifdef JS_CPU_X64 - static const uintptr_t base = 0x0000000080000000; - static const uintptr_t mask = 0x000003ffffff0000; -#elif defined(JS_CPU_X86) - static const uintptr_t base = 0x04000000; - static const uintptr_t mask = 0x3fff0000; -#else -# error "Unsupported architecture" -#endif - - if (randomNumberGenerator.isNothing()) { - mozilla::Array<uint64_t, 2> seed; - js::GenerateXorShift128PlusSeed(seed); - randomNumberGenerator.emplace(seed[0], seed[1]); - } - - uint64_t rand = randomNumberGenerator.ref().next(); - return (void*) (base | (rand & mask)); -} - -static bool -RandomizeIsBrokenImpl() -{ - // We disable everything before Vista, for now. - return !mozilla::IsVistaOrLater(); -} - -static bool -RandomizeIsBroken() -{ - // Use the compiler's intrinsic guards for |static type value = expr| to avoid some potential - // races if runtimes are created from multiple threads. - static int result = RandomizeIsBrokenImpl(); - return !!result; -} - -#ifdef JS_CPU_X64 -static js::JitExceptionHandler sJitExceptionHandler; - -JS_FRIEND_API(void) -js::SetJitExceptionHandler(JitExceptionHandler handler) -{ - MOZ_ASSERT(!sJitExceptionHandler); - sJitExceptionHandler = handler; -} - -// From documentation for UNWIND_INFO on -// http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx -struct UnwindInfo -{ - uint8_t version : 3; - uint8_t flags : 5; - uint8_t sizeOfPrologue; - uint8_t countOfUnwindCodes; - uint8_t frameRegister : 4; - uint8_t frameOffset : 4; - ULONG exceptionHandler; -}; - -static const unsigned ThunkLength = 12; - -struct ExceptionHandlerRecord -{ - RUNTIME_FUNCTION runtimeFunction; - UnwindInfo unwindInfo; - uint8_t thunk[ThunkLength]; -}; - -// This function must match the function pointer type PEXCEPTION_HANDLER -// mentioned in: -// http://msdn.microsoft.com/en-us/library/ssa62fwe.aspx. -// This type is rather elusive in documentation; Wine is the best I've found: -// http://source.winehq.org/source/include/winnt.h -static DWORD -ExceptionHandler(PEXCEPTION_RECORD exceptionRecord, _EXCEPTION_REGISTRATION_RECORD*, - PCONTEXT context, _EXCEPTION_REGISTRATION_RECORD**) -{ - return sJitExceptionHandler(exceptionRecord, context); -} - -// For an explanation of the problem being solved here, see -// SetJitExceptionFilter in jsfriendapi.h. -static bool -RegisterExecutableMemory(void* p, size_t bytes, size_t pageSize) -{ - ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p); - - // All these fields are specified to be offsets from the base of the - // executable code (which is 'p'), even if they have 'Address' in their - // names. In particular, exceptionHandler is a ULONG offset which is a - // 32-bit integer. Since 'p' can be farther than INT32_MAX away from - // sJitExceptionHandler, we must generate a little thunk inside the - // record. The record is put on its own page so that we can take away write - // access to protect against accidental clobbering. - - r->runtimeFunction.BeginAddress = pageSize; - r->runtimeFunction.EndAddress = (DWORD)bytes; - r->runtimeFunction.UnwindData = offsetof(ExceptionHandlerRecord, unwindInfo); - - r->unwindInfo.version = 1; - r->unwindInfo.flags = UNW_FLAG_EHANDLER; - r->unwindInfo.sizeOfPrologue = 0; - r->unwindInfo.countOfUnwindCodes = 0; - r->unwindInfo.frameRegister = 0; - r->unwindInfo.frameOffset = 0; - r->unwindInfo.exceptionHandler = offsetof(ExceptionHandlerRecord, thunk); - - // mov imm64, rax - r->thunk[0] = 0x48; - r->thunk[1] = 0xb8; - void* handler = JS_FUNC_TO_DATA_PTR(void*, ExceptionHandler); - memcpy(&r->thunk[2], &handler, 8); - - // jmp rax - r->thunk[10] = 0xff; - r->thunk[11] = 0xe0; - - DWORD oldProtect; - if (!VirtualProtect(p, pageSize, PAGE_EXECUTE_READ, &oldProtect)) - return false; - - return RtlAddFunctionTable(&r->runtimeFunction, 1, reinterpret_cast<DWORD64>(p)); -} - -static void -UnregisterExecutableMemory(void* p, size_t bytes, size_t pageSize) -{ - ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p); - RtlDeleteFunctionTable(&r->runtimeFunction); -} -#endif - -void* -js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag, - size_t pageSize) -{ - MOZ_ASSERT(bytes % pageSize == 0); - -#ifdef JS_CPU_X64 - if (sJitExceptionHandler) - bytes += pageSize; -#endif - - void* p = VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, permissions); - if (!p) - return nullptr; - -#ifdef JS_CPU_X64 - if (sJitExceptionHandler) { - if (!RegisterExecutableMemory(p, bytes, pageSize)) { - VirtualFree(p, 0, MEM_RELEASE); - return nullptr; - } - - p = (uint8_t*)p + pageSize; - } -#endif - - return p; -} - -void -js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize) -{ - MOZ_ASSERT(bytes % pageSize == 0); - -#ifdef JS_CPU_X64 - if (sJitExceptionHandler) { - addr = (uint8_t*)addr - pageSize; - UnregisterExecutableMemory(addr, bytes, pageSize); - } -#endif - - VirtualFree(addr, 0, MEM_RELEASE); -} - -ExecutablePool::Allocation -ExecutableAllocator::systemAlloc(size_t n) -{ - void* allocation = nullptr; - if (!RandomizeIsBroken()) { - void* randomAddress = computeRandomAllocationAddress(); - allocation = AllocateExecutableMemory(randomAddress, n, initialProtectionFlags(Executable), - "js-jit-code", pageSize); - } - if (!allocation) { - allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable), - "js-jit-code", pageSize); - } - ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n }; - return alloc; -} - -void -ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) -{ - DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize); -} - -void -ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) -{ - MOZ_ASSERT(nonWritableJitCode); - MOZ_ASSERT(pageSize); - - // Calculate the start of the page containing this region, - // and account for this extra memory within size. - intptr_t startPtr = reinterpret_cast<intptr_t>(start); - intptr_t pageStartPtr = startPtr & ~(pageSize - 1); - void* pageStart = reinterpret_cast<void*>(pageStartPtr); - size += (startPtr - pageStartPtr); - - // Round size up - size += (pageSize - 1); - size &= ~(pageSize - 1); - - DWORD oldProtect; - int flags = (setting == Writable) ? PAGE_READWRITE : PAGE_EXECUTE_READ; - if (!VirtualProtect(pageStart, size, flags, &oldProtect)) - MOZ_CRASH(); -} - -/* static */ unsigned -ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection) -{ - if (!nonWritableJitCode) - return PAGE_EXECUTE_READWRITE; - - return (protection == Writable) ? PAGE_READWRITE : PAGE_EXECUTE_READ; -} diff --git a/src/third_party/mozjs-45/extract/js/src/jit/Ion.cpp b/src/third_party/mozjs-45/extract/js/src/jit/Ion.cpp index 93d96c257c0..f47a413fc68 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/Ion.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/Ion.cpp @@ -722,13 +722,14 @@ JitCompartment::sweep(FreeOp* fop, JSCompartment* compartment) if (!stubCodes_->lookup(ICSetProp_Fallback::Compiler::BASELINE_KEY)) baselineSetPropReturnAddr_ = nullptr; - if (stringConcatStub_ && !IsMarkedUnbarriered(&stringConcatStub_)) + JSRuntime* rt = fop->runtime(); + if (stringConcatStub_ && !IsMarkedUnbarriered(rt, &stringConcatStub_)) stringConcatStub_ = nullptr; - if (regExpExecStub_ && !IsMarkedUnbarriered(®ExpExecStub_)) + if (regExpExecStub_ && !IsMarkedUnbarriered(rt, ®ExpExecStub_)) regExpExecStub_ = nullptr; - if (regExpTestStub_ && !IsMarkedUnbarriered(®ExpTestStub_)) + if (regExpTestStub_ && !IsMarkedUnbarriered(rt, ®ExpTestStub_)) regExpTestStub_ = nullptr; for (size_t i = 0; i <= SimdTypeDescr::LAST_TYPE; i++) { @@ -2413,6 +2414,11 @@ Compile(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode* if (optimizationLevel == Optimization_DontCompile) return Method_Skipped; + if (!CanLikelyAllocateMoreExecutableMemory()) { + script->resetWarmUpCounter(); + return Method_Skipped; + } + if (script->hasIonScript()) { IonScript* scriptIon = script->ionScript(); if (!scriptIon->method()) diff --git a/src/third_party/mozjs-45/extract/js/src/jit/IonAnalysis.cpp b/src/third_party/mozjs-45/extract/js/src/jit/IonAnalysis.cpp index 0dd337c2ecb..8a41afc51eb 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/IonAnalysis.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/IonAnalysis.cpp @@ -3673,6 +3673,9 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, TempAllocator temp(&alloc); JitContext jctx(cx, &temp); + if (!jit::CanLikelyAllocateMoreExecutableMemory()) + return true; + if (!cx->compartment()->ensureJitCompartmentExists(cx)) return false; @@ -3902,6 +3905,9 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg) TempAllocator temp(&alloc); JitContext jctx(cx, &temp); + if (!jit::CanLikelyAllocateMoreExecutableMemory()) + return true; + if (!cx->compartment()->ensureJitCompartmentExists(cx)) return false; diff --git a/src/third_party/mozjs-45/extract/js/src/jit/IonBuilder.cpp b/src/third_party/mozjs-45/extract/js/src/jit/IonBuilder.cpp index 3efc6bb0c11..9e70e244889 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/IonBuilder.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/IonBuilder.cpp @@ -1235,9 +1235,11 @@ IonBuilder::initScopeChain(MDefinition* callee) current->add(scope); // This reproduce what is done in CallObject::createForFunction. Skip - // this for analyses, as the script might not have a baseline script - // with template objects yet. - if (fun->needsCallObject() && !info().isAnalysis()) { + // this for the arguments analysis, as the script might not have a + // baseline script with template objects yet. + if (fun->needsCallObject() && + info().analysisMode() != Analysis_ArgumentsUsage) + { if (fun->isNamedLambda()) { scope = createDeclEnvObject(callee, scope); if (!scope) @@ -6135,6 +6137,9 @@ IonBuilder::getSingletonPrototype(JSFunction* target) MDefinition* IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee) { + if (!target->hasScript()) + return nullptr; + // Get the singleton prototype (if exists) JSObject* proto = getSingletonPrototype(target); if (!proto) diff --git a/src/third_party/mozjs-45/extract/js/src/jit/IonCaches.cpp b/src/third_party/mozjs-45/extract/js/src/jit/IonCaches.cpp index b5fe6dec072..56437abf613 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/IonCaches.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/IonCaches.cpp @@ -2418,9 +2418,20 @@ IsCacheableSetPropCallNative(HandleObject obj, HandleObject holder, HandleShape if (!shape || !IsCacheableProtoChainForIon(obj, holder)) return false; - return shape->hasSetterValue() && shape->setterObject() && - shape->setterObject()->is<JSFunction>() && - shape->setterObject()->as<JSFunction>().isNative(); + if (!shape->hasSetterValue()) + return false; + + if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>()) + return false; + + JSFunction& setter = shape->setterObject()->as<JSFunction>(); + if (!setter.isNative()) + return false; + + if (setter.jitInfo() && !setter.jitInfo()->needsOuterizedThisObject()) + return true; + + return !IsWindow(obj); } static bool @@ -2429,6 +2440,9 @@ IsCacheableSetPropCallScripted(HandleObject obj, HandleObject holder, HandleShap if (!shape || !IsCacheableProtoChainForIon(obj, holder)) return false; + if (IsWindow(obj)) + return false; + return shape->hasSetterValue() && shape->setterObject() && shape->setterObject()->is<JSFunction>() && shape->setterObject()->as<JSFunction>().hasJITCode(); diff --git a/src/third_party/mozjs-45/extract/js/src/jit/IonCode.h b/src/third_party/mozjs-45/extract/js/src/jit/IonCode.h index 085a9076c33..8156b9cb8f6 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/IonCode.h +++ b/src/third_party/mozjs-45/extract/js/src/jit/IonCode.h @@ -767,7 +767,7 @@ struct AutoFlushICache namespace gc { inline bool -IsMarked(const jit::VMFunction*) +IsMarked(JSRuntime* rt, const jit::VMFunction*) { // VMFunction are only static objects which are used by WeakMaps as keys. // It is considered as a root object which is always marked. diff --git a/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.cpp b/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.cpp index 7f6a06120d2..e8cba8e63a4 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.cpp @@ -756,7 +756,7 @@ JitcodeGlobalTable::setAllEntriesAsExpired(JSRuntime* rt) struct Unconditionally { template <typename T> - static bool ShouldMark(T* thingp) { return true; } + static bool ShouldMark(JSRuntime* rt, T* thingp) { return true; } }; void @@ -775,13 +775,13 @@ JitcodeGlobalTable::markUnconditionally(JSTracer* trc) struct IfUnmarked { template <typename T> - static bool ShouldMark(T* thingp) { return !IsMarkedUnbarriered(thingp); } + static bool ShouldMark(JSRuntime* rt, T* thingp) { return !IsMarkedUnbarriered(rt, thingp); } }; template <> -bool IfUnmarked::ShouldMark<TypeSet::Type>(TypeSet::Type* type) +bool IfUnmarked::ShouldMark<TypeSet::Type>(JSRuntime* rt, TypeSet::Type* type) { - return !TypeSet::IsTypeMarked(type); + return !TypeSet::IsTypeMarked(rt, type); } bool @@ -832,7 +832,7 @@ JitcodeGlobalTable::markIteratively(JSTracer* trc) // mapping, alive as well. if (!entry->isSampled(gen, lapCount)) { entry->setAsExpired(); - if (!entry->baseEntry().isJitcodeMarkedFromAnyThread()) + if (!entry->baseEntry().isJitcodeMarkedFromAnyThread(trc->runtime())) continue; } @@ -868,7 +868,7 @@ template <class ShouldMarkProvider> bool JitcodeGlobalEntry::BaseEntry::markJitcode(JSTracer* trc) { - if (ShouldMarkProvider::ShouldMark(&jitcode_)) { + if (ShouldMarkProvider::ShouldMark(trc->runtime(), &jitcode_)) { TraceManuallyBarrieredEdge(trc, &jitcode_, "jitcodglobaltable-baseentry-jitcode"); return true; } @@ -876,9 +876,9 @@ JitcodeGlobalEntry::BaseEntry::markJitcode(JSTracer* trc) } bool -JitcodeGlobalEntry::BaseEntry::isJitcodeMarkedFromAnyThread() +JitcodeGlobalEntry::BaseEntry::isJitcodeMarkedFromAnyThread(JSRuntime* rt) { - return IsMarkedUnbarriered(&jitcode_) || + return IsMarkedUnbarriered(rt, &jitcode_) || jitcode_->arenaHeader()->allocatedDuringIncremental; } @@ -892,7 +892,7 @@ template <class ShouldMarkProvider> bool JitcodeGlobalEntry::BaselineEntry::mark(JSTracer* trc) { - if (ShouldMarkProvider::ShouldMark(&script_)) { + if (ShouldMarkProvider::ShouldMark(trc->runtime(), &script_)) { TraceManuallyBarrieredEdge(trc, &script_, "jitcodeglobaltable-baselineentry-script"); return true; } @@ -906,9 +906,9 @@ JitcodeGlobalEntry::BaselineEntry::sweepChildren() } bool -JitcodeGlobalEntry::BaselineEntry::isMarkedFromAnyThread() +JitcodeGlobalEntry::BaselineEntry::isMarkedFromAnyThread(JSRuntime* rt) { - return IsMarkedUnbarriered(&script_) || + return IsMarkedUnbarriered(rt, &script_) || script_->arenaHeader()->allocatedDuringIncremental; } @@ -918,8 +918,9 @@ JitcodeGlobalEntry::IonEntry::mark(JSTracer* trc) { bool markedAny = false; + JSRuntime* rt = trc->runtime(); for (unsigned i = 0; i < numScripts(); i++) { - if (ShouldMarkProvider::ShouldMark(&sizedScriptList()->pairs[i].script)) { + if (ShouldMarkProvider::ShouldMark(rt, &sizedScriptList()->pairs[i].script)) { TraceManuallyBarrieredEdge(trc, &sizedScriptList()->pairs[i].script, "jitcodeglobaltable-ionentry-script"); markedAny = true; @@ -932,15 +933,15 @@ JitcodeGlobalEntry::IonEntry::mark(JSTracer* trc) for (IonTrackedTypeWithAddendum* iter = optsAllTypes_->begin(); iter != optsAllTypes_->end(); iter++) { - if (ShouldMarkProvider::ShouldMark(&iter->type)) { + if (ShouldMarkProvider::ShouldMark(rt, &iter->type)) { TypeSet::MarkTypeUnbarriered(trc, &iter->type, "jitcodeglobaltable-ionentry-type"); markedAny = true; } - if (iter->hasAllocationSite() && ShouldMarkProvider::ShouldMark(&iter->script)) { + if (iter->hasAllocationSite() && ShouldMarkProvider::ShouldMark(rt, &iter->script)) { TraceManuallyBarrieredEdge(trc, &iter->script, "jitcodeglobaltable-ionentry-type-addendum-script"); markedAny = true; - } else if (iter->hasConstructor() && ShouldMarkProvider::ShouldMark(&iter->constructor)) { + } else if (iter->hasConstructor() && ShouldMarkProvider::ShouldMark(rt, &iter->constructor)) { TraceManuallyBarrieredEdge(trc, &iter->constructor, "jitcodeglobaltable-ionentry-type-addendum-constructor"); markedAny = true; @@ -973,10 +974,10 @@ JitcodeGlobalEntry::IonEntry::sweepChildren() } bool -JitcodeGlobalEntry::IonEntry::isMarkedFromAnyThread() +JitcodeGlobalEntry::IonEntry::isMarkedFromAnyThread(JSRuntime* rt) { for (unsigned i = 0; i < numScripts(); i++) { - if (!IsMarkedUnbarriered(&sizedScriptList()->pairs[i].script) && + if (!IsMarkedUnbarriered(rt, &sizedScriptList()->pairs[i].script) && !sizedScriptList()->pairs[i].script->arenaHeader()->allocatedDuringIncremental) { return false; @@ -989,7 +990,7 @@ JitcodeGlobalEntry::IonEntry::isMarkedFromAnyThread() for (IonTrackedTypeWithAddendum* iter = optsAllTypes_->begin(); iter != optsAllTypes_->end(); iter++) { - if (!TypeSet::IsTypeMarked(&iter->type) && + if (!TypeSet::IsTypeMarked(rt, &iter->type) && !TypeSet::IsTypeAllocatedDuringIncremental(iter->type)) { return false; diff --git a/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.h b/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.h index 01c475adecb..e11126321d3 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.h +++ b/src/third_party/mozjs-45/extract/js/src/jit/JitcodeMap.h @@ -208,7 +208,7 @@ class JitcodeGlobalEntry } template <class ShouldMarkProvider> bool markJitcode(JSTracer* trc); - bool isJitcodeMarkedFromAnyThread(); + bool isJitcodeMarkedFromAnyThread(JSRuntime* rt); bool isJitcodeAboutToBeFinalized(); }; @@ -370,7 +370,7 @@ class JitcodeGlobalEntry template <class ShouldMarkProvider> bool mark(JSTracer* trc); void sweepChildren(); - bool isMarkedFromAnyThread(); + bool isMarkedFromAnyThread(JSRuntime* rt); }; struct BaselineEntry : public BaseEntry @@ -428,7 +428,7 @@ class JitcodeGlobalEntry template <class ShouldMarkProvider> bool mark(JSTracer* trc); void sweepChildren(); - bool isMarkedFromAnyThread(); + bool isMarkedFromAnyThread(JSRuntime* rt); }; struct IonCacheEntry : public BaseEntry @@ -949,13 +949,13 @@ class JitcodeGlobalEntry } bool isMarkedFromAnyThread(JSRuntime* rt) { - if (!baseEntry().isJitcodeMarkedFromAnyThread()) + if (!baseEntry().isJitcodeMarkedFromAnyThread(rt)) return false; switch (kind()) { case Ion: - return ionEntry().isMarkedFromAnyThread(); + return ionEntry().isMarkedFromAnyThread(rt); case Baseline: - return baselineEntry().isMarkedFromAnyThread(); + return baselineEntry().isMarkedFromAnyThread(rt); case IonCache: return ionCacheEntry().isMarkedFromAnyThread(rt); case Dummy: diff --git a/src/third_party/mozjs-45/extract/js/src/jit/Lowering.cpp b/src/third_party/mozjs-45/extract/js/src/jit/Lowering.cpp index 64f86f38f22..f1fc578f207 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/Lowering.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/Lowering.cpp @@ -2310,9 +2310,7 @@ LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) // is complicated because there could be another AutoWritableJitCode on the // stack. LInstructionHelper<0, 0, 0>* lir; - if (GetJitContext()->runtime->canUseSignalHandlers() && - !ExecutableAllocator::nonWritableJitCode) - { + if (GetJitContext()->runtime->canUseSignalHandlers()) { lir = new(alloc()) LInterruptCheckImplicit(); } else { lir = new(alloc()) LInterruptCheck(); diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.cpp b/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.cpp new file mode 100644 index 00000000000..7e05dfc84f1 --- /dev/null +++ b/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.cpp @@ -0,0 +1,614 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +#include "jit/ProcessExecutableMemory.h" + +#include "mozilla/Array.h" +#include "mozilla/Atomics.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Maybe.h" +#include "mozilla/TaggedAnonymousMemory.h" +#include "mozilla/XorShift128PlusRNG.h" + +#include "jsfriendapi.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsutil.h" +#include "jswin.h" + +#include <errno.h> + +#include "gc/Memory.h" + +#ifdef XP_WIN +# include "mozilla/WindowsVersion.h" +#else +# include <sys/mman.h> +# include <unistd.h> +#endif + +using namespace js; +using namespace js::jit; + +#ifdef XP_WIN +static void* +ComputeRandomAllocationAddress() +{ + /* + * Inspiration is V8's OS::Allocate in platform-win32.cc. + * + * VirtualAlloc takes 64K chunks out of the virtual address space, so we + * keep 16b alignment. + * + * x86: V8 comments say that keeping addresses in the [64MiB, 1GiB) range + * tries to avoid system default DLL mapping space. In the end, we get 13 + * bits of randomness in our selection. + * x64: [2GiB, 4TiB), with 25 bits of randomness. + */ +# ifdef HAVE_64BIT_BUILD + static const uintptr_t base = 0x0000000080000000; + static const uintptr_t mask = 0x000003ffffff0000; +# elif defined(_M_IX86) || defined(__i386__) + static const uintptr_t base = 0x04000000; + static const uintptr_t mask = 0x3fff0000; +# else +# error "Unsupported architecture" +# endif + + uint64_t rand = js::GenerateRandomSeed(); + return (void*) (base | (rand & mask)); +} + +# ifdef HAVE_64BIT_BUILD +static js::JitExceptionHandler sJitExceptionHandler; + +JS_FRIEND_API(void) +js::SetJitExceptionHandler(JitExceptionHandler handler) +{ + MOZ_ASSERT(!sJitExceptionHandler); + sJitExceptionHandler = handler; +} + +// From documentation for UNWIND_INFO on +// http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx +struct UnwindInfo +{ + uint8_t version : 3; + uint8_t flags : 5; + uint8_t sizeOfPrologue; + uint8_t countOfUnwindCodes; + uint8_t frameRegister : 4; + uint8_t frameOffset : 4; + ULONG exceptionHandler; +}; + +static const unsigned ThunkLength = 12; + +struct ExceptionHandlerRecord +{ + RUNTIME_FUNCTION runtimeFunction; + UnwindInfo unwindInfo; + uint8_t thunk[ThunkLength]; +}; + +// This function must match the function pointer type PEXCEPTION_HANDLER +// mentioned in: +// http://msdn.microsoft.com/en-us/library/ssa62fwe.aspx. +// This type is rather elusive in documentation; Wine is the best I've found: +// http://source.winehq.org/source/include/winnt.h +static DWORD +ExceptionHandler(PEXCEPTION_RECORD exceptionRecord, _EXCEPTION_REGISTRATION_RECORD*, + PCONTEXT context, _EXCEPTION_REGISTRATION_RECORD**) +{ + return sJitExceptionHandler(exceptionRecord, context); +} + +// For an explanation of the problem being solved here, see +// SetJitExceptionFilter in jsfriendapi.h. +static bool +RegisterExecutableMemory(void* p, size_t bytes, size_t pageSize) +{ + if (!VirtualAlloc(p, pageSize, MEM_COMMIT, PAGE_READWRITE)) + MOZ_CRASH(); + + ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p); + + // All these fields are specified to be offsets from the base of the + // executable code (which is 'p'), even if they have 'Address' in their + // names. In particular, exceptionHandler is a ULONG offset which is a + // 32-bit integer. Since 'p' can be farther than INT32_MAX away from + // sJitExceptionHandler, we must generate a little thunk inside the + // record. The record is put on its own page so that we can take away write + // access to protect against accidental clobbering. + + r->runtimeFunction.BeginAddress = pageSize; + r->runtimeFunction.EndAddress = (DWORD)bytes; + r->runtimeFunction.UnwindData = offsetof(ExceptionHandlerRecord, unwindInfo); + + r->unwindInfo.version = 1; + r->unwindInfo.flags = UNW_FLAG_EHANDLER; + r->unwindInfo.sizeOfPrologue = 0; + r->unwindInfo.countOfUnwindCodes = 0; + r->unwindInfo.frameRegister = 0; + r->unwindInfo.frameOffset = 0; + r->unwindInfo.exceptionHandler = offsetof(ExceptionHandlerRecord, thunk); + + // mov imm64, rax + r->thunk[0] = 0x48; + r->thunk[1] = 0xb8; + void* handler = JS_FUNC_TO_DATA_PTR(void*, ExceptionHandler); + memcpy(&r->thunk[2], &handler, 8); + + // jmp rax + r->thunk[10] = 0xff; + r->thunk[11] = 0xe0; + + DWORD oldProtect; + if (!VirtualProtect(p, pageSize, PAGE_EXECUTE_READ, &oldProtect)) + MOZ_CRASH(); + + bool success = RtlAddFunctionTable(&r->runtimeFunction, 1, reinterpret_cast<DWORD64>(p)); + + return success; +} + +static void +UnregisterExecutableMemory(void* p, size_t bytes, size_t pageSize) +{ + ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p); + + RtlDeleteFunctionTable(&r->runtimeFunction); +} +# endif + +static void* +ReserveProcessExecutableMemory(size_t bytes) +{ +# ifdef HAVE_64BIT_BUILD + size_t pageSize = gc::SystemPageSize(); + if (sJitExceptionHandler) + bytes += pageSize; +# endif + + void* p = nullptr; + for (size_t i = 0; i < 10; i++) { + void* randomAddr = ComputeRandomAllocationAddress(); + p = VirtualAlloc(randomAddr, bytes, MEM_RESERVE, PAGE_NOACCESS); + if (p) + break; + } + + if (!p) { + // Try again without randomization. + p = VirtualAlloc(nullptr, bytes, MEM_RESERVE, PAGE_NOACCESS); + if (!p) + return nullptr; + } + +# ifdef HAVE_64BIT_BUILD + if (sJitExceptionHandler) { + if (!RegisterExecutableMemory(p, bytes, pageSize)) { + VirtualFree(p, 0, MEM_RELEASE); + return nullptr; + } + + p = (uint8_t*)p + pageSize; + } +# endif + + return p; +} + +static void +DeallocateProcessExecutableMemory(void* addr, size_t bytes) +{ +# ifdef HAVE_64BIT_BUILD + if (sJitExceptionHandler) { + size_t pageSize = gc::SystemPageSize(); + addr = (uint8_t*)addr - pageSize; + UnregisterExecutableMemory(addr, bytes, pageSize); + } +# endif + + VirtualFree(addr, 0, MEM_RELEASE); +} + +static DWORD +ProtectionSettingToFlags(ProtectionSetting protection) +{ + return PAGE_EXECUTE_READWRITE; +} + +static void +CommitPages(void* addr, size_t bytes, ProtectionSetting protection) +{ + if (!VirtualAlloc(addr, bytes, MEM_COMMIT, ProtectionSettingToFlags(protection))) + MOZ_CRASH("CommitPages failed"); +} + +static void +DecommitPages(void* addr, size_t bytes) +{ + if (!VirtualFree(addr, bytes, MEM_DECOMMIT)) + MOZ_CRASH("DecommitPages failed"); +} +#else // !XP_WIN +static void* +ComputeRandomAllocationAddress() +{ + uint64_t rand = js::GenerateRandomSeed(); + +# ifdef HAVE_64BIT_BUILD + // x64 CPUs have a 48-bit address space and on some platforms the OS will + // give us access to 47 bits, so to be safe we right shift by 18 to leave + // 46 bits. + rand >>= 18; +# else + // On 32-bit, right shift by 34 to leave 30 bits, range [0, 1GiB). Then add + // 512MiB to get range [512MiB, 1.5GiB), or [0x20000000, 0x60000000). This + // is based on V8 comments in platform-posix.cc saying this range is + // relatively unpopulated across a variety of kernels. + rand >>= 34; + rand += 512 * 1024 * 1024; +# endif + + // Ensure page alignment. + uintptr_t mask = ~uintptr_t(gc::SystemPageSize() - 1); + return (void*) uintptr_t(rand & mask); +} + +static void* +ReserveProcessExecutableMemory(size_t bytes) +{ + // Note that randomAddr is just a hint: if the address is not available + // mmap will pick a different address. + void* randomAddr = ComputeRandomAllocationAddress(); +#ifdef SOLARIS + // Do not reserve swap space for the entire allocation. Regardless of what mmap(2) says, + // Solaris reserves swap space even though this allocation is not marked as writable. + void* p = MozTaggedAnonymousMmap(randomAddr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, 0, "js-executable-memory"); +#else + void* p = MozTaggedAnonymousMmap(randomAddr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0, "js-executable-memory"); +#endif + if (p == MAP_FAILED) + return nullptr; + return p; +} + +static void +DeallocateProcessExecutableMemory(void* addr, size_t bytes) +{ + mozilla::DebugOnly<int> result = munmap(addr, bytes); + MOZ_ASSERT(!result || errno == ENOMEM); +} + +static unsigned +ProtectionSettingToFlags(ProtectionSetting protection) +{ + return PROT_READ | PROT_WRITE | PROT_EXEC; +} + +static void +CommitPages(void* addr, size_t bytes, ProtectionSetting protection) +{ + void* p = MozTaggedAnonymousMmap(addr, bytes, ProtectionSettingToFlags(protection), + MAP_FIXED | MAP_PRIVATE | MAP_ANON, + -1, 0, "js-executable-memory"); + MOZ_RELEASE_ASSERT(addr == p); +} + +static void +DecommitPages(void* addr, size_t bytes) +{ + // Use mmap with MAP_FIXED and PROT_NONE. Inspired by jemalloc's + // pages_decommit. + void* p = MozTaggedAnonymousMmap(addr, bytes, PROT_NONE, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, + -1, 0, "js-executable-memory"); + MOZ_RELEASE_ASSERT(addr == p); +} +#endif + +template <size_t NumBits> +class PageBitSet +{ + using WordType = uint32_t; + static const size_t BitsPerWord = sizeof(WordType) * 8; + + static_assert((NumBits % BitsPerWord) == 0, + "NumBits must be a multiple of BitsPerWord"); + static const size_t NumWords = NumBits / BitsPerWord; + + mozilla::Array<WordType, NumWords> words_; + + uint32_t indexToWord(uint32_t index) const { + MOZ_ASSERT(index < NumBits); + return index / BitsPerWord; + } + WordType indexToBit(uint32_t index) const { + MOZ_ASSERT(index < NumBits); + return WordType(1) << (index % BitsPerWord); + } + + public: + void init() { + mozilla::PodArrayZero(words_); + } + bool contains(size_t index) const { + uint32_t word = indexToWord(index); + return words_[word] & indexToBit(index); + } + void insert(size_t index) { + MOZ_ASSERT(!contains(index)); + uint32_t word = indexToWord(index); + words_[word] |= indexToBit(index); + } + void remove(size_t index) { + MOZ_ASSERT(contains(index)); + uint32_t word = indexToWord(index); + words_[word] &= ~indexToBit(index); + } + +#ifdef DEBUG + bool empty() const { + for (size_t i = 0; i < NumWords; i++) { + if (words_[i] != 0) + return false; + } + return true; + } +#endif +}; + +// Limit on the number of bytes of executable memory to prevent JIT spraying +// attacks. +#if JS_BITS_PER_WORD == 32 +static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; +#else +static const size_t MaxCodeBytesPerProcess = 640 * 1024 * 1024; +#endif + +// Per-process executable memory allocator. It reserves a block of memory of +// MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that. +// +// This has a number of benefits compared to raw mmap/VirtualAlloc: +// +// * More resillient against certain attacks. +// +// * Behaves more consistently across platforms: it avoids the 64K granularity +// issues on Windows, for instance. +// +// * On x64, near jumps can be used for jumps to other JIT pages. +// +// * On Win64, we have to register the exception handler only once (at process +// startup). This saves some memory and avoids RtlAddFunctionTable profiler +// deadlocks. +class ProcessExecutableMemory +{ + static_assert((MaxCodeBytesPerProcess % ExecutableCodePageSize) == 0, + "MaxCodeBytesPerProcess must be a multiple of ExecutableCodePageSize"); + static const size_t MaxCodePages = MaxCodeBytesPerProcess / ExecutableCodePageSize; + + // Start of the MaxCodeBytesPerProcess memory block or nullptr if + // uninitialized. Note that this is NOT guaranteed to be aligned to + // ExecutableCodePageSize. + uint8_t* base_; + + // The fields below should only be accessed while we hold the lock. + PRLock* lock_; + + // pagesAllocated_ is an Atomic so that bytesAllocated does not have to + // take the lock. + mozilla::Atomic<size_t, mozilla::ReleaseAcquire> pagesAllocated_; + + // Page where we should try to allocate next. + size_t cursor_; + + mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> rng_; + PageBitSet<MaxCodePages> pages_; + + public: + ProcessExecutableMemory() + : base_(nullptr), + lock_(nullptr), + pagesAllocated_(0), + cursor_(0), + rng_(), + pages_() + {} + + MOZ_MUST_USE bool init() { + pages_.init(); + + MOZ_RELEASE_ASSERT(!initialized()); + MOZ_RELEASE_ASSERT(gc::SystemPageSize() <= ExecutableCodePageSize); + + lock_ = PR_NewLock(); + if (!lock_) + return false; + + void* p = ReserveProcessExecutableMemory(MaxCodeBytesPerProcess); + if (!p) + return false; + + base_ = static_cast<uint8_t*>(p); + + mozilla::Array<uint64_t, 2> seed; + GenerateXorShift128PlusSeed(seed); + rng_.emplace(seed[0], seed[1]); + return true; + } + + bool initialized() const { + return base_ != nullptr; + } + + size_t bytesAllocated() const { + MOZ_ASSERT(pagesAllocated_ <= MaxCodePages); + return pagesAllocated_ * ExecutableCodePageSize; + } + + void release() { + MOZ_ASSERT(initialized()); + MOZ_ASSERT(pages_.empty()); + MOZ_ASSERT(pagesAllocated_ == 0); + DeallocateProcessExecutableMemory(base_, MaxCodeBytesPerProcess); + base_ = nullptr; + rng_.reset(); + MOZ_ASSERT(lock_); + PR_DestroyLock(lock_); + lock_ = nullptr; + MOZ_ASSERT(!initialized()); + } + + void assertValidAddress(void* p, size_t bytes) const { + MOZ_RELEASE_ASSERT(p >= base_ && + uintptr_t(p) + bytes <= uintptr_t(base_) + MaxCodeBytesPerProcess); + } + + void* allocate(size_t bytes, ProtectionSetting protection); + void deallocate(void* addr, size_t bytes); +}; + +void* +ProcessExecutableMemory::allocate(size_t bytes, ProtectionSetting protection) +{ + MOZ_ASSERT(initialized()); + MOZ_ASSERT(bytes > 0); + MOZ_ASSERT((bytes % ExecutableCodePageSize) == 0); + + size_t numPages = bytes / ExecutableCodePageSize; + + // Take the lock and try to allocate. + void* p = nullptr; + { + PR_Lock(lock_); + MOZ_ASSERT(pagesAllocated_ <= MaxCodePages); + + // Check if we have enough pages available. + if (pagesAllocated_ + numPages >= MaxCodePages) { + PR_Unlock(lock_); + return nullptr; + } + + MOZ_ASSERT(bytes <= MaxCodeBytesPerProcess); + + // Maybe skip a page to make allocations less predictable. + size_t page = cursor_ + (rng_.ref().next() % 2); + + for (size_t i = 0; i < MaxCodePages; i++) { + // Make sure page + numPages - 1 is a valid index. + if (page + numPages > MaxCodePages) + page = 0; + + bool available = true; + for (size_t j = 0; j < numPages; j++) { + if (pages_.contains(page + j)) { + available = false; + break; + } + } + if (!available) { + page++; + continue; + } + + // Mark the pages as unavailable. + for (size_t j = 0; j < numPages; j++) + pages_.insert(page + j); + + pagesAllocated_ += numPages; + MOZ_ASSERT(pagesAllocated_ <= MaxCodePages); + + // If we allocated a small number of pages, move cursor_ to the + // next page. We don't do this for larger allocations to avoid + // skipping a large number of small holes. + if (numPages <= 2) + cursor_ = page + numPages; + + p = base_ + page * ExecutableCodePageSize; + break; + } + PR_Unlock(lock_); + if (!p) + return nullptr; + } + + // Commit the pages after releasing the lock. + CommitPages(p, bytes, protection); + return p; +} + +void +ProcessExecutableMemory::deallocate(void* addr, size_t bytes) +{ + MOZ_ASSERT(initialized()); + MOZ_ASSERT(addr); + MOZ_ASSERT((uintptr_t(addr) % gc::SystemPageSize()) == 0); + MOZ_ASSERT(bytes > 0); + MOZ_ASSERT((bytes % ExecutableCodePageSize) == 0); + + assertValidAddress(addr, bytes); + + size_t firstPage = (static_cast<uint8_t*>(addr) - base_) / ExecutableCodePageSize; + size_t numPages = bytes / ExecutableCodePageSize; + + // Decommit before taking the lock. + DecommitPages(addr, bytes); + + PR_Lock(lock_); + MOZ_ASSERT(numPages <= pagesAllocated_); + pagesAllocated_ -= numPages; + + for (size_t i = 0; i < numPages; i++) + pages_.remove(firstPage + i); + + // Move the cursor back so we can reuse pages instead of fragmenting the + // whole region. + if (firstPage < cursor_) + cursor_ = firstPage; + + PR_Unlock(lock_); +} + +static ProcessExecutableMemory execMemory; + +void* +js::jit::AllocateExecutableMemory(size_t bytes, ProtectionSetting protection) +{ + return execMemory.allocate(bytes, protection); +} + +void +js::jit::DeallocateExecutableMemory(void* addr, size_t bytes) +{ + execMemory.deallocate(addr, bytes); +} + +bool +js::jit::InitProcessExecutableMemory() +{ + return execMemory.init(); +} + +void +js::jit::ReleaseProcessExecutableMemory() +{ + execMemory.release(); +} + +bool +js::jit::CanLikelyAllocateMoreExecutableMemory() +{ + // Use a 16 MB buffer. + static const size_t BufferSize = 16 * 1024 * 1024; + + MOZ_ASSERT(execMemory.bytesAllocated() <= MaxCodeBytesPerProcess); + + return execMemory.bytesAllocated() + BufferSize <= MaxCodeBytesPerProcess; +} diff --git a/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.h b/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.h new file mode 100644 index 00000000000..7884706e3bd --- /dev/null +++ b/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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 jit_ProcessExecutableMemory_h +#define jit_ProcessExecutableMemory_h + +#include "mozilla/Attributes.h" + +namespace js { +namespace jit { + +// Executable code is allocated in 64K chunks. ExecutableAllocator uses pools +// that are at least this big. Code we allocate does not necessarily have 64K +// alignment though. +static const size_t ExecutableCodePageSize = 64 * 1024; + +enum class ProtectionSetting { + Protected, // Not readable, writable, or executable. + Writable, + Executable, +}; + +// Functions called at process start-up/shutdown to initialize/release the +// executable memory region. +extern MOZ_MUST_USE bool InitProcessExecutableMemory(); +extern void ReleaseProcessExecutableMemory(); + +// Allocate/deallocate executable pages. +extern void* AllocateExecutableMemory(size_t bytes, ProtectionSetting protection); +extern void DeallocateExecutableMemory(void* addr, size_t bytes); + +// Returns true if we can allocate a few more MB of executable code without +// hitting our code limit. This function can be used to stop compiling things +// that are optional (like Baseline and Ion code) when we're about to reach the +// limit, so we are less likely to OOM or crash. Note that the limit is +// per-process, so other threads can also allocate code after we call this +// function. +extern bool CanLikelyAllocateMoreExecutableMemory(); + +} // namespace jit +} // namespace js + +#endif // jit_ProcessExecutableMemory_h diff --git a/src/third_party/mozjs-45/extract/js/src/jit/SharedIC.cpp b/src/third_party/mozjs-45/extract/js/src/jit/SharedIC.cpp index 2867776f0af..3d3a30f4813 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/SharedIC.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/SharedIC.cpp @@ -2448,6 +2448,14 @@ IsCacheableGetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh return false; JSFunction* func = &shape->getterObject()->as<JSFunction>(); + if (IsWindow(obj)) { + if (!func->isNative()) + return false; + + if (!func->jitInfo() || func->jitInfo()->needsOuterizedThisObject()) + return false; + } + if (func->isNative()) { *isScripted = false; return true; diff --git a/src/third_party/mozjs-45/extract/js/src/jit/VMFunctions.cpp b/src/third_party/mozjs-45/extract/js/src/jit/VMFunctions.cpp index 6eda48e0a5f..1296b52fec5 100644 --- a/src/third_party/mozjs-45/extract/js/src/jit/VMFunctions.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jit/VMFunctions.cpp @@ -1208,14 +1208,18 @@ AssertValidStringPtr(JSContext* cx, JSString* str) MOZ_ASSERT(str->length() <= JSString::MAX_LENGTH); gc::AllocKind kind = str->getAllocKind(); - if (str->isFatInline()) - MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING); - else if (str->isExternal()) + if (str->isFatInline()) { + MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING || + kind == gc::AllocKind::FAT_INLINE_ATOM); + } else if (str->isExternal()) { MOZ_ASSERT(kind == gc::AllocKind::EXTERNAL_STRING); - else if (str->isAtom() || str->isFlat()) + } else if (str->isAtom()) { + MOZ_ASSERT(kind == gc::AllocKind::ATOM); + } else if (str->isFlat()) { MOZ_ASSERT(kind == gc::AllocKind::STRING || kind == gc::AllocKind::FAT_INLINE_STRING); - else + } else { MOZ_ASSERT(kind == gc::AllocKind::STRING); + } #endif } diff --git a/src/third_party/mozjs-45/extract/js/src/jsarray.cpp b/src/third_party/mozjs-45/extract/js/src/jsarray.cpp index 59384b3fd4b..1131720cb72 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsarray.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsarray.cpp @@ -1882,6 +1882,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) undefs = 0; bool allStrings = true; bool allInts = true; + bool extraIndexed = ObjectMayHaveExtraIndexedProperties(obj); RootedValue v(cx); for (uint32_t i = 0; i < len; i++) { if (!CheckForInterrupt(cx)) @@ -1914,7 +1915,10 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) } /* Here len == n + undefs + number_of_holes. */ + bool defaultOrMatch; if (fval.isNull()) { + defaultOrMatch = true; + /* * Sort using the default comparator converting all elements to * strings. @@ -1938,6 +1942,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) if (comp == Match_Failure) return false; + defaultOrMatch = comp != Match_None; if (comp != Match_None) { if (allInts) { JS_ALWAYS_TRUE(vec.resize(n * 2)); @@ -1958,7 +1963,10 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) } } - if (!InitArrayElements(cx, obj, 0, uint32_t(n), vec.begin(), ShouldUpdateTypes::DontUpdate)) + ShouldUpdateTypes updateTypes = !extraIndexed && (allStrings || allInts) && defaultOrMatch + ? ShouldUpdateTypes::DontUpdate + : ShouldUpdateTypes::Update; + if (!InitArrayElements(cx, obj, 0, uint32_t(n), vec.begin(), updateTypes)) return false; } diff --git a/src/third_party/mozjs-45/extract/js/src/jsatom.cpp b/src/third_party/mozjs-45/extract/js/src/jsatom.cpp index 3d3c0e4d821..65f1deffbf9 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsatom.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsatom.cpp @@ -340,7 +340,8 @@ AtomizeAndCopyChars(ExclusiveContext* cx, const CharT* tbchars, size_t length, P return nullptr; } - JSAtom* atom = flat->morphAtomizedStringIntoAtom(); + JSAtom* atom = flat->morphAtomizedStringIntoAtom(lookup.hash); + MOZ_ASSERT(atom->hash() == lookup.hash); // We have held the lock since looking up p, and the operations we've done // since then can't GC; therefore the atoms table has not been modified and diff --git a/src/third_party/mozjs-45/extract/js/src/jsatom.h b/src/third_party/mozjs-45/extract/js/src/jsatom.h index ed1a6c9adf8..48d3c0ef9cf 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsatom.h +++ b/src/third_party/mozjs-45/extract/js/src/jsatom.h @@ -23,25 +23,6 @@ class JSAutoByteString; namespace js { -JS_STATIC_ASSERT(sizeof(HashNumber) == 4); - -static MOZ_ALWAYS_INLINE js::HashNumber -HashId(jsid id) -{ - return mozilla::HashGeneric(JSID_BITS(id)); -} - -struct JsidHasher -{ - typedef jsid Lookup; - static HashNumber hash(const Lookup& l) { - return HashNumber(JSID_BITS(l)); - } - static bool match(const jsid& id, const Lookup& l) { - return id == l; - } -}; - /* * Return a printable, lossless char[] representation of a string-type atom. * The lifetime of the result matches the lifetime of bytes. diff --git a/src/third_party/mozjs-45/extract/js/src/jsatominlines.h b/src/third_party/mozjs-45/extract/js/src/jsatominlines.h index 2fb7d35aa0a..216a91071e2 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsatominlines.h +++ b/src/third_party/mozjs-45/extract/js/src/jsatominlines.h @@ -156,12 +156,13 @@ inline AtomHasher::Lookup::Lookup(const JSAtom* atom) : isLatin1(atom->hasLatin1Chars()), length(atom->length()), atom(atom) { + hash = atom->hash(); if (isLatin1) { latin1Chars = atom->latin1Chars(nogc); - hash = mozilla::HashString(latin1Chars, length); + MOZ_ASSERT(mozilla::HashString(latin1Chars, length) == hash); } else { twoByteChars = atom->twoByteChars(nogc); - hash = mozilla::HashString(twoByteChars, length); + MOZ_ASSERT(mozilla::HashString(twoByteChars, length) == hash); } } @@ -171,7 +172,7 @@ AtomHasher::match(const AtomStateEntry& entry, const Lookup& lookup) JSAtom* key = entry.asPtr(); if (lookup.atom) return lookup.atom == key; - if (key->length() != lookup.length) + if (key->length() != lookup.length || key->hash() != lookup.hash) return false; if (key->hasLatin1Chars()) { diff --git a/src/third_party/mozjs-45/extract/js/src/jscntxt.h b/src/third_party/mozjs-45/extract/js/src/jscntxt.h index 0f70509d67f..89bf2863503 100644 --- a/src/third_party/mozjs-45/extract/js/src/jscntxt.h +++ b/src/third_party/mozjs-45/extract/js/src/jscntxt.h @@ -12,6 +12,7 @@ #include "mozilla/MemoryReporting.h" #include "js/TraceableVector.h" +#include "js/Utility.h" #include "js/Vector.h" #include "vm/Runtime.h" diff --git a/src/third_party/mozjs-45/extract/js/src/jscompartment.cpp b/src/third_party/mozjs-45/extract/js/src/jscompartment.cpp index c0d41ce8037..0d72551ef4b 100644 --- a/src/third_party/mozjs-45/extract/js/src/jscompartment.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jscompartment.cpp @@ -46,6 +46,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = runtime_(zone->runtimeFromMainThread()), principals_(nullptr), isSystem_(false), + isAtomsCompartment_(false), isSelfHosting(false), marked(true), warnedAboutFlagsArgument(false), @@ -72,6 +73,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = gcIncomingGrayPointers(nullptr), gcPreserveJitCode(options.preserveJitCode()), debugModeBits(0), + randomKeyGenerator_(runtime_->forkRandomKeyGenerator()), watchpointMap(nullptr), scriptCountsMap(nullptr), debugScriptMap(nullptr), @@ -157,6 +159,12 @@ JSRuntime::createJitRuntime(JSContext* cx) MOZ_ASSERT(!jitRuntime_); + if (!CanLikelyAllocateMoreExecutableMemory()) { + // Report OOM instead of potentially hitting the MOZ_CRASH below. + ReportOutOfMemory(cx); + return nullptr; + } + jit::JitRuntime* jrt = cx->new_<jit::JitRuntime>(); if (!jrt) return nullptr; @@ -1168,6 +1176,20 @@ JSCompartment::addTelemetry(const char* filename, DeprecatedLanguageExtension e) sawDeprecatedLanguageExtension[e] = true; } +HashNumber +JSCompartment::randomHashCode() +{ + ensureRandomNumberGenerator(); + return HashNumber(randomNumberGenerator.ref().next()); +} + +mozilla::HashCodeScrambler +JSCompartment::randomHashCodeScrambler() +{ + return mozilla::HashCodeScrambler(randomKeyGenerator_.next(), + randomKeyGenerator_.next()); +} + AutoSetNewObjectMetadata::AutoSetNewObjectMetadata(ExclusiveContext* ecx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) : CustomAutoRooter(ecx) diff --git a/src/third_party/mozjs-45/extract/js/src/jscompartment.h b/src/third_party/mozjs-45/extract/js/src/jscompartment.h index 96938211507..de5592fd65a 100644 --- a/src/third_party/mozjs-45/extract/js/src/jscompartment.h +++ b/src/third_party/mozjs-45/extract/js/src/jscompartment.h @@ -270,9 +270,19 @@ struct JSCompartment performanceMonitoring.unlink(); isSystem_ = isSystem; } + + bool isAtomsCompartment() const { + return isAtomsCompartment_; + } + void setIsAtomsCompartment() { + isAtomsCompartment_ = true; + } + private: JSPrincipals* principals_; bool isSystem_; + bool isAtomsCompartment_; + public: bool isSelfHosting; bool marked; @@ -601,6 +611,14 @@ struct JSCompartment void ensureRandomNumberGenerator(); private: + mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_; + + public: + js::HashNumber randomHashCode(); + + mozilla::HashCodeScrambler randomHashCodeScrambler(); + + private: JSCompartment* thisForCtor() { return this; } public: diff --git a/src/third_party/mozjs-45/extract/js/src/jsgc.cpp b/src/third_party/mozjs-45/extract/js/src/jsgc.cpp index 610fd78b0b6..776ebef6563 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsgc.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsgc.cpp @@ -238,6 +238,7 @@ using namespace js; using namespace js::gc; using mozilla::ArrayLength; +using mozilla::HashCodeScrambler; using mozilla::Maybe; using mozilla::Swap; @@ -291,6 +292,8 @@ const uint32_t Arena::ThingSizes[] = CHECK_MIN_THING_SIZE( sizeof(JSFatInlineString), /* AllocKind::FAT_INLINE_STRING */ sizeof(JSString), /* AllocKind::STRING */ sizeof(JSExternalString), /* AllocKind::EXTERNAL_STRING */ + sizeof(js::FatInlineAtom), /* AllocKind::FAT_INLINE_ATOM */ + sizeof(js::NormalAtom), /* AllocKind::ATOM */ sizeof(JS::Symbol), /* AllocKind::SYMBOL */ sizeof(jit::JitCode), /* AllocKind::JITCODE */ ); @@ -324,6 +327,8 @@ const uint32_t Arena::FirstThingOffsets[] = { OFFSET(JSFatInlineString), /* AllocKind::FAT_INLINE_STRING */ OFFSET(JSString), /* AllocKind::STRING */ OFFSET(JSExternalString), /* AllocKind::EXTERNAL_STRING */ + OFFSET(js::FatInlineAtom), /* AllocKind::FAT_INLINE_ATOM */ + OFFSET(js::NormalAtom), /* AllocKind::ATOM */ OFFSET(JS::Symbol), /* AllocKind::SYMBOL */ OFFSET(jit::JitCode), /* AllocKind::JITCODE */ }; @@ -380,6 +385,8 @@ static const AllocKind BackgroundPhaseObjects[] = { static const AllocKind BackgroundPhaseStringsAndSymbols[] = { AllocKind::FAT_INLINE_STRING, AllocKind::STRING, + AllocKind::FAT_INLINE_ATOM, + AllocKind::ATOM, AllocKind::SYMBOL }; @@ -633,6 +640,10 @@ FinalizeArenas(FreeOp* fop, return FinalizeTypedArenas<JSFatInlineString>(fop, src, dest, thingKind, budget, keepArenas); case AllocKind::EXTERNAL_STRING: return FinalizeTypedArenas<JSExternalString>(fop, src, dest, thingKind, budget, keepArenas); + case AllocKind::FAT_INLINE_ATOM: + return FinalizeTypedArenas<js::FatInlineAtom>(fop, src, dest, thingKind, budget, keepArenas); + case AllocKind::ATOM: + return FinalizeTypedArenas<js::NormalAtom>(fop, src, dest, thingKind, budget, keepArenas); case AllocKind::SYMBOL: return FinalizeTypedArenas<JS::Symbol>(fop, src, dest, thingKind, budget, keepArenas); case AllocKind::JITCODE: @@ -2323,8 +2334,9 @@ GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason, ArenaHeader*& void MovingTracer::onObjectEdge(JSObject** objp) { - if (IsForwarded(*objp)) - *objp = Forwarded(*objp); + JSObject* obj = *objp; + if (obj->runtimeFromAnyThread() == runtime() && IsForwarded(obj)) + *objp = Forwarded(obj); } void @@ -2477,6 +2489,8 @@ bool ArenasToUpdate::shouldProcessKind(AllocKind kind) if (kind == AllocKind::FAT_INLINE_STRING || kind == AllocKind::STRING || kind == AllocKind::EXTERNAL_STRING || + kind == AllocKind::FAT_INLINE_ATOM || + kind == AllocKind::ATOM || kind == AllocKind::SYMBOL) { return false; @@ -3782,10 +3796,12 @@ GCRuntime::purgeRuntime() bool GCRuntime::shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime, - JS::gcreason::Reason reason) + JS::gcreason::Reason reason, bool canAllocateMoreCode) { if (cleanUpEverything) return false; + if (!canAllocateMoreCode) + return false; if (alwaysPreserveCode) return true; @@ -3932,15 +3948,19 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason) zone->setPreservingCode(false); } + // Discard JIT code more aggressively if the process is approaching its + // executable code limit. + bool canAllocateMoreCode = jit::CanLikelyAllocateMoreExecutableMemory(); + for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { c->marked = false; c->scheduledForDestruction = false; c->maybeAlive = false; - if (shouldPreserveJITCode(c, currentTime, reason)) + if (shouldPreserveJITCode(c, currentTime, reason, canAllocateMoreCode)) c->zone()->setPreservingCode(true); } - if (!rt->gc.cleanUpEverything) { + if (!rt->gc.cleanUpEverything && canAllocateMoreCode) { if (JSCompartment* comp = jit::TopmostIonActivationCompartment(rt)) comp->zone()->setPreservingCode(true); } @@ -4298,7 +4318,7 @@ js::gc::MarkingValidator::nonIncrementalMark() * For saving, smush all of the keys into one big table and split them back * up into per-zone tables when restoring. */ - gc::WeakKeyTable savedWeakKeys; + gc::WeakKeyTable savedWeakKeys(SystemAllocPolicy(), runtime->randomHashCodeScrambler()); if (!savedWeakKeys.init()) return; @@ -4571,7 +4591,6 @@ Zone::findOutgoingEdges(ComponentFinder<JS::Zone>& finder) if (r.front()->isGCMarking()) finder.addEdgeTo(r.front()); } - gcZoneGroupEdges.clear(); Debugger::findZoneEdges(this, finder); } @@ -4600,6 +4619,11 @@ GCRuntime::findZoneEdgesForWeakMaps() void GCRuntime::findZoneGroups() { +#ifdef DEBUG + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) + MOZ_ASSERT(zone->gcZoneGroupEdges.empty()); +#endif + ComponentFinder<Zone> finder(rt->mainThread.nativeStackLimit[StackForSystemCode]); if (!isIncremental || !findZoneEdgesForWeakMaps()) finder.useOneComponent(); @@ -4612,12 +4636,19 @@ GCRuntime::findZoneGroups() currentZoneGroup = zoneGroups; zoneGroupIndex = 0; + for (GCZonesIter zone(rt); !zone.done(); zone.next()) + zone->gcZoneGroupEdges.clear(); + +#ifdef DEBUG for (Zone* head = currentZoneGroup; head; head = head->nextGroup()) { for (Zone* zone = head; zone; zone = zone->nextNodeInGroup()) MOZ_ASSERT(zone->isGCMarking()); } MOZ_ASSERT_IF(!isIncremental, !currentZoneGroup->nextGroup()); + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) + MOZ_ASSERT(zone->gcZoneGroupEdges.empty()); +#endif } static void @@ -4787,11 +4818,11 @@ MarkIncomingCrossCompartmentPointers(JSRuntime* rt, const uint32_t color) MOZ_ASSERT(dst->compartment() == c); if (color == GRAY) { - if (IsMarkedUnbarriered(&src) && src->asTenured().isMarked(GRAY)) + if (IsMarkedUnbarriered(rt, &src) && src->asTenured().isMarked(GRAY)) TraceManuallyBarrieredEdge(&rt->gc.marker, &dst, "cross-compartment gray pointer"); } else { - if (IsMarkedUnbarriered(&src) && !src->asTenured().isMarked(GRAY)) + if (IsMarkedUnbarriered(rt, &src) && !src->asTenured().isMarked(GRAY)) TraceManuallyBarrieredEdge(&rt->gc.marker, &dst, "cross-compartment black pointer"); } diff --git a/src/third_party/mozjs-45/extract/js/src/jsgc.h b/src/third_party/mozjs-45/extract/js/src/jsgc.h index a254a0b3ae9..d4cfc9960b8 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsgc.h +++ b/src/third_party/mozjs-45/extract/js/src/jsgc.h @@ -103,6 +103,8 @@ template <> struct MapTypeToFinalizeKind<ObjectGroup> { static const Alloc template <> struct MapTypeToFinalizeKind<JSFatInlineString> { static const AllocKind kind = AllocKind::FAT_INLINE_STRING; }; template <> struct MapTypeToFinalizeKind<JSString> { static const AllocKind kind = AllocKind::STRING; }; template <> struct MapTypeToFinalizeKind<JSExternalString> { static const AllocKind kind = AllocKind::EXTERNAL_STRING; }; +template <> struct MapTypeToFinalizeKind<js::FatInlineAtom> { static const AllocKind kind = AllocKind::FAT_INLINE_ATOM; }; +template <> struct MapTypeToFinalizeKind<js::NormalAtom> { static const AllocKind kind = AllocKind::ATOM; }; template <> struct MapTypeToFinalizeKind<JS::Symbol> { static const AllocKind kind = AllocKind::SYMBOL; }; template <> struct MapTypeToFinalizeKind<jit::JitCode> { static const AllocKind kind = AllocKind::JITCODE; }; @@ -140,6 +142,8 @@ IsNurseryAllocable(AllocKind kind) false, /* AllocKind::FAT_INLINE_STRING */ false, /* AllocKind::STRING */ false, /* AllocKind::EXTERNAL_STRING */ + false, /* AllocKind::FAT_INLINE_ATOM */ + false, /* AllocKind::ATOM */ false, /* AllocKind::SYMBOL */ false, /* AllocKind::JITCODE */ }; @@ -175,6 +179,8 @@ IsBackgroundFinalized(AllocKind kind) true, /* AllocKind::FAT_INLINE_STRING */ true, /* AllocKind::STRING */ false, /* AllocKind::EXTERNAL_STRING */ + true, /* AllocKind::FAT_INLINE_ATOM */ + true, /* AllocKind::ATOM */ true, /* AllocKind::SYMBOL */ false, /* AllocKind::JITCODE */ }; diff --git a/src/third_party/mozjs-45/extract/js/src/jsgcinlines.h b/src/third_party/mozjs-45/extract/js/src/jsgcinlines.h index 6ca8804cd8f..0cc2b051cb4 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsgcinlines.h +++ b/src/third_party/mozjs-45/extract/js/src/jsgcinlines.h @@ -89,11 +89,19 @@ class ArenaIter } }; +enum CellIterNeedsBarrier : uint8_t +{ + CellIterDoesntNeedBarrier = 0, + CellIterMayNeedBarrier = 1 +}; + class ArenaCellIterImpl { - // These three are set in initUnsynchronized(). + // These are set in initUnsynchronized(). size_t firstThingOffset; size_t thingSize; + JS::TraceKind traceKind; + bool needsBarrier; #ifdef DEBUG bool isInited; #endif @@ -122,26 +130,30 @@ class ArenaCellIterImpl ArenaCellIterImpl() : firstThingOffset(0) // Squelch , thingSize(0) // warnings + , traceKind(JS::TraceKind::Null) + , needsBarrier(false) , limit(0) { } - void initUnsynchronized(ArenaHeader* aheader) { + void initUnsynchronized(ArenaHeader* aheader, CellIterNeedsBarrier mayNeedBarrier) { AllocKind kind = aheader->getAllocKind(); #ifdef DEBUG isInited = true; #endif firstThingOffset = Arena::firstThingOffset(kind); thingSize = Arena::thingSize(kind); + traceKind = MapAllocToTraceKind(kind); + needsBarrier = mayNeedBarrier && !aheader->zone->runtimeFromMainThread()->isHeapCollecting(); reset(aheader); } - void init(ArenaHeader* aheader) { + void init(ArenaHeader* aheader, CellIterNeedsBarrier mayNeedBarrier) { #ifdef DEBUG AllocKind kind = aheader->getAllocKind(); MOZ_ASSERT(aheader->zone->arenas.isSynchronizedFreeList(kind)); #endif - initUnsynchronized(aheader); + initUnsynchronized(aheader, mayNeedBarrier); } // Use this to move from an Arena of a particular kind to another Arena of @@ -161,7 +173,15 @@ class ArenaCellIterImpl TenuredCell* getCell() const { MOZ_ASSERT(!done()); - return reinterpret_cast<TenuredCell*>(thing); + TenuredCell* cell = reinterpret_cast<TenuredCell*>(thing); + + // This can result in a a new reference being created to an object that + // an ongoing incremental GC may find to be unreachable, so we may need + // a barrier here. + if (needsBarrier) + ExposeGCThingToActiveJS(JS::GCCellPtr(cell, traceKind)); + + return cell; } template<typename T> T* get() const { @@ -186,7 +206,7 @@ class ArenaCellIterUnderGC : public ArenaCellIterImpl public: explicit ArenaCellIterUnderGC(ArenaHeader* aheader) { MOZ_ASSERT(aheader->zone->runtimeFromAnyThread()->isHeapBusy()); - init(aheader); + init(aheader, CellIterDoesntNeedBarrier); } }; @@ -194,7 +214,7 @@ class ArenaCellIterUnderFinalize : public ArenaCellIterImpl { public: explicit ArenaCellIterUnderFinalize(ArenaHeader* aheader) { - initUnsynchronized(aheader); + initUnsynchronized(aheader, CellIterDoesntNeedBarrier); } }; @@ -210,7 +230,7 @@ class ZoneCellIterImpl MOZ_ASSERT(zone->arenas.isSynchronizedFreeList(kind)); arenaIter.init(zone, kind); if (!arenaIter.done()) - cellIter.init(arenaIter.get()); + cellIter.init(arenaIter.get(), CellIterMayNeedBarrier); } public: diff --git a/src/third_party/mozjs-45/extract/js/src/jsiter.cpp b/src/third_party/mozjs-45/extract/js/src/jsiter.cpp index 9b27317683b..9cbff88bfb1 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsiter.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsiter.cpp @@ -69,17 +69,7 @@ NativeIterator::mark(JSTracer* trc) TraceManuallyBarrieredEdge(trc, &iterObj_, "iterObj"); } -struct IdHashPolicy { - typedef jsid Lookup; - static HashNumber hash(jsid id) { - return JSID_BITS(id); - } - static bool match(jsid id1, jsid id2) { - return id1 == id2; - } -}; - -typedef HashSet<jsid, IdHashPolicy> IdSet; +typedef HashSet<jsid, JsidHasher> IdSet; static inline bool NewKeyValuePair(JSContext* cx, jsid id, const Value& val, MutableHandleValue rval) diff --git a/src/third_party/mozjs-45/extract/js/src/jsmath.cpp b/src/third_party/mozjs-45/extract/js/src/jsmath.cpp index 040269f63d9..e381b42a846 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsmath.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsmath.cpp @@ -747,8 +747,8 @@ js::math_pow(JSContext* cx, unsigned argc, Value* vp) return math_pow_handle(cx, args.get(0), args.get(1), args.rval()); } -static uint64_t -GenerateSeed() +uint64_t +js::GenerateRandomSeed() { uint64_t seed = 0; @@ -763,7 +763,7 @@ GenerateSeed() close(fd); } #else -# error "Platform needs to implement GenerateSeed()" +# error "Platform needs to implement GenerateRandomSeed()" #endif // Also mix in PRMJ_Now() in case we couldn't read random bits from the OS. @@ -775,8 +775,8 @@ js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed) { // XorShift128PlusRNG must be initialized with a non-zero seed. do { - seed[0] = GenerateSeed(); - seed[1] = GenerateSeed(); + seed[0] = GenerateRandomSeed(); + seed[1] = GenerateRandomSeed(); } while (seed[0] == 0 && seed[1] == 0); } diff --git a/src/third_party/mozjs-45/extract/js/src/jsmath.h b/src/third_party/mozjs-45/extract/js/src/jsmath.h index e703c703c62..a1d1aaedfb3 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsmath.h +++ b/src/third_party/mozjs-45/extract/js/src/jsmath.h @@ -86,6 +86,9 @@ class MathCache extern JSObject* InitMathClass(JSContext* cx, HandleObject obj); +extern uint64_t +GenerateRandomSeed(); + // Fill |seed[0]| and |seed[1]| with random bits, suitable for // seeding a XorShift128+ random number generator. extern void diff --git a/src/third_party/mozjs-45/extract/js/src/jswatchpoint.cpp b/src/third_party/mozjs-45/extract/js/src/jswatchpoint.cpp index 9713ebe5990..53418e36fc4 100644 --- a/src/third_party/mozjs-45/extract/js/src/jswatchpoint.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jswatchpoint.cpp @@ -11,6 +11,7 @@ #include "jsfriendapi.h" #include "gc/Marking.h" +#include "vm/Shape.h" #include "jsgcinlines.h" @@ -153,7 +154,7 @@ WatchpointMap::markIteratively(JSTracer* trc) JSObject* priorKeyObj = entry.key().object; jsid priorKeyId(entry.key().id.get()); bool objectIsLive = - IsMarked(const_cast<PreBarrieredObject*>(&entry.key().object)); + IsMarked(trc->runtime(), const_cast<PreBarrieredObject*>(&entry.key().object)); if (objectIsLive || entry.value().held) { if (!objectIsLive) { TraceEdge(trc, const_cast<PreBarrieredObject*>(&entry.key().object), @@ -166,7 +167,7 @@ WatchpointMap::markIteratively(JSTracer* trc) JSID_IS_SYMBOL(priorKeyId)); TraceEdge(trc, const_cast<PreBarrieredId*>(&entry.key().id), "WatchKey::id"); - if (entry.value().closure && !IsMarked(&entry.value().closure)) { + if (entry.value().closure && !IsMarked(trc->runtime(), &entry.value().closure)) { TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); marked = true; } diff --git a/src/third_party/mozjs-45/extract/js/src/jsweakmap.cpp b/src/third_party/mozjs-45/extract/js/src/jsweakmap.cpp index 2249f46f71c..70a119601c7 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsweakmap.cpp +++ b/src/third_party/mozjs-45/extract/js/src/jsweakmap.cpp @@ -150,7 +150,7 @@ ObjectValueMap::findZoneEdges() if (!delegate) continue; Zone* delegateZone = delegate->zone(); - if (delegateZone == zone) + if (delegateZone == zone || !delegateZone->isGCMarking()) continue; if (!delegateZone->gcZoneGroupEdges.put(key->zone())) return false; diff --git a/src/third_party/mozjs-45/extract/js/src/jsweakmap.h b/src/third_party/mozjs-45/extract/js/src/jsweakmap.h index 3c17c78d415..020f51e9733 100644 --- a/src/third_party/mozjs-45/extract/js/src/jsweakmap.h +++ b/src/third_party/mozjs-45/extract/js/src/jsweakmap.h @@ -184,7 +184,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, Key key(p->key()); MOZ_ASSERT((markedCell == extractUnbarriered(key)) || (markedCell == getDelegate(key))); - if (gc::IsMarked(&key)) { + if (gc::IsMarked(trc->runtime(), &key)) { TraceEdge(trc, &p->value(), "ephemeron value"); } else if (keyNeedsMark(key)) { TraceEdge(trc, &p->value(), "WeakMap ephemeron value"); @@ -249,7 +249,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, for (Enum e(*this); !e.empty(); e.popFront()) { // If the entry is live, ensure its key and value are marked. - bool keyIsMarked = gc::IsMarked(&e.front().mutableKey()); + bool keyIsMarked = gc::IsMarked(trc->runtime(), &e.front().mutableKey()); if (!keyIsMarked && keyNeedsMark(e.front().key())) { TraceEdge(trc, &e.front().mutableKey(), "proxy-preserved WeakMap entry key"); keyIsMarked = true; @@ -257,7 +257,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, } if (keyIsMarked) { - if (!gc::IsMarked(&e.front().value())) { + if (!gc::IsMarked(trc->runtime(), &e.front().value())) { TraceEdge(trc, &e.front().value(), "WeakMap entry value"); markedAny = true; } @@ -283,7 +283,15 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, JSObject* getDelegate(JSObject* key) const { JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp; - return op ? op(key) : nullptr; + if (!op) + return nullptr; + + JSObject* obj = op(key); + if (!obj) + return nullptr; + + MOZ_ASSERT(obj->runtimeFromMainThread() == zone->runtimeFromMainThread()); + return obj; } JSObject* getDelegate(gc::Cell* cell) const { @@ -296,7 +304,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, * Check if the delegate is marked with any color to properly handle * gray marking when the key's delegate is black and the map is gray. */ - return delegate && gc::IsMarkedUnbarriered(&delegate); + return delegate && gc::IsMarkedUnbarriered(zone->runtimeFromMainThread(), &delegate); } bool keyNeedsMark(gc::Cell* cell) const { diff --git a/src/third_party/mozjs-45/extract/js/src/moz.build b/src/third_party/mozjs-45/extract/js/src/moz.build index 591d7a6a3ee..123c9f3bcb5 100644 --- a/src/third_party/mozjs-45/extract/js/src/moz.build +++ b/src/third_party/mozjs-45/extract/js/src/moz.build @@ -236,6 +236,7 @@ UNIFIED_SOURCES += [ 'jit/MoveResolver.cpp', 'jit/OptimizationTracking.cpp', 'jit/PerfSpewer.cpp', + 'jit/ProcessExecutableMemory.cpp', 'jit/RangeAnalysis.cpp', 'jit/Recover.cpp', 'jit/RegisterAllocator.cpp', @@ -530,15 +531,8 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: ] if CONFIG['OS_ARCH'] == 'WINNT': - SOURCES += [ - 'jit/ExecutableAllocatorWin.cpp', - ] # _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s() DEFINES['_CRT_RAND_S'] = True -else: - SOURCES += [ - 'jit/ExecutableAllocatorPosix.cpp', - ] if CONFIG['JS_HAS_CTYPES']: SOURCES += [ diff --git a/src/third_party/mozjs-45/extract/js/src/proxy/Wrapper.cpp b/src/third_party/mozjs-45/extract/js/src/proxy/Wrapper.cpp index e80113ce362..6a60746904d 100644 --- a/src/third_party/mozjs-45/extract/js/src/proxy/Wrapper.cpp +++ b/src/third_party/mozjs-45/extract/js/src/proxy/Wrapper.cpp @@ -42,7 +42,10 @@ JSObject* Wrapper::wrappedObject(JSObject* wrapper) { MOZ_ASSERT(wrapper->is<WrapperObject>()); - return wrapper->as<ProxyObject>().target(); + JSObject* target = wrapper->as<ProxyObject>().target(); + if (target) + JS::ExposeObjectToActiveJS(target); + return target; } bool diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Debugger.cpp b/src/third_party/mozjs-45/extract/js/src/vm/Debugger.cpp index 12de1145276..d583c9c52e9 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Debugger.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/Debugger.cpp @@ -517,7 +517,7 @@ Debugger::getHook(Hook hook) const } bool -Debugger::hasAnyLiveHooks() const +Debugger::hasAnyLiveHooks(JSRuntime* rt) const { if (!enabled) return false; @@ -532,7 +532,7 @@ Debugger::hasAnyLiveHooks() const /* If any breakpoints are in live scripts, return true. */ for (Breakpoint* bp = firstBreakpoint(); bp; bp = bp->nextInDebugger()) { - if (IsMarkedUnbarriered(&bp->site->script)) + if (IsMarkedUnbarriered(rt, &bp->site->script)) return true; } @@ -2520,7 +2520,7 @@ Debugger::markAllIteratively(GCMarker* trc) for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { if (c->isDebuggee()) { GlobalObject* global = c->unsafeUnbarrieredMaybeGlobal(); - if (!IsMarkedUnbarriered(&global)) + if (!IsMarkedUnbarriered(rt, &global)) continue; /* @@ -2542,8 +2542,8 @@ Debugger::markAllIteratively(GCMarker* trc) if (!dbgobj->zone()->isGCMarking()) continue; - bool dbgMarked = IsMarked(&dbgobj); - if (!dbgMarked && dbg->hasAnyLiveHooks()) { + bool dbgMarked = IsMarked(rt, &dbgobj); + if (!dbgMarked && dbg->hasAnyLiveHooks(rt)) { /* * obj could be reachable only via its live, enabled * debugger hooks, which may yet be called. @@ -2556,12 +2556,12 @@ Debugger::markAllIteratively(GCMarker* trc) if (dbgMarked) { /* Search for breakpoints to mark. */ for (Breakpoint* bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) { - if (IsMarkedUnbarriered(&bp->site->script)) { + if (IsMarkedUnbarriered(rt, &bp->site->script)) { /* * The debugger and the script are both live. * Therefore the breakpoint handler is live. */ - if (!IsMarked(&bp->getHandlerRef())) { + if (!IsMarked(rt, &bp->getHandlerRef())) { TraceEdge(trc, &bp->getHandlerRef(), "breakpoint handler"); markedAny = true; } diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Debugger.h b/src/third_party/mozjs-45/extract/js/src/vm/Debugger.h index ef7b94bc24f..49744a7d00d 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Debugger.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/Debugger.h @@ -607,7 +607,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> void updateObservesAsmJSOnDebuggees(IsObserving observing); JSObject* getHook(Hook hook) const; - bool hasAnyLiveHooks() const; + bool hasAnyLiveHooks(JSRuntime* rt) const; static JSTrapStatus slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame); static bool slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok); diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Initialization.cpp b/src/third_party/mozjs-45/extract/js/src/vm/Initialization.cpp index cf5d21aa230..fcef4b22b44 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Initialization.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/Initialization.cpp @@ -83,7 +83,9 @@ JS_Init(void) js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN); #endif - js::jit::ExecutableAllocator::initStatic(); + js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works. + if (!js::jit::InitProcessExecutableMemory()) + return false; if (!js::jit::InitializeIon()) return false; @@ -146,6 +148,9 @@ JS_ShutDown(void) u_cleanup(); #endif // EXPOSE_INTL_API + if (!JSRuntime::hasLiveRuntimes()) + js::jit::ReleaseProcessExecutableMemory(); + libraryInitState = InitState::ShutDown; } diff --git a/src/third_party/mozjs-45/extract/js/src/vm/ObjectGroup.cpp b/src/third_party/mozjs-45/extract/js/src/vm/ObjectGroup.cpp index 6ef50de88c3..ad002b4a05e 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/ObjectGroup.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/ObjectGroup.cpp @@ -12,6 +12,7 @@ #include "gc/StoreBuffer.h" #include "gc/Zone.h" #include "vm/ArrayObject.h" +#include "vm/Shape.h" #include "vm/UnboxedObject.h" #include "jsobjinlines.h" @@ -554,45 +555,38 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, associated); - if (proto.isObject()) { - RootedObject obj(cx, proto.toObject()); - - if (associated) { - if (associated->is<JSFunction>()) { - if (!TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>())) - return nullptr; - } else { - group->setTypeDescr(&associated->as<TypeDescr>()); - } + if (associated) { + if (associated->is<JSFunction>()) { + if (!TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>())) + return nullptr; + } else { + group->setTypeDescr(&associated->as<TypeDescr>()); } + } - /* - * Some builtin objects have slotful native properties baked in at - * creation via the Shape::{insert,get}initialShape mechanism. Since - * these properties are never explicitly defined on new objects, update - * the type information for them here. - */ - - const JSAtomState& names = cx->names(); - - if (obj->is<RegExpObject>()) { - AddTypePropertyId(cx, group, nullptr, NameToId(names.source), TypeSet::StringType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.global), TypeSet::BooleanType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.ignoreCase), TypeSet::BooleanType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.multiline), TypeSet::BooleanType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.sticky), TypeSet::BooleanType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type()); - } + /* + * Some builtin objects have slotful native properties baked in at + * creation via the Shape::{insert,get}initialShape mechanism. Since + * these properties are never explicitly defined on new objects, update + * the type information for them here. + */ - if (obj->is<StringObject>()) - AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type()); + const JSAtomState& names = cx->names(); - if (obj->is<ErrorObject>()) { - AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.stack), TypeSet::StringType()); - } + if (clasp == &RegExpObject::class_) { + AddTypePropertyId(cx, group, nullptr, NameToId(names.source), TypeSet::StringType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.global), TypeSet::BooleanType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.ignoreCase), TypeSet::BooleanType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.multiline), TypeSet::BooleanType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.sticky), TypeSet::BooleanType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type()); + } else if (clasp == &StringObject::class_) { + AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type()); + } else if (ErrorObject::isErrorClass(clasp)) { + AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type()); + AddTypePropertyId(cx, group, nullptr, NameToId(names.stack), TypeSet::StringType()); } return group; @@ -1116,7 +1110,7 @@ struct ObjectGroupCompartment::PlainObjectKey }; static inline HashNumber hash(const Lookup& lookup) { - return (HashNumber) (JSID_BITS(lookup.properties[lookup.nproperties - 1].id) ^ + return (HashNumber) (HashId(lookup.properties[lookup.nproperties - 1].id) ^ lookup.nproperties); } diff --git a/src/third_party/mozjs-45/extract/js/src/vm/RegExpObject.cpp b/src/third_party/mozjs-45/extract/js/src/vm/RegExpObject.cpp index fec090d3f19..9d0dd97d037 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/RegExpObject.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/RegExpObject.cpp @@ -793,7 +793,7 @@ RegExpCompartment::sweep(JSRuntime* rt) // the RegExpShared if it was accidentally marked earlier but wasn't // marked by the current trace. bool keep = shared->marked() && - IsMarked(&shared->source); + IsMarked(rt, &shared->source); for (size_t i = 0; i < ArrayLength(shared->compilationArray); i++) { RegExpShared::RegExpCompilation& compilation = shared->compilationArray[i]; if (compilation.jitCode && diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Runtime.cpp b/src/third_party/mozjs-45/extract/js/src/vm/Runtime.cpp index 94909a2ed47..a3a3fda4158 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Runtime.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/Runtime.cpp @@ -311,6 +311,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) return false; atomsCompartment->setIsSystem(true); + atomsCompartment->setIsAtomsCompartment(); atomsZone.forget(); this->atomsCompartment_ = atomsCompartment.forget(); @@ -745,6 +746,32 @@ JSRuntime::triggerActivityCallback(bool active) activityCallback(activityCallbackArg, active); } +mozilla::non_crypto::XorShift128PlusRNG& +JSRuntime::randomKeyGenerator() +{ + MOZ_ASSERT(CurrentThreadCanAccessRuntime(this)); + if (randomKeyGenerator_.isNothing()) { + mozilla::Array<uint64_t, 2> seed; + GenerateXorShift128PlusSeed(seed); + randomKeyGenerator_.emplace(seed[0], seed[1]); + } + return randomKeyGenerator_.ref(); +} + +mozilla::HashCodeScrambler +JSRuntime::randomHashCodeScrambler() +{ + auto& rng = randomKeyGenerator(); + return mozilla::HashCodeScrambler(rng.next(), rng.next()); +} + +mozilla::non_crypto::XorShift128PlusRNG +JSRuntime::forkRandomKeyGenerator() +{ + auto& rng = randomKeyGenerator(); + return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next()); +} + void JSRuntime::updateMallocCounter(size_t nbytes) { diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Runtime.h b/src/third_party/mozjs-45/extract/js/src/vm/Runtime.h index 51734df147a..9df53087c03 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Runtime.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/Runtime.h @@ -949,6 +949,15 @@ struct JSRuntime : public JS::shadow::Runtime, return interpreterStack_; } + private: + // Used to generate random keys for hash tables. + mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_; + mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator(); + + public: + mozilla::HashCodeScrambler randomHashCodeScrambler(); + mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator(); + //------------------------------------------------------------------------- // Self-hosting support //------------------------------------------------------------------------- diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Shape.h b/src/third_party/mozjs-45/extract/js/src/vm/Shape.h index 51185898d80..1c2c99a1feb 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Shape.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/Shape.h @@ -29,6 +29,8 @@ #include "js/RootingAPI.h" #include "js/UbiNode.h" #include "vm/ObjectGroup.h" +#include "vm/String.h" +#include "vm/Symbol.h" #ifdef _MSC_VER #pragma warning(push) @@ -516,11 +518,33 @@ struct StackBaseShape : public DefaultHasher<ReadBarriered<UnownedBaseShape*>> static inline bool match(ReadBarriered<UnownedBaseShape*> key, const Lookup& lookup); }; +static MOZ_ALWAYS_INLINE js::HashNumber +HashId(jsid id) +{ + // HashGeneric alone would work, but bits of atom and symbol addresses + // could then be recovered from the hash code. See bug 1330769. + if (MOZ_LIKELY(JSID_IS_ATOM(id))) + return JSID_TO_ATOM(id)->hash(); + if (JSID_IS_SYMBOL(id)) + return JSID_TO_SYMBOL(id)->hash(); + return mozilla::HashGeneric(JSID_BITS(id)); +} + +struct JsidHasher +{ + typedef jsid Lookup; + static HashNumber hash(jsid id) { + return HashId(id); + } + static bool match(jsid id1, jsid id2) { + return id1 == id2; + } +}; + typedef HashSet<ReadBarriered<UnownedBaseShape*>, StackBaseShape, SystemAllocPolicy> BaseShapeSet; - class Shape : public gc::TenuredCell { friend class ::JSObject; @@ -1172,7 +1196,7 @@ struct StackShape : public JS::Traceable /* Accumulate from least to most random so the low bits are most random. */ hash = mozilla::RotateLeft(hash, 4) ^ attrs; hash = mozilla::RotateLeft(hash, 4) ^ slot_; - hash = mozilla::RotateLeft(hash, 4) ^ JSID_BITS(propid); + hash = mozilla::RotateLeft(hash, 4) ^ HashId(propid); hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawGetter); hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawSetter); return hash; diff --git a/src/third_party/mozjs-45/extract/js/src/vm/String-inl.h b/src/third_party/mozjs-45/extract/js/src/vm/String-inl.h index b4676d344d0..0e95063f21a 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/String-inl.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/String-inl.h @@ -13,6 +13,7 @@ #include "mozilla/Range.h" #include "jscntxt.h" +#include "jscompartment.h" #include "gc/Allocator.h" #include "gc/Marking.h" @@ -220,7 +221,11 @@ JSFlatString::new_(js::ExclusiveContext* cx, const CharT* chars, size_t length) if (!validateLength(cx, length)) return nullptr; - JSFlatString* str = static_cast<JSFlatString*>(js::Allocate<JSString, allowGC>(cx)); + JSFlatString* str; + if (cx->compartment()->isAtomsCompartment()) + str = js::Allocate<js::NormalAtom, allowGC>(cx); + else + str = static_cast<JSFlatString*>(js::Allocate<JSString, allowGC>(cx)); if (!str) return nullptr; @@ -247,6 +252,9 @@ template <js::AllowGC allowGC> MOZ_ALWAYS_INLINE JSThinInlineString* JSThinInlineString::new_(js::ExclusiveContext* cx) { + if (cx->compartment()->isAtomsCompartment()) + return (JSThinInlineString*)(js::Allocate<js::NormalAtom, allowGC>(cx)); + return static_cast<JSThinInlineString*>(js::Allocate<JSString, allowGC>(cx)); } @@ -254,6 +262,9 @@ template <js::AllowGC allowGC> MOZ_ALWAYS_INLINE JSFatInlineString* JSFatInlineString::new_(js::ExclusiveContext* cx) { + if (cx->compartment()->isAtomsCompartment()) + return (JSFatInlineString*)(js::Allocate<js::FatInlineAtom, allowGC>(cx)); + return js::Allocate<JSFatInlineString, allowGC>(cx); } @@ -351,6 +362,7 @@ JSString::finalize(js::FreeOp* fop) { /* FatInline strings are in a different arena. */ MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING); + MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM); if (isFlat()) asFlat().finalize(fop); @@ -362,6 +374,7 @@ inline void JSFlatString::finalize(js::FreeOp* fop) { MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING); + MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM); if (!isInline()) fop->free_(nonInlineCharsRaw()); @@ -381,6 +394,8 @@ JSAtom::finalize(js::FreeOp* fop) { MOZ_ASSERT(JSString::isAtom()); MOZ_ASSERT(JSString::isFlat()); + MOZ_ASSERT(getAllocKind() == js::gc::AllocKind::ATOM || + getAllocKind() == js::gc::AllocKind::FAT_INLINE_ATOM); if (!isInline()) fop->free_(nonInlineCharsRaw()); diff --git a/src/third_party/mozjs-45/extract/js/src/vm/String.cpp b/src/third_party/mozjs-45/extract/js/src/vm/String.cpp index e5a315fbfc3..1bbe151c015 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/String.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/String.cpp @@ -71,8 +71,12 @@ JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) JS::ubi::Node::Size JS::ubi::Concrete<JSString>::size(mozilla::MallocSizeOf mallocSizeOf) const { - JSString &str = get(); - size_t size = str.isFatInline() ? sizeof(JSFatInlineString) : sizeof(JSString); + JSString& str = get(); + size_t size; + if (str.isAtom()) + size = str.isFatInline() ? sizeof(js::FatInlineAtom) : sizeof(js::NormalAtom); + else + size = str.isFatInline() ? sizeof(JSFatInlineString) : sizeof(JSString); // We can't use mallocSizeof on things in the nursery. At the moment, // strings are never in the nursery, but that may change. @@ -789,7 +793,8 @@ StaticStrings::init(JSContext* cx) JSFlatString* s = NewStringCopyN<NoGC>(cx, buffer, 1); if (!s) return false; - unitStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(); + HashNumber hash = mozilla::HashString(buffer, 1); + unitStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash); } for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) { @@ -797,7 +802,8 @@ StaticStrings::init(JSContext* cx) JSFlatString* s = NewStringCopyN<NoGC>(cx, buffer, 2); if (!s) return false; - length2StaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(); + HashNumber hash = mozilla::HashString(buffer, 2); + length2StaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash); } for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) { @@ -815,7 +821,8 @@ StaticStrings::init(JSContext* cx) JSFlatString* s = NewStringCopyN<NoGC>(cx, buffer, 3); if (!s) return false; - intStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(); + HashNumber hash = mozilla::HashString(buffer, 3); + intStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash); } } diff --git a/src/third_party/mozjs-45/extract/js/src/vm/String.h b/src/third_party/mozjs-45/extract/js/src/vm/String.h index e788aadbe14..80466681507 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/String.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/String.h @@ -123,7 +123,11 @@ static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1; * | | * | +-- JSFatInlineString - / header is fat * | - * JSAtom - / string equality === pointer equality + * JSAtom (abstract) - / string equality === pointer equality + * | | + * | +-- js::NormalAtom - JSFlatString + atom hash code + * | | + * | +-- js::FatInlineAtom - JSFatInlineString + atom hash code * | * js::PropertyName - / chars don't contain an index (uint32_t) * @@ -135,10 +139,9 @@ static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1; * Atoms can additionally be permanent, i.e. unable to be collected, and can * be combined with other string types to create additional most-derived types * that satisfy the invariants of more than one of the abovementioned - * most-derived types: - * - InlineAtom = JSInlineString + JSAtom (atom with inline chars, abstract) - * - ThinInlineAtom = JSThinInlineString + JSAtom (atom with inline chars) - * - FatInlineAtom = JSFatInlineString + JSAtom (atom with (more) inline chars) + * most-derived types. Furthermore, each atom stores a hash number (based on its + * chars). This hash number is used as key in the atoms table and when the atom + * is used as key in a JS Map/Set. * * Derived string types can be queried from ancestor types via isX() and * retrieved with asX() debug-only-checked casts. @@ -765,14 +768,8 @@ class JSFlatString : public JSLinearString * Once a JSFlatString sub-class has been added to the atom state, this * operation changes the string to the JSAtom type, in place. */ - MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoAtom() { - d.u1.flags |= ATOM_BIT; - return &asAtom(); - } - MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoPermanentAtom() { - d.u1.flags |= PERMANENT_ATOM_MASK; - return &asAtom(); - } + MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoAtom(js::HashNumber hash); + MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoPermanentAtom(js::HashNumber hash); inline void finalize(js::FreeOp* fop); @@ -984,6 +981,9 @@ class JSAtom : public JSFlatString d.u1.flags |= PERMANENT_ATOM_MASK; } + inline js::HashNumber hash() const; + inline void initHash(js::HashNumber hash); + #ifdef DEBUG void dump(); #endif @@ -994,6 +994,83 @@ static_assert(sizeof(JSAtom) == sizeof(JSString), namespace js { +class NormalAtom : public JSAtom +{ + protected: // Silence Clang unused-field warning. + HashNumber hash_; + uint32_t padding_; // Ensure the size is a multiple of gc::CellSize. + + public: + HashNumber hash() const { + return hash_; + } + void initHash(HashNumber hash) { + hash_ = hash; + } +}; + +static_assert(sizeof(NormalAtom) == sizeof(JSString) + sizeof(uint64_t), + "NormalAtom must have size of a string + HashNumber, " + "aligned to gc::CellSize"); + +class FatInlineAtom : public JSAtom +{ + protected: // Silence Clang unused-field warning. + char inlineStorage_[sizeof(JSFatInlineString) - sizeof(JSString)]; + HashNumber hash_; + uint32_t padding_; // Ensure the size is a multiple of gc::CellSize. + + public: + HashNumber hash() const { + return hash_; + } + void initHash(HashNumber hash) { + hash_ = hash; + } +}; + +static_assert(sizeof(FatInlineAtom) == sizeof(JSFatInlineString) + sizeof(uint64_t), + "FatInlineAtom must have size of a fat inline string + HashNumber, " + "aligned to gc::CellSize"); + +} // namespace js + +inline js::HashNumber +JSAtom::hash() const +{ + if (isFatInline()) + return static_cast<const js::FatInlineAtom*>(this)->hash(); + return static_cast<const js::NormalAtom*>(this)->hash(); +} + +inline void +JSAtom::initHash(js::HashNumber hash) +{ + if (isFatInline()) + return static_cast<js::FatInlineAtom*>(this)->initHash(hash); + return static_cast<js::NormalAtom*>(this)->initHash(hash); +} + +MOZ_ALWAYS_INLINE JSAtom* +JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash) +{ + d.u1.flags |= ATOM_BIT; + JSAtom* atom = &asAtom(); + atom->initHash(hash); + return atom; +} + +MOZ_ALWAYS_INLINE JSAtom* +JSFlatString::morphAtomizedStringIntoPermanentAtom(js::HashNumber hash) +{ + d.u1.flags |= PERMANENT_ATOM_MASK; + JSAtom* atom = &asAtom(); + atom->initHash(hash); + return atom; +} + +namespace js { + class StaticStrings { private: @@ -1187,6 +1264,8 @@ NewStringCopyZ(js::ExclusiveContext* cx, const char* s) return NewStringCopyN<allowGC>(cx, s, strlen(s)); } +JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + } /* namespace js */ // Addon IDs are interned atoms which are never destroyed. This detail is diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Symbol.cpp b/src/third_party/mozjs-45/extract/js/src/vm/Symbol.cpp index dfe6278d140..c1ec8892bf0 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Symbol.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/Symbol.cpp @@ -20,7 +20,7 @@ using JS::Symbol; using namespace js; Symbol* -Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, JSAtom* description) +Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, uint32_t hash, JSAtom* description) { MOZ_ASSERT(cx->compartment() == cx->atomsCompartment()); MOZ_ASSERT(cx->atomsCompartment()->runtimeFromAnyThread()->currentThreadHasExclusiveAccess()); @@ -31,7 +31,7 @@ Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, JSAtom* descripti ReportOutOfMemory(cx); return nullptr; } - return new (p) Symbol(code, description); + return new (p) Symbol(code, hash, description); } Symbol* @@ -48,7 +48,7 @@ Symbol::new_(ExclusiveContext* cx, JS::SymbolCode code, JSString* description) // probably be replaced with an assertion that we're on the main thread. AutoLockForExclusiveAccess lock(cx); AutoCompartment ac(cx, cx->atomsCompartment()); - return newInternal(cx, code, atom); + return newInternal(cx, code, cx->compartment()->randomHashCode(), atom); } Symbol* @@ -66,7 +66,7 @@ Symbol::for_(js::ExclusiveContext* cx, HandleString description) return *p; AutoCompartment ac(cx, cx->atomsCompartment()); - Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom); + Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom->hash(), atom); if (!sym) return nullptr; diff --git a/src/third_party/mozjs-45/extract/js/src/vm/Symbol.h b/src/third_party/mozjs-45/extract/js/src/vm/Symbol.h index c201ed127c5..e39a490662f 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/Symbol.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/Symbol.h @@ -16,10 +16,11 @@ #include "gc/Barrier.h" #include "gc/Marking.h" - #include "js/GCHashTable.h" #include "js/RootingAPI.h" #include "js/TypeDecls.h" +#include "js/Utility.h" +#include "vm/String.h" namespace JS { @@ -27,25 +28,31 @@ class Symbol : public js::gc::TenuredCell { private: SymbolCode code_; + + // Each Symbol gets its own hash code so that we don't have to use + // addresses as hash codes (a security hazard). + js::HashNumber hash_; + JSAtom* description_; // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit - // architectures and 24 bytes on 64-bit. 8 bytes of padding makes Symbol + // architectures and 24 bytes on 64-bit. A size_t of padding makes Symbol // the minimum size on both. - uint64_t unused2_; + size_t unused_; - Symbol(SymbolCode code, JSAtom* desc) - : code_(code), description_(desc) + Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc) + : code_(code), hash_(hash), description_(desc) { - // Silence warnings about unused2 being... unused. - (void)unused2_; + // Silence warnings about unused_ being... unused. + (void)unused_; } Symbol(const Symbol&) = delete; void operator=(const Symbol&) = delete; static Symbol* - newInternal(js::ExclusiveContext* cx, SymbolCode code, JSAtom* description); + newInternal(js::ExclusiveContext* cx, SymbolCode code, js::HashNumber hash, + JSAtom* description); public: static Symbol* new_(js::ExclusiveContext* cx, SymbolCode code, JSString* description); @@ -53,6 +60,7 @@ class Symbol : public js::gc::TenuredCell JSAtom* description() const { return description_; } SymbolCode code() const { return code_; } + js::HashNumber hash() const { return hash_; } bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; } @@ -88,7 +96,7 @@ struct HashSymbolsByDescription typedef JSAtom* Lookup; static HashNumber hash(Lookup l) { - return HashNumber(reinterpret_cast<uintptr_t>(l)); + return HashNumber(l->hash()); } static bool match(Key sym, Lookup l) { return sym->description() == l; diff --git a/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.cpp b/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.cpp index b289cfd62a7..2738145960c 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.cpp @@ -749,16 +749,16 @@ TypeSet::readBarrier(const TypeSet* types) } /* static */ bool -TypeSet::IsTypeMarked(TypeSet::Type* v) +TypeSet::IsTypeMarked(JSRuntime* rt, TypeSet::Type* v) { bool rv; if (v->isSingletonUnchecked()) { JSObject* obj = v->singletonNoBarrier(); - rv = IsMarkedUnbarriered(&obj); + rv = IsMarkedUnbarriered(rt, &obj); *v = TypeSet::ObjectType(obj); } else if (v->isGroupUnchecked()) { ObjectGroup* group = v->groupNoBarrier(); - rv = IsMarkedUnbarriered(&group); + rv = IsMarkedUnbarriered(rt, &group); *v = TypeSet::ObjectType(group); } else { rv = true; @@ -4192,6 +4192,10 @@ ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom) if (unboxedLayout().newScript()) unboxedLayout().newScript()->sweep(); + + // Discard constructor code to avoid holding onto ExecutablePools. + if (zone()->isGCCompacting()) + unboxedLayout().setConstructorCode(nullptr); } if (maybePreliminaryObjects()) diff --git a/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.h b/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.h index 7e647c0fe25..2f85f8620a7 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.h +++ b/src/third_party/mozjs-45/extract/js/src/vm/TypeInference.h @@ -532,7 +532,7 @@ class TypeSet static void MarkTypeRoot(JSTracer* trc, Type* v, const char* name); static void MarkTypeUnbarriered(JSTracer* trc, Type* v, const char* name); - static bool IsTypeMarked(Type* v); + static bool IsTypeMarked(JSRuntime* rt, Type* v); static bool IsTypeAllocatedDuringIncremental(Type v); static bool IsTypeAboutToBeFinalized(Type* v); }; diff --git a/src/third_party/mozjs-45/extract/js/src/vm/TypedArrayObject.cpp b/src/third_party/mozjs-45/extract/js/src/vm/TypedArrayObject.cpp index a3c8a902581..7f92aab6da9 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/TypedArrayObject.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/TypedArrayObject.cpp @@ -1032,6 +1032,11 @@ DataViewObject* DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, Handle<ArrayBufferObject*> arrayBuffer, JSObject* protoArg) { + if (arrayBuffer->isNeutered()) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); + return nullptr; + } + MOZ_ASSERT(byteOffset <= INT32_MAX); MOZ_ASSERT(byteLength <= INT32_MAX); MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX); @@ -2264,36 +2269,50 @@ js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index, { MOZ_ASSERT(IsAnyTypedArray(obj)); - // These are all substeps of 3.c. - // Steps i-vi. + // These are all substeps of 3.b. + + // Steps i-iii are handled by the caller. + + // Steps iv-v. // We (wrongly) ignore out of range defines with a value. - if (index >= AnyTypedArrayLength(obj)) + uint32_t length = AnyTypedArrayLength(obj); + if (index >= length) return result.succeed(); - // Step vii. + // Step vi. if (desc.isAccessorDescriptor()) return result.fail(JSMSG_CANT_REDEFINE_PROP); - // Step viii. + // Step vii. if (desc.hasConfigurable() && desc.configurable()) return result.fail(JSMSG_CANT_REDEFINE_PROP); - // Step ix. + // Step viii. if (desc.hasEnumerable() && !desc.enumerable()) return result.fail(JSMSG_CANT_REDEFINE_PROP); - // Step x. + // Step ix. if (desc.hasWritable() && !desc.writable()) return result.fail(JSMSG_CANT_REDEFINE_PROP); - // Step xi. + // Step x. if (desc.hasValue()) { - double d; - if (!ToNumber(cx, desc.value(), &d)) + // The following step numbers refer to 9.4.5.9 + // IntegerIndexedElementSet. + + // Steps 1-2 are enforced by the caller. + + // Step 3. + double numValue; + if (!ToNumber(cx, desc.value(), &numValue)) return false; - if (obj->is<TypedArrayObject>()) - TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d); + // Steps 4-5, 8-9. + if (AnyTypedArrayIsDetached(obj)) + return result.fail(JSMSG_TYPED_ARRAY_DETACHED); + + // Steps 10-16. + TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, numValue); } // Step xii. diff --git a/src/third_party/mozjs-45/extract/js/src/vm/UnboxedObject.cpp b/src/third_party/mozjs-45/extract/js/src/vm/UnboxedObject.cpp index 504a5c418c4..f1b377d57b4 100644 --- a/src/third_party/mozjs-45/extract/js/src/vm/UnboxedObject.cpp +++ b/src/third_party/mozjs-45/extract/js/src/vm/UnboxedObject.cpp @@ -7,6 +7,7 @@ #include "vm/UnboxedObject-inl.h" #include "jit/BaselineIC.h" +#include "jit/ExecutableAllocator.h" #include "jit/JitCommon.h" #include "jit/Linker.h" @@ -698,7 +699,8 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup #ifndef JS_CODEGEN_NONE if (cx->isJSContext() && !layout.constructorCode() && - cx->asJSContext()->runtime()->jitSupportsFloatingPoint) + cx->asJSContext()->runtime()->jitSupportsFloatingPoint && + jit::CanLikelyAllocateMoreExecutableMemory()) { if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group)) return nullptr; diff --git a/src/third_party/mozjs-45/extract/mfbt/HashFunctions.h b/src/third_party/mozjs-45/extract/mfbt/HashFunctions.h index f490a28fee4..8eb83a3737c 100644 --- a/src/third_party/mozjs-45/extract/mfbt/HashFunctions.h +++ b/src/third_party/mozjs-45/extract/mfbt/HashFunctions.h @@ -50,6 +50,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Char16.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" #include <stdint.h> @@ -312,6 +313,90 @@ HashString(const wchar_t* aStr, size_t aLength) MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t HashBytes(const void* bytes, size_t aLength); +/** + * A pseudorandom function mapping 32-bit integers to 32-bit integers. + * + * This is for when you're feeding private data (like pointer values or credit + * card numbers) to a non-crypto hash function (like HashBytes) and then using + * the hash code for something that untrusted parties could observe (like a JS + * Map). Plug in a HashCodeScrambler before that last step to avoid leaking the + * private data. + * + * By itself, this does not prevent hash-flooding DoS attacks, because an + * attacker can still generate many values with exactly equal hash codes by + * attacking the non-crypto hash function alone. Equal hash codes will, of + * course, still be equal however much you scramble them. + * + * The algorithm is SipHash-1-3. See <https://131002.net/siphash/>. + */ +class HashCodeScrambler +{ + struct SipHasher; + + uint64_t mK0, mK1; + +public: + /** Creates a new scrambler with the given 128-bit key. */ + HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + + /** + * Scramble a hash code. Always produces the same result for the same + * combination of key and hash code. + */ + uint32_t scramble(uint32_t aHashCode) const + { + SipHasher hasher(mK0, mK1); + return uint32_t(hasher.sipHash(aHashCode)); + } + +private: + struct SipHasher + { + SipHasher(uint64_t aK0, uint64_t aK1) + { + // 1. Initialization. + mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); + mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); + mV2 = aK0 ^ UINT64_C(0x6c7967656e657261); + mV3 = aK1 ^ UINT64_C(0x7465646279746573); + } + + uint64_t sipHash(uint64_t aM) + { + // 2. Compression. + mV3 ^= aM; + sipRound(); + mV0 ^= aM; + + // 3. Finalization. + mV2 ^= 0xff; + for (int i = 0; i < 3; i++) + sipRound(); + return mV0 ^ mV1 ^ mV2 ^ mV3; + } + + void sipRound() + { + mV0 += mV1; + mV1 = RotateLeft(mV1, 13); + mV1 ^= mV0; + mV0 = RotateLeft(mV0, 32); + mV2 += mV3; + mV3 = RotateLeft(mV3, 16); + mV3 ^= mV2; + mV0 += mV3; + mV3 = RotateLeft(mV3, 21); + mV3 ^= mV0; + mV2 += mV1; + mV1 = RotateLeft(mV1, 17); + mV1 ^= mV2; + mV2 = RotateLeft(mV2, 32); + } + + uint64_t mV0, mV1, mV2, mV3; + }; +}; + } /* namespace mozilla */ #endif /* __cplusplus */ diff --git a/src/third_party/mozjs-45/get-sources.sh b/src/third_party/mozjs-45/get-sources.sh index 39acace54e5..089a52d2793 100644 --- a/src/third_party/mozjs-45/get-sources.sh +++ b/src/third_party/mozjs-45/get-sources.sh @@ -2,7 +2,7 @@ # how we got the last firefox sources -VERSION=45.5.0esr +VERSION=45.8.0esr TARBALL=firefox-$VERSION.source.tar.xz if [ ! -f $TARBALL ]; then wget "https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/$VERSION/source/$TARBALL" diff --git a/src/third_party/mozjs-45/include/js/GCAPI.h b/src/third_party/mozjs-45/include/js/GCAPI.h index 90f8e4eba3f..84b6150c36f 100644 --- a/src/third_party/mozjs-45/include/js/GCAPI.h +++ b/src/third_party/mozjs-45/include/js/GCAPI.h @@ -566,8 +566,6 @@ namespace gc { static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { - MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape); - /* * GC things residing in the nursery cannot be gray: they have no mark bits. * All live objects in the nursery are moved to tenured at the beginning of diff --git a/src/third_party/mozjs-45/include/mozilla/HashFunctions.h b/src/third_party/mozjs-45/include/mozilla/HashFunctions.h index f490a28fee4..8eb83a3737c 100644 --- a/src/third_party/mozjs-45/include/mozilla/HashFunctions.h +++ b/src/third_party/mozjs-45/include/mozilla/HashFunctions.h @@ -50,6 +50,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Char16.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" #include <stdint.h> @@ -312,6 +313,90 @@ HashString(const wchar_t* aStr, size_t aLength) MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t HashBytes(const void* bytes, size_t aLength); +/** + * A pseudorandom function mapping 32-bit integers to 32-bit integers. + * + * This is for when you're feeding private data (like pointer values or credit + * card numbers) to a non-crypto hash function (like HashBytes) and then using + * the hash code for something that untrusted parties could observe (like a JS + * Map). Plug in a HashCodeScrambler before that last step to avoid leaking the + * private data. + * + * By itself, this does not prevent hash-flooding DoS attacks, because an + * attacker can still generate many values with exactly equal hash codes by + * attacking the non-crypto hash function alone. Equal hash codes will, of + * course, still be equal however much you scramble them. + * + * The algorithm is SipHash-1-3. See <https://131002.net/siphash/>. + */ +class HashCodeScrambler +{ + struct SipHasher; + + uint64_t mK0, mK1; + +public: + /** Creates a new scrambler with the given 128-bit key. */ + HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + + /** + * Scramble a hash code. Always produces the same result for the same + * combination of key and hash code. + */ + uint32_t scramble(uint32_t aHashCode) const + { + SipHasher hasher(mK0, mK1); + return uint32_t(hasher.sipHash(aHashCode)); + } + +private: + struct SipHasher + { + SipHasher(uint64_t aK0, uint64_t aK1) + { + // 1. Initialization. + mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); + mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); + mV2 = aK0 ^ UINT64_C(0x6c7967656e657261); + mV3 = aK1 ^ UINT64_C(0x7465646279746573); + } + + uint64_t sipHash(uint64_t aM) + { + // 2. Compression. + mV3 ^= aM; + sipRound(); + mV0 ^= aM; + + // 3. Finalization. + mV2 ^= 0xff; + for (int i = 0; i < 3; i++) + sipRound(); + return mV0 ^ mV1 ^ mV2 ^ mV3; + } + + void sipRound() + { + mV0 += mV1; + mV1 = RotateLeft(mV1, 13); + mV1 ^= mV0; + mV0 = RotateLeft(mV0, 32); + mV2 += mV3; + mV3 = RotateLeft(mV3, 16); + mV3 ^= mV2; + mV0 += mV3; + mV3 = RotateLeft(mV3, 21); + mV3 ^= mV0; + mV2 += mV1; + mV1 = RotateLeft(mV1, 17); + mV1 ^= mV2; + mV2 = RotateLeft(mV2, 32); + } + + uint64_t mV0, mV1, mV2, mV3; + }; +}; + } /* namespace mozilla */ #endif /* __cplusplus */ diff --git a/src/third_party/mozjs-45/mongo_patches/SERVER-28400-Solaris_MAP_NORESERVE.patch b/src/third_party/mozjs-45/mongo_patches/SERVER-28400-Solaris_MAP_NORESERVE.patch new file mode 100644 index 00000000000..99ef9ad9d5c --- /dev/null +++ b/src/third_party/mozjs-45/mongo_patches/SERVER-28400-Solaris_MAP_NORESERVE.patch @@ -0,0 +1,18 @@ +--- a/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.cpp ++++ b/src/third_party/mozjs-45/extract/js/src/jit/ProcessExecutableMemory.cpp +@@ -266,8 +266,15 @@ ReserveProcessExecutableMemory(size_t bytes) + // Note that randomAddr is just a hint: if the address is not available + // mmap will pick a different address. + void* randomAddr = ComputeRandomAllocationAddress(); ++#ifdef SOLARIS ++ // Do not reserve swap space for the entire allocation. Regardless of what mmap(2) says, ++ // Solaris reserves swap space even though this allocation is not marked as writable. ++ void* p = MozTaggedAnonymousMmap(randomAddr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, ++ -1, 0, "js-executable-memory"); ++#else + void* p = MozTaggedAnonymousMmap(randomAddr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0, "js-executable-memory"); ++#endif + if (p == MAP_FAILED) + return nullptr; + return p; diff --git a/src/third_party/mozjs-45/platform/aarch64/linux/build/js-confdefs.h b/src/third_party/mozjs-45/platform/aarch64/linux/build/js-confdefs.h index debbcfb5052..2b1a51d09f7 100644 --- a/src/third_party/mozjs-45/platform/aarch64/linux/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/aarch64/linux/build/js-confdefs.h @@ -74,10 +74,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/aarch64/linux/include/js-config.h b/src/third_party/mozjs-45/platform/aarch64/linux/include/js-config.h index 49bb6d59d70..e4dcddbe680 100644 --- a/src/third_party/mozjs-45/platform/aarch64/linux/include/js-config.h +++ b/src/third_party/mozjs-45/platform/aarch64/linux/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/ppc64le/linux/build/js-confdefs.h b/src/third_party/mozjs-45/platform/ppc64le/linux/build/js-confdefs.h index debbcfb5052..2b1a51d09f7 100644 --- a/src/third_party/mozjs-45/platform/ppc64le/linux/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/ppc64le/linux/build/js-confdefs.h @@ -74,10 +74,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/ppc64le/linux/include/js-config.h b/src/third_party/mozjs-45/platform/ppc64le/linux/include/js-config.h index 49bb6d59d70..e4dcddbe680 100644 --- a/src/third_party/mozjs-45/platform/ppc64le/linux/include/js-config.h +++ b/src/third_party/mozjs-45/platform/ppc64le/linux/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/s390x/linux/build/js-confdefs.h b/src/third_party/mozjs-45/platform/s390x/linux/build/js-confdefs.h index b4a6a864fc0..c94367cff3f 100644 --- a/src/third_party/mozjs-45/platform/s390x/linux/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/s390x/linux/build/js-confdefs.h @@ -75,10 +75,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/s390x/linux/include/js-config.h b/src/third_party/mozjs-45/platform/s390x/linux/include/js-config.h index 49bb6d59d70..e4dcddbe680 100644 --- a/src/third_party/mozjs-45/platform/s390x/linux/include/js-config.h +++ b/src/third_party/mozjs-45/platform/s390x/linux/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/freebsd/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/freebsd/build/js-confdefs.h index c99865cff0d..c36f3704f05 100644 --- a/src/third_party/mozjs-45/platform/x86_64/freebsd/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/freebsd/build/js-confdefs.h @@ -69,10 +69,10 @@ #define MALLOC_H <malloc_np.h> #define MALLOC_USABLE_SIZE_CONST_PTR const #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/freebsd/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/freebsd/include/js-config.h index e4175f7d74d..dcc2617a294 100644 --- a/src/third_party/mozjs-45/platform/x86_64/freebsd/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/freebsd/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/linux/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/linux/build/js-confdefs.h index d3a0aac8ae9..9b3d5f6ca7b 100644 --- a/src/third_party/mozjs-45/platform/x86_64/linux/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/linux/build/js-confdefs.h @@ -79,10 +79,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/linux/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/linux/include/js-config.h index 49bb6d59d70..e4dcddbe680 100644 --- a/src/third_party/mozjs-45/platform/x86_64/linux/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/linux/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/macOS/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/macOS/build/js-confdefs.h index c4ff9c6d80b..48623cf2b8b 100644 --- a/src/third_party/mozjs-45/platform/x86_64/macOS/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/macOS/build/js-confdefs.h @@ -62,10 +62,10 @@ #define MALLOC_H <malloc/malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR const #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".dylib" #define MOZ_MEMORY 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/macOS/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/macOS/include/js-config.h index e4175f7d74d..dcc2617a294 100644 --- a/src/third_party/mozjs-45/platform/x86_64/macOS/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/macOS/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/openbsd/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/openbsd/build/js-confdefs.h index 8b25ee0b17b..d4ccca388b9 100644 --- a/src/third_party/mozjs-45/platform/x86_64/openbsd/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/openbsd/build/js-confdefs.h @@ -67,10 +67,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR const #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so.1.0" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/openbsd/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/openbsd/include/js-config.h index ac52cef4d93..071a002314c 100644 --- a/src/third_party/mozjs-45/platform/x86_64/openbsd/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/openbsd/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/solaris/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/solaris/build/js-confdefs.h index bd7f2dc1cba..24af9ec84b2 100644 --- a/src/third_party/mozjs-45/platform/x86_64/solaris/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/solaris/build/js-confdefs.h @@ -69,10 +69,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR const #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".so" #define MOZ_GLUE_IN_PROGRAM 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/solaris/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/solaris/include/js-config.h index d916ed709c4..8dd55eebb3f 100644 --- a/src/third_party/mozjs-45/platform/x86_64/solaris/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/solaris/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ diff --git a/src/third_party/mozjs-45/platform/x86_64/windows/build/js-confdefs.h b/src/third_party/mozjs-45/platform/x86_64/windows/build/js-confdefs.h index 4bcf6372758..2be82e81ea4 100644 --- a/src/third_party/mozjs-45/platform/x86_64/windows/build/js-confdefs.h +++ b/src/third_party/mozjs-45/platform/x86_64/windows/build/js-confdefs.h @@ -30,10 +30,10 @@ #define MALLOC_H <malloc.h> #define MALLOC_USABLE_SIZE_CONST_PTR const #define MOZILLA_UAVERSION "45.0" -#define MOZILLA_VERSION "45.5.0" -#define MOZILLA_VERSION_U 45.5.0 +#define MOZILLA_VERSION "45.8.0" +#define MOZILLA_VERSION_U 45.8.0 #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #define MOZ_DEBUG_SYMBOLS 1 #define MOZ_DLL_SUFFIX ".dll" #define MOZ_MEMORY 1 diff --git a/src/third_party/mozjs-45/platform/x86_64/windows/include/js-config.h b/src/third_party/mozjs-45/platform/x86_64/windows/include/js-config.h index 01fcaf17001..1ea25b51001 100644 --- a/src/third_party/mozjs-45/platform/x86_64/windows/include/js-config.h +++ b/src/third_party/mozjs-45/platform/x86_64/windows/include/js-config.h @@ -54,6 +54,6 @@ /* MOZILLA JSAPI version number components */ #define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 5 +#define MOZJS_MINOR_VERSION 8 #endif /* js_config_h */ |